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