From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 16 Mar 2020 18:49:26 +0900 Subject: Fresh start --- jni/ruby/ext/win32ole/win32ole_param.c | 438 +++++++++++++++++++++++++++++++++ 1 file changed, 438 insertions(+) create mode 100644 jni/ruby/ext/win32ole/win32ole_param.c (limited to 'jni/ruby/ext/win32ole/win32ole_param.c') diff --git a/jni/ruby/ext/win32ole/win32ole_param.c b/jni/ruby/ext/win32ole/win32ole_param.c new file mode 100644 index 0000000..31cf853 --- /dev/null +++ b/jni/ruby/ext/win32ole/win32ole_param.c @@ -0,0 +1,438 @@ +#include "win32ole.h" + +VALUE cWIN32OLE_PARAM; + +struct oleparamdata { + ITypeInfo *pTypeInfo; + UINT method_index; + UINT index; +}; + +static void oleparam_free(void *ptr); +static size_t oleparam_size(const void *ptr); +static VALUE foleparam_s_allocate(VALUE klass); +static VALUE oleparam_ole_param_from_index(VALUE self, ITypeInfo *pTypeInfo, UINT method_index, int param_index); +static VALUE oleparam_ole_param(VALUE self, VALUE olemethod, int n); +static VALUE foleparam_initialize(VALUE self, VALUE olemethod, VALUE n); +static VALUE foleparam_name(VALUE self); +static VALUE ole_param_ole_type(ITypeInfo *pTypeInfo, UINT method_index, UINT index); +static VALUE foleparam_ole_type(VALUE self); +static VALUE ole_param_ole_type_detail(ITypeInfo *pTypeInfo, UINT method_index, UINT index); +static VALUE foleparam_ole_type_detail(VALUE self); +static VALUE ole_param_flag_mask(ITypeInfo *pTypeInfo, UINT method_index, UINT index, USHORT mask); +static VALUE foleparam_input(VALUE self); +static VALUE foleparam_output(VALUE self); +static VALUE foleparam_optional(VALUE self); +static VALUE foleparam_retval(VALUE self); +static VALUE ole_param_default(ITypeInfo *pTypeInfo, UINT method_index, UINT index); +static VALUE foleparam_default(VALUE self); +static VALUE foleparam_inspect(VALUE self); + +static const rb_data_type_t oleparam_datatype = { + "win32ole_param", + {NULL, oleparam_free, oleparam_size,}, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY +}; + +static void +oleparam_free(void *ptr) +{ + struct oleparamdata *pole = ptr; + OLE_FREE(pole->pTypeInfo); + free(pole); +} + +static size_t +oleparam_size(const void *ptr) +{ + return ptr ? sizeof(struct oleparamdata) : 0; +} + +VALUE +create_win32ole_param(ITypeInfo *pTypeInfo, UINT method_index, UINT index, VALUE name) +{ + struct oleparamdata *pparam; + VALUE obj = foleparam_s_allocate(cWIN32OLE_PARAM); + TypedData_Get_Struct(obj, struct oleparamdata, &oleparam_datatype, pparam); + + pparam->pTypeInfo = pTypeInfo; + OLE_ADDREF(pTypeInfo); + pparam->method_index = method_index; + pparam->index = index; + rb_ivar_set(obj, rb_intern("name"), name); + return obj; +} + +/* + * Document-class: WIN32OLE_PARAM + * + * WIN32OLE_PARAM objects represent param information of + * the OLE method. + */ +static VALUE +foleparam_s_allocate(VALUE klass) +{ + struct oleparamdata *pparam; + VALUE obj; + obj = TypedData_Make_Struct(klass, + struct oleparamdata, + &oleparam_datatype, pparam); + pparam->pTypeInfo = NULL; + pparam->method_index = 0; + pparam->index = 0; + return obj; +} + +static VALUE +oleparam_ole_param_from_index(VALUE self, ITypeInfo *pTypeInfo, UINT method_index, int param_index) +{ + FUNCDESC *pFuncDesc; + HRESULT hr; + BSTR *bstrs; + UINT len; + struct oleparamdata *pparam; + hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc); + if (FAILED(hr)) + ole_raise(hr, rb_eRuntimeError, "fail to ITypeInfo::GetFuncDesc"); + + len = 0; + bstrs = ALLOCA_N(BSTR, pFuncDesc->cParams + 1); + hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pFuncDesc->memid, + bstrs, pFuncDesc->cParams + 1, + &len); + if (FAILED(hr)) { + pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc); + ole_raise(hr, rb_eRuntimeError, "fail to ITypeInfo::GetNames"); + } + SysFreeString(bstrs[0]); + if (param_index < 1 || len <= (UINT)param_index) + { + pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc); + rb_raise(rb_eIndexError, "index of param must be in 1..%d", len); + } + + TypedData_Get_Struct(self, struct oleparamdata, &oleparam_datatype, pparam); + pparam->pTypeInfo = pTypeInfo; + OLE_ADDREF(pTypeInfo); + pparam->method_index = method_index; + pparam->index = param_index - 1; + rb_ivar_set(self, rb_intern("name"), WC2VSTR(bstrs[param_index])); + + pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc); + return self; +} + +static VALUE +oleparam_ole_param(VALUE self, VALUE olemethod, int n) +{ + struct olemethoddata *pmethod = olemethod_data_get_struct(olemethod); + return oleparam_ole_param_from_index(self, pmethod->pTypeInfo, pmethod->index, n); +} + +/* + * call-seq: + * WIN32OLE_PARAM.new(method, n) -> WIN32OLE_PARAM object + * + * Returns WIN32OLE_PARAM object which represents OLE parameter information. + * 1st argument should be WIN32OLE_METHOD object. + * 2nd argument `n' is n-th parameter of the method specified by 1st argument. + * + * tobj = WIN32OLE_TYPE.new('Microsoft Scripting Runtime', 'IFileSystem') + * method = WIN32OLE_METHOD.new(tobj, 'CreateTextFile') + * param = WIN32OLE_PARAM.new(method, 2) # => # + * + */ +static VALUE +foleparam_initialize(VALUE self, VALUE olemethod, VALUE n) +{ + int idx; + if (!rb_obj_is_kind_of(olemethod, cWIN32OLE_METHOD)) { + rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE_METHOD object"); + } + idx = FIX2INT(n); + return oleparam_ole_param(self, olemethod, idx); +} + +/* + * call-seq: + * WIN32OLE_PARAM#name + * + * Returns name. + * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook') + * method = WIN32OLE_METHOD.new(tobj, 'SaveAs') + * param1 = method.params[0] + * puts param1.name # => Filename + */ +static VALUE +foleparam_name(VALUE self) +{ + return rb_ivar_get(self, rb_intern("name")); +} + +static VALUE +ole_param_ole_type(ITypeInfo *pTypeInfo, UINT method_index, UINT index) +{ + FUNCDESC *pFuncDesc; + HRESULT hr; + VALUE type = rb_str_new2("unknown type"); + hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc); + if (FAILED(hr)) + return type; + type = ole_typedesc2val(pTypeInfo, + &(pFuncDesc->lprgelemdescParam[index].tdesc), Qnil); + pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc); + return type; +} + +/* + * call-seq: + * WIN32OLE_PARAM#ole_type + * + * Returns OLE type of WIN32OLE_PARAM object(parameter of OLE method). + * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook') + * method = WIN32OLE_METHOD.new(tobj, 'SaveAs') + * param1 = method.params[0] + * puts param1.ole_type # => VARIANT + */ +static VALUE +foleparam_ole_type(VALUE self) +{ + struct oleparamdata *pparam; + TypedData_Get_Struct(self, struct oleparamdata, &oleparam_datatype, pparam); + return ole_param_ole_type(pparam->pTypeInfo, pparam->method_index, + pparam->index); +} + +static VALUE +ole_param_ole_type_detail(ITypeInfo *pTypeInfo, UINT method_index, UINT index) +{ + FUNCDESC *pFuncDesc; + HRESULT hr; + VALUE typedetail = rb_ary_new(); + hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc); + if (FAILED(hr)) + return typedetail; + ole_typedesc2val(pTypeInfo, + &(pFuncDesc->lprgelemdescParam[index].tdesc), typedetail); + pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc); + return typedetail; +} + +/* + * call-seq: + * WIN32OLE_PARAM#ole_type_detail + * + * Returns detail information of type of argument. + * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'IWorksheetFunction') + * method = WIN32OLE_METHOD.new(tobj, 'SumIf') + * param1 = method.params[0] + * p param1.ole_type_detail # => ["PTR", "USERDEFINED", "Range"] + */ +static VALUE +foleparam_ole_type_detail(VALUE self) +{ + struct oleparamdata *pparam; + TypedData_Get_Struct(self, struct oleparamdata, &oleparam_datatype, pparam); + return ole_param_ole_type_detail(pparam->pTypeInfo, pparam->method_index, + pparam->index); +} + +static VALUE +ole_param_flag_mask(ITypeInfo *pTypeInfo, UINT method_index, UINT index, USHORT mask) +{ + FUNCDESC *pFuncDesc; + HRESULT hr; + VALUE ret = Qfalse; + hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc); + if(FAILED(hr)) + return ret; + if (V_UNION1((&(pFuncDesc->lprgelemdescParam[index])), paramdesc).wParamFlags &mask) + ret = Qtrue; + pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc); + return ret; +} + +/* + * call-seq: + * WIN32OLE_PARAM#input? + * + * Returns true if the parameter is input. + * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook') + * method = WIN32OLE_METHOD.new(tobj, 'SaveAs') + * param1 = method.params[0] + * puts param1.input? # => true + */ +static VALUE +foleparam_input(VALUE self) +{ + struct oleparamdata *pparam; + TypedData_Get_Struct(self, struct oleparamdata, &oleparam_datatype, pparam); + return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index, + pparam->index, PARAMFLAG_FIN); +} + +/* + * call-seq: + * WIN32OLE#output? + * + * Returns true if argument is output. + * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'DWebBrowserEvents') + * method = WIN32OLE_METHOD.new(tobj, 'NewWindow') + * method.params.each do |param| + * puts "#{param.name} #{param.output?}" + * end + * + * The result of above script is following: + * URL false + * Flags false + * TargetFrameName false + * PostData false + * Headers false + * Processed true + */ +static VALUE +foleparam_output(VALUE self) +{ + struct oleparamdata *pparam; + TypedData_Get_Struct(self, struct oleparamdata, &oleparam_datatype, pparam); + return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index, + pparam->index, PARAMFLAG_FOUT); +} + +/* + * call-seq: + * WIN32OLE_PARAM#optional? + * + * Returns true if argument is optional. + * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook') + * method = WIN32OLE_METHOD.new(tobj, 'SaveAs') + * param1 = method.params[0] + * puts "#{param1.name} #{param1.optional?}" # => Filename true + */ +static VALUE +foleparam_optional(VALUE self) +{ + struct oleparamdata *pparam; + TypedData_Get_Struct(self, struct oleparamdata, &oleparam_datatype, pparam); + return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index, + pparam->index, PARAMFLAG_FOPT); +} + +/* + * call-seq: + * WIN32OLE_PARAM#retval? + * + * Returns true if argument is return value. + * tobj = WIN32OLE_TYPE.new('DirectX 7 for Visual Basic Type Library', + * 'DirectPlayLobbyConnection') + * method = WIN32OLE_METHOD.new(tobj, 'GetPlayerShortName') + * param = method.params[0] + * puts "#{param.name} #{param.retval?}" # => name true + */ +static VALUE +foleparam_retval(VALUE self) +{ + struct oleparamdata *pparam; + TypedData_Get_Struct(self, struct oleparamdata, &oleparam_datatype, pparam); + return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index, + pparam->index, PARAMFLAG_FRETVAL); +} + +static VALUE +ole_param_default(ITypeInfo *pTypeInfo, UINT method_index, UINT index) +{ + FUNCDESC *pFuncDesc; + ELEMDESC *pElemDesc; + PARAMDESCEX * pParamDescEx; + HRESULT hr; + USHORT wParamFlags; + USHORT mask = PARAMFLAG_FOPT|PARAMFLAG_FHASDEFAULT; + VALUE defval = Qnil; + hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc); + if (FAILED(hr)) + return defval; + pElemDesc = &pFuncDesc->lprgelemdescParam[index]; + wParamFlags = V_UNION1(pElemDesc, paramdesc).wParamFlags; + if ((wParamFlags & mask) == mask) { + pParamDescEx = V_UNION1(pElemDesc, paramdesc).pparamdescex; + defval = ole_variant2val(&pParamDescEx->varDefaultValue); + } + pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc); + return defval; +} + +/* + * call-seq: + * WIN32OLE_PARAM#default + * + * Returns default value. If the default value does not exist, + * this method returns nil. + * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook') + * method = WIN32OLE_METHOD.new(tobj, 'SaveAs') + * method.params.each do |param| + * if param.default + * puts "#{param.name} (= #{param.default})" + * else + * puts "#{param}" + * end + * end + * + * The above script result is following: + * Filename + * FileFormat + * Password + * WriteResPassword + * ReadOnlyRecommended + * CreateBackup + * AccessMode (= 1) + * ConflictResolution + * AddToMru + * TextCodepage + * TextVisualLayout + */ +static VALUE +foleparam_default(VALUE self) +{ + struct oleparamdata *pparam; + TypedData_Get_Struct(self, struct oleparamdata, &oleparam_datatype, pparam); + return ole_param_default(pparam->pTypeInfo, pparam->method_index, + pparam->index); +} + +/* + * call-seq: + * WIN32OLE_PARAM#inspect -> String + * + * Returns the parameter name with class name. If the parameter has default value, + * then returns name=value string with class name. + * + */ +static VALUE +foleparam_inspect(VALUE self) +{ + VALUE detail = foleparam_name(self); + VALUE defval = foleparam_default(self); + if (defval != Qnil) { + rb_str_cat2(detail, "="); + rb_str_concat(detail, rb_inspect(defval)); + } + return make_inspect("WIN32OLE_PARAM", detail); +} + +void +Init_win32ole_param(void) +{ + cWIN32OLE_PARAM = rb_define_class("WIN32OLE_PARAM", rb_cObject); + rb_define_alloc_func(cWIN32OLE_PARAM, foleparam_s_allocate); + rb_define_method(cWIN32OLE_PARAM, "initialize", foleparam_initialize, 2); + rb_define_method(cWIN32OLE_PARAM, "name", foleparam_name, 0); + rb_define_method(cWIN32OLE_PARAM, "ole_type", foleparam_ole_type, 0); + rb_define_method(cWIN32OLE_PARAM, "ole_type_detail", foleparam_ole_type_detail, 0); + rb_define_method(cWIN32OLE_PARAM, "input?", foleparam_input, 0); + rb_define_method(cWIN32OLE_PARAM, "output?", foleparam_output, 0); + rb_define_method(cWIN32OLE_PARAM, "optional?", foleparam_optional, 0); + rb_define_method(cWIN32OLE_PARAM, "retval?", foleparam_retval, 0); + rb_define_method(cWIN32OLE_PARAM, "default", foleparam_default, 0); + rb_define_alias(cWIN32OLE_PARAM, "to_s", "name"); + rb_define_method(cWIN32OLE_PARAM, "inspect", foleparam_inspect, 0); +} -- cgit v1.2.3