#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); }