/* * call-seq: * WIN32OLE_VARIANT.new(val, vartype) #=> WIN32OLE_VARIANT object. * * Returns Ruby object wrapping OLE variant. * The first argument specifies Ruby object to convert OLE variant variable. * The second argument specifies VARIANT type. * In some situation, you need the WIN32OLE_VARIANT object to pass OLE method * * shell = WIN32OLE.new("Shell.Application") * folder = shell.NameSpace("C:\\Windows") * item = folder.ParseName("tmp.txt") * # You can't use Ruby String object to call FolderItem.InvokeVerb. * # Instead, you have to use WIN32OLE_VARIANT object to call the method. * shortcut = WIN32OLE_VARIANT.new("Create Shortcut(\&S)") * item.invokeVerb(shortcut) * */ static VALUE folevariant_initialize(VALUE self, VALUE args) { int len = 0; VARIANT var; VALUE val; VALUE vvt; VARTYPE vt; struct olevariantdata *pvar; len = RARRAY_LEN(args); rb_check_arity(len, 1, 3); VariantInit(&var); val = rb_ary_entry(args, 0); check_type_val2variant(val); TypedData_Get_Struct(self, struct olevariantdata, &olevariant_datatype, pvar); if (len == 1) { ole_val2variant(val, &(pvar->var)); } else { vvt = rb_ary_entry(args, 1); vt = RB_NUM2INT(vvt); if ((vt & VT_TYPEMASK) == VT_RECORD) { rb_raise(rb_eArgError, "not supported VT_RECORD WIN32OLE_VARIANT object"); } ole_val2olevariantdata(val, vt, pvar); } return self; }
STDMETHODIMP EVENTSINK_Invoke( PEVENTSINK pEventSink, DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr ) { HRESULT hr; BSTR bstr; unsigned int count; unsigned int i; ITypeInfo *pTypeInfo; VARIANT *pvar; VALUE ary, obj, event, args, outargv, ev, result; VALUE handler = Qnil; VALUE arg[3]; VALUE mid; VALUE is_outarg = Qfalse; BOOL is_default_handler = FALSE; int state; PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink; pTypeInfo = pEV->pTypeInfo; obj = evs_entry(pEV->m_event_id); if (!rb_obj_is_kind_of(obj, cWIN32OLE_EVENT)) { return NOERROR; } ary = rb_ivar_get(obj, id_events); if (NIL_P(ary) || !RB_TYPE_P(ary, T_ARRAY)) { return NOERROR; } hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid, &bstr, 1, &count); if (FAILED(hr)) { return NOERROR; } ev = WC2VSTR(bstr); event = ole_search_event(ary, ev, &is_default_handler); if (RB_TYPE_P(event, T_ARRAY)) { handler = rb_ary_entry(event, 0); mid = rb_intern("call"); is_outarg = rb_ary_entry(event, 3); } else { handler = rb_ivar_get(obj, rb_intern("handler")); if (handler == Qnil) { return NOERROR; } mid = ole_search_handler_method(handler, ev, &is_default_handler); } if (handler == Qnil || mid == Qnil) { return NOERROR; } args = rb_ary_new(); if (is_default_handler) { rb_ary_push(args, ev); } /* make argument of event handler */ for (i = 0; i < pdispparams->cArgs; ++i) { pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1]; rb_ary_push(args, ole_variant2val(pvar)); } outargv = Qnil; if (is_outarg == Qtrue) { outargv = rb_ary_new(); rb_ary_push(args, outargv); } /* * if exception raised in event callback, * then you receive cfp consistency error. * to avoid this error we use begin rescue end. * and the exception raised then error message print * and exit ruby process by Win32OLE itself. */ arg[0] = handler; arg[1] = mid; arg[2] = args; result = rb_protect(exec_callback, (VALUE)arg, &state); if (state != 0) { rescue_callback(Qnil); } if(RB_TYPE_P(result, T_HASH)) { hash2ptr_dispparams(result, pTypeInfo, dispid, pdispparams); result = hash2result(result); }else if (is_outarg == Qtrue && RB_TYPE_P(outargv, T_ARRAY)) { ary2ptr_dispparams(outargv, pdispparams); } if (pvarResult) { VariantInit(pvarResult); ole_val2variant(result, pvarResult); } return NOERROR; }