From cd3d7fe846d4671671612658c9f76ce1ec4c3d56 Mon Sep 17 00:00:00 2001 From: suke Date: Fri, 15 Aug 2014 11:36:12 +0000 Subject: * ext/win32ole/win32ole.c: seperate WIN32OLE_EVENT src from win32ole.c. * ext/win32ole/win32ole.h: ditto. * ext/win32ole/win32ole_event.c: ditto. * ext/win32ole/win32ole_event.h: ditto. * ext/win32ole/depend: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47192 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/win32ole/win32ole.c | 1269 +---------------------------------------------- 1 file changed, 4 insertions(+), 1265 deletions(-) (limited to 'ext/win32ole/win32ole.c') diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index 24cc184fcb..3c52c9c088 100644 --- a/ext/win32ole/win32ole.c +++ b/ext/win32ole/win32ole.c @@ -26,13 +26,6 @@ const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}}; #endif -#define OLEData_Get_Struct(obj, pole) {\ - Data_Get_Struct(obj, struct oledata, pole);\ - if(!pole->pDispatch) {\ - rb_raise(rb_eRuntimeError, "failed to get Dispatch Interface");\ - }\ -} - #define WIN32OLE_VERSION "1.7.7" typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) @@ -41,60 +34,7 @@ typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) typedef HWND (WINAPI FNHTMLHELP)(HWND hwndCaller, LPCSTR pszFile, UINT uCommand, DWORD dwData); typedef BOOL (FNENUMSYSEMCODEPAGES) (CODEPAGE_ENUMPROC, DWORD); -typedef struct { - struct IEventSinkVtbl * lpVtbl; -} IEventSink, *PEVENTSINK; - -typedef struct IEventSinkVtbl IEventSinkVtbl; - -struct IEventSinkVtbl { - STDMETHOD(QueryInterface)( - PEVENTSINK, - REFIID, - LPVOID *); - STDMETHOD_(ULONG, AddRef)(PEVENTSINK); - STDMETHOD_(ULONG, Release)(PEVENTSINK); - - STDMETHOD(GetTypeInfoCount)( - PEVENTSINK, - UINT *); - STDMETHOD(GetTypeInfo)( - PEVENTSINK, - UINT, - LCID, - ITypeInfo **); - STDMETHOD(GetIDsOfNames)( - PEVENTSINK, - REFIID, - OLECHAR **, - UINT, - LCID, - DISPID *); - STDMETHOD(Invoke)( - PEVENTSINK, - DISPID, - REFIID, - LCID, - WORD, - DISPPARAMS *, - VARIANT *, - EXCEPINFO *, - UINT *); -}; - -typedef struct tagIEVENTSINKOBJ { - IEventSinkVtbl *lpVtbl; - DWORD m_cRef; - IID m_iid; - int m_event_id; - ITypeInfo *pTypeInfo; -}IEVENTSINKOBJ, *PIEVENTSINKOBJ; - VALUE cWIN32OLE; -VALUE cWIN32OLE_EVENT; - -static VALUE ary_ole_event; -static ID id_events; #if defined(RB_THREAD_SPECIFIC) && (defined(__CYGWIN__) || defined(__MINGW32__)) static RB_THREAD_SPECIFIC BOOL g_ole_initialized; @@ -133,22 +73,11 @@ static IMultiLanguage *pIMultiLanguage = NULL; #define pIMultiLanguage NULL /* dummy */ #endif -struct oledata { - IDispatch *pDispatch; -}; - -struct oleeventdata { - DWORD dwCookie; - IConnectionPoint *pConnectionPoint; - long event_id; -}; - struct oleparam { DISPPARAMS dp; OLECHAR** pNamedArgs; }; - static HRESULT ( STDMETHODCALLTYPE QueryInterface )(IDispatch __RPC_FAR *, REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject); static ULONG ( STDMETHODCALLTYPE AddRef )(IDispatch __RPC_FAR * This); static ULONG ( STDMETHODCALLTYPE Release )(IDispatch __RPC_FAR * This); @@ -166,10 +95,8 @@ NORETURN(static void failed_load_conv51932(void)); static void load_conv_function51932(void); #endif static UINT ole_init_cp(void); -static char *ole_wc2mb(LPWSTR pw); static void ole_freeexceptinfo(EXCEPINFO *pExInfo); static VALUE ole_excepinfo2msg(EXCEPINFO *pExInfo); -static void ole_msg_loop(void); static void ole_free(struct oledata *pole); static LPWSTR ole_mb2wc(char *pm, int len); static VALUE ole_ary_m_entry(VALUE val, LONG *pid); @@ -178,7 +105,6 @@ static void * get_ptr_of_variant(VARIANT *pvar); static void ole_set_safe_array(long n, SAFEARRAY *psa, LONG *pid, long *pub, VALUE val, long dim, VARTYPE vt); static long dimension(VALUE val); static long ary_len_of_dim(VALUE ary, long dim); -static void ole_val2ptr_variant(VALUE val, VARIANT *var); static VALUE ole_set_member(VALUE self, IDispatch *dispatch); static VALUE fole_s_allocate(VALUE klass); static VALUE create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv); @@ -239,38 +165,6 @@ static VALUE ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE ty static VALUE fole_method_help(VALUE self, VALUE cmdname); static VALUE fole_activex_initialize(VALUE self); - -static long ole_search_event_at(VALUE ary, VALUE ev); -static VALUE ole_search_event(VALUE ary, VALUE ev, BOOL *is_default); -static VALUE ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler); -static void ole_delete_event(VALUE ary, VALUE ev); -static void hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams); -static VALUE hash2result(VALUE hash); -static void ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams); -static VALUE exec_callback(VALUE arg); -static VALUE rescue_callback(VALUE arg); -static HRESULT find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo); -static HRESULT find_coclass(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **pTypeInfo2, TYPEATTR **pTypeAttr2); -static HRESULT find_default_source_from_typeinfo(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **ppTypeInfo); -static HRESULT find_default_source(VALUE ole, IID *piid, ITypeInfo **ppTypeInfo); -static void ole_event_free(struct oleeventdata *poleev); -static VALUE fev_s_allocate(VALUE klass); -static VALUE ev_advise(int argc, VALUE *argv, VALUE self); -static VALUE fev_initialize(int argc, VALUE *argv, VALUE self); -static VALUE fev_s_msg_loop(VALUE klass); -static void add_event_call_back(VALUE obj, VALUE event, VALUE data); -static VALUE ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg); -static VALUE fev_on_event(int argc, VALUE *argv, VALUE self); -static VALUE fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self); -static VALUE fev_off_event(int argc, VALUE *argv, VALUE self); -static VALUE fev_unadvise(VALUE self); -static VALUE fev_set_handler(VALUE self, VALUE val); -static VALUE fev_get_handler(VALUE self); -static VALUE evs_push(VALUE ev); -static VALUE evs_delete(long i); -static VALUE evs_entry(long i); -static VALUE evs_length(void); - static void init_enc2cp(void); static void free_enc2cp(void); @@ -791,7 +685,7 @@ ole_alloc_str(UINT size, void *arg) return ALLOC_N(char, size + 1); } -static char * +char * ole_wc2mb(LPWSTR pw) { return ole_wc2mb_alloc(pw, ole_alloc_str, NULL); @@ -886,15 +780,6 @@ ole_initialize(void) } } -static void -ole_msg_loop() { - MSG msg; - while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} - static void ole_free(struct oledata *pole) { @@ -1365,74 +1250,6 @@ ole_val2variant(VALUE val, VARIANT *var) } } -static void -ole_val2ptr_variant(VALUE val, VARIANT *var) -{ - switch (TYPE(val)) { - case T_STRING: - if (V_VT(var) == (VT_BSTR | VT_BYREF)) { - *V_BSTRREF(var) = ole_vstr2wc(val); - } - break; - case T_FIXNUM: - switch(V_VT(var)) { - case (VT_UI1 | VT_BYREF) : - *V_UI1REF(var) = NUM2CHR(val); - break; - case (VT_I2 | VT_BYREF) : - *V_I2REF(var) = (short)NUM2INT(val); - break; - case (VT_I4 | VT_BYREF) : - *V_I4REF(var) = NUM2INT(val); - break; - case (VT_R4 | VT_BYREF) : - *V_R4REF(var) = (float)NUM2INT(val); - break; - case (VT_R8 | VT_BYREF) : - *V_R8REF(var) = NUM2INT(val); - break; - default: - break; - } - break; - case T_FLOAT: - switch(V_VT(var)) { - case (VT_I2 | VT_BYREF) : - *V_I2REF(var) = (short)NUM2INT(val); - break; - case (VT_I4 | VT_BYREF) : - *V_I4REF(var) = NUM2INT(val); - break; - case (VT_R4 | VT_BYREF) : - *V_R4REF(var) = (float)NUM2DBL(val); - break; - case (VT_R8 | VT_BYREF) : - *V_R8REF(var) = NUM2DBL(val); - break; - default: - break; - } - break; - case T_BIGNUM: - if (V_VT(var) == (VT_R8 | VT_BYREF)) { - *V_R8REF(var) = rb_big2dbl(val); - } - break; - case T_TRUE: - if (V_VT(var) == (VT_BOOL | VT_BYREF)) { - *V_BOOLREF(var) = VARIANT_TRUE; - } - break; - case T_FALSE: - if (V_VT(var) == (VT_BOOL | VT_BYREF)) { - *V_BOOLREF(var) = VARIANT_FALSE; - } - break; - default: - break; - } -} - void ole_val2variant2(VALUE val, VARIANT *var) { @@ -3695,10 +3512,10 @@ fole_respond_to(VALUE self, VALUE method) DISPID DispID; HRESULT hr; if(!RB_TYPE_P(method, T_STRING) && !RB_TYPE_P(method, T_SYMBOL)) { - rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)"); + rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)"); } if (RB_TYPE_P(method, T_SYMBOL)) { - method = rb_sym_to_s(method); + method = rb_sym_to_s(method); } OLEData_Get_Struct(self, pole); wcmdname = ole_vstr2wc(method); @@ -3969,1070 +3786,6 @@ fole_activex_initialize(VALUE self) return Qnil; } -/* - * Document-class: WIN32OLE_EVENT - * - * WIN32OLE_EVENT objects controls OLE event. - */ - -static IEventSinkVtbl vtEventSink; -static BOOL g_IsEventSinkVtblInitialized = FALSE; - -void EVENTSINK_Destructor(PIEVENTSINKOBJ); - -STDMETHODIMP -EVENTSINK_QueryInterface( - PEVENTSINK pEV, - REFIID iid, - LPVOID* ppv - ) { - if (IsEqualIID(iid, &IID_IUnknown) || - IsEqualIID(iid, &IID_IDispatch) || - IsEqualIID(iid, &((PIEVENTSINKOBJ)pEV)->m_iid)) { - *ppv = pEV; - } - else { - *ppv = NULL; - return E_NOINTERFACE; - } - ((LPUNKNOWN)*ppv)->lpVtbl->AddRef((LPUNKNOWN)*ppv); - return NOERROR; -} - -STDMETHODIMP_(ULONG) -EVENTSINK_AddRef( - PEVENTSINK pEV - ){ - PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV; - return ++pEVObj->m_cRef; -} - -STDMETHODIMP_(ULONG) EVENTSINK_Release( - PEVENTSINK pEV - ) { - PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV; - --pEVObj->m_cRef; - if(pEVObj->m_cRef != 0) - return pEVObj->m_cRef; - EVENTSINK_Destructor(pEVObj); - return 0; -} - -STDMETHODIMP EVENTSINK_GetTypeInfoCount( - PEVENTSINK pEV, - UINT *pct - ) { - *pct = 0; - return NOERROR; -} - -STDMETHODIMP EVENTSINK_GetTypeInfo( - PEVENTSINK pEV, - UINT info, - LCID lcid, - ITypeInfo **pInfo - ) { - *pInfo = NULL; - return DISP_E_BADINDEX; -} - -STDMETHODIMP EVENTSINK_GetIDsOfNames( - PEVENTSINK pEventSink, - REFIID riid, - OLECHAR **szNames, - UINT cNames, - LCID lcid, - DISPID *pDispID - ) { - ITypeInfo *pTypeInfo; - PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink; - pTypeInfo = pEV->pTypeInfo; - if (pTypeInfo) { - return pTypeInfo->lpVtbl->GetIDsOfNames(pTypeInfo, szNames, cNames, pDispID); - } - return DISP_E_UNKNOWNNAME; -} - -static long -ole_search_event_at(VALUE ary, VALUE ev) -{ - VALUE event; - VALUE event_name; - long i, len; - long ret = -1; - len = RARRAY_LEN(ary); - for(i = 0; i < len; i++) { - event = rb_ary_entry(ary, i); - event_name = rb_ary_entry(event, 1); - if(NIL_P(event_name) && NIL_P(ev)) { - ret = i; - break; - } - else if (RB_TYPE_P(ev, T_STRING) && - RB_TYPE_P(event_name, T_STRING) && - rb_str_cmp(ev, event_name) == 0) { - ret = i; - break; - } - } - return ret; -} - -static VALUE -ole_search_event(VALUE ary, VALUE ev, BOOL *is_default) -{ - VALUE event; - VALUE def_event; - VALUE event_name; - int i, len; - *is_default = FALSE; - def_event = Qnil; - len = RARRAY_LEN(ary); - for(i = 0; i < len; i++) { - event = rb_ary_entry(ary, i); - event_name = rb_ary_entry(event, 1); - if(NIL_P(event_name)) { - *is_default = TRUE; - def_event = event; - } - else if (rb_str_cmp(ev, event_name) == 0) { - *is_default = FALSE; - return event; - } - } - return def_event; -} -static VALUE -ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler) -{ - VALUE mid; - - *is_default_handler = FALSE; - mid = rb_to_id(rb_sprintf("on%"PRIsVALUE, ev)); - if (rb_respond_to(handler, mid)) { - return mid; - } - mid = rb_intern("method_missing"); - if (rb_respond_to(handler, mid)) { - *is_default_handler = TRUE; - return mid; - } - return Qnil; -} - -static void -ole_delete_event(VALUE ary, VALUE ev) -{ - long at = -1; - at = ole_search_event_at(ary, ev); - if (at >= 0) { - rb_ary_delete_at(ary, at); - } -} - -static void -hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams) -{ - BSTR *bstrs; - HRESULT hr; - UINT len, i; - VARIANT *pvar; - VALUE val; - VALUE key; - len = 0; - bstrs = ALLOCA_N(BSTR, pdispparams->cArgs + 1); - hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid, - bstrs, pdispparams->cArgs + 1, - &len); - if (FAILED(hr)) - return; - - for (i = 0; i < len - 1; i++) { - key = WC2VSTR(bstrs[i + 1]); - val = rb_hash_aref(hash, INT2FIX(i)); - if (val == Qnil) - val = rb_hash_aref(hash, key); - if (val == Qnil) - val = rb_hash_aref(hash, rb_str_intern(key)); - pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1]; - ole_val2ptr_variant(val, pvar); - } -} - -static VALUE -hash2result(VALUE hash) -{ - VALUE ret = Qnil; - ret = rb_hash_aref(hash, rb_str_new2("return")); - if (ret == Qnil) - ret = rb_hash_aref(hash, rb_str_intern(rb_str_new2("return"))); - return ret; -} - -static void -ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams) -{ - int i; - VALUE v; - VARIANT *pvar; - for(i = 0; i < RARRAY_LEN(ary) && (unsigned int) i < pdispparams->cArgs; i++) { - v = rb_ary_entry(ary, i); - pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1]; - ole_val2ptr_variant(v, pvar); - } -} - -static VALUE -exec_callback(VALUE arg) -{ - VALUE *parg = (VALUE *)arg; - VALUE handler = parg[0]; - VALUE mid = parg[1]; - VALUE args = parg[2]; - return rb_apply(handler, mid, args); -} - -static VALUE -rescue_callback(VALUE arg) -{ - - VALUE error; - VALUE e = rb_errinfo(); - VALUE bt = rb_funcall(e, rb_intern("backtrace"), 0); - VALUE msg = rb_funcall(e, rb_intern("message"), 0); - bt = rb_ary_entry(bt, 0); - error = rb_sprintf("%"PRIsVALUE": %"PRIsVALUE" (%s)\n", bt, msg, rb_obj_classname(e)); - rb_write_error(StringValuePtr(error)); - rb_backtrace(); - ruby_finalize(); - exit(-1); - - return Qnil; -} - -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; -} - -PIEVENTSINKOBJ -EVENTSINK_Constructor() { - PIEVENTSINKOBJ pEv; - if (!g_IsEventSinkVtblInitialized) { - vtEventSink.QueryInterface=EVENTSINK_QueryInterface; - vtEventSink.AddRef = EVENTSINK_AddRef; - vtEventSink.Release = EVENTSINK_Release; - vtEventSink.Invoke = EVENTSINK_Invoke; - vtEventSink.GetIDsOfNames = EVENTSINK_GetIDsOfNames; - vtEventSink.GetTypeInfoCount = EVENTSINK_GetTypeInfoCount; - vtEventSink.GetTypeInfo = EVENTSINK_GetTypeInfo; - - g_IsEventSinkVtblInitialized = TRUE; - } - pEv = ALLOC_N(IEVENTSINKOBJ, 1); - if(pEv == NULL) return NULL; - pEv->lpVtbl = &vtEventSink; - pEv->m_cRef = 0; - pEv->m_event_id = 0; - pEv->pTypeInfo = NULL; - return pEv; -} - -void EVENTSINK_Destructor( - PIEVENTSINKOBJ pEVObj - ) { - if(pEVObj != NULL) { - OLE_RELEASE(pEVObj->pTypeInfo); - free(pEVObj); - pEVObj = NULL; - } -} - -static HRESULT -find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo) -{ - HRESULT hr; - IDispatch *pDispatch; - ITypeInfo *pTypeInfo; - ITypeLib *pTypeLib; - TYPEATTR *pTypeAttr; - HREFTYPE RefType; - ITypeInfo *pImplTypeInfo; - TYPEATTR *pImplTypeAttr; - - struct oledata *pole; - unsigned int index; - unsigned int count; - int type; - BSTR bstr; - char *pstr; - - BOOL is_found = FALSE; - LCID lcid = cWIN32OLE_lcid; - - OLEData_Get_Struct(ole, pole); - - pDispatch = pole->pDispatch; - - hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, lcid, &pTypeInfo); - if (FAILED(hr)) - return hr; - - hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, - &pTypeLib, - &index); - OLE_RELEASE(pTypeInfo); - if (FAILED(hr)) - return hr; - - if (!pitf) { - hr = pTypeLib->lpVtbl->GetTypeInfoOfGuid(pTypeLib, - piid, - ppTypeInfo); - OLE_RELEASE(pTypeLib); - return hr; - } - count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib); - for (index = 0; index < count; index++) { - hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, - index, - &pTypeInfo); - if (FAILED(hr)) - break; - hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr); - - if(FAILED(hr)) { - OLE_RELEASE(pTypeInfo); - break; - } - if(pTypeAttr->typekind == TKIND_COCLASS) { - for (type = 0; type < pTypeAttr->cImplTypes; type++) { - hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, - type, - &RefType); - if (FAILED(hr)) - break; - hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, - RefType, - &pImplTypeInfo); - if (FAILED(hr)) - break; - - hr = pImplTypeInfo->lpVtbl->GetDocumentation(pImplTypeInfo, - -1, - &bstr, - NULL, NULL, NULL); - if (FAILED(hr)) { - OLE_RELEASE(pImplTypeInfo); - break; - } - pstr = ole_wc2mb(bstr); - if (strcmp(pitf, pstr) == 0) { - hr = pImplTypeInfo->lpVtbl->GetTypeAttr(pImplTypeInfo, - &pImplTypeAttr); - if (SUCCEEDED(hr)) { - is_found = TRUE; - *piid = pImplTypeAttr->guid; - if (ppTypeInfo) { - *ppTypeInfo = pImplTypeInfo; - (*ppTypeInfo)->lpVtbl->AddRef((*ppTypeInfo)); - } - pImplTypeInfo->lpVtbl->ReleaseTypeAttr(pImplTypeInfo, - pImplTypeAttr); - } - } - free(pstr); - OLE_RELEASE(pImplTypeInfo); - if (is_found || FAILED(hr)) - break; - } - } - - OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr); - OLE_RELEASE(pTypeInfo); - if (is_found || FAILED(hr)) - break; - } - OLE_RELEASE(pTypeLib); - if(!is_found) - return E_NOINTERFACE; - return hr; -} - -static HRESULT -find_coclass( - ITypeInfo *pTypeInfo, - TYPEATTR *pTypeAttr, - ITypeInfo **pCOTypeInfo, - TYPEATTR **pCOTypeAttr) -{ - HRESULT hr = E_NOINTERFACE; - ITypeLib *pTypeLib; - int count; - BOOL found = FALSE; - ITypeInfo *pTypeInfo2; - TYPEATTR *pTypeAttr2; - int flags; - int i,j; - HREFTYPE href; - ITypeInfo *pRefTypeInfo; - TYPEATTR *pRefTypeAttr; - - hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, NULL); - if (FAILED(hr)) { - return hr; - } - count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib); - for (i = 0; i < count && !found; i++) { - hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo2); - if (FAILED(hr)) - continue; - hr = OLE_GET_TYPEATTR(pTypeInfo2, &pTypeAttr2); - if (FAILED(hr)) { - OLE_RELEASE(pTypeInfo2); - continue; - } - if (pTypeAttr2->typekind != TKIND_COCLASS) { - OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2); - OLE_RELEASE(pTypeInfo2); - continue; - } - for (j = 0; j < pTypeAttr2->cImplTypes && !found; j++) { - hr = pTypeInfo2->lpVtbl->GetImplTypeFlags(pTypeInfo2, j, &flags); - if (FAILED(hr)) - continue; - if (!(flags & IMPLTYPEFLAG_FDEFAULT)) - continue; - hr = pTypeInfo2->lpVtbl->GetRefTypeOfImplType(pTypeInfo2, j, &href); - if (FAILED(hr)) - continue; - hr = pTypeInfo2->lpVtbl->GetRefTypeInfo(pTypeInfo2, href, &pRefTypeInfo); - if (FAILED(hr)) - continue; - hr = OLE_GET_TYPEATTR(pRefTypeInfo, &pRefTypeAttr); - if (FAILED(hr)) { - OLE_RELEASE(pRefTypeInfo); - continue; - } - if (IsEqualGUID(&(pTypeAttr->guid), &(pRefTypeAttr->guid))) { - found = TRUE; - } - } - if (!found) { - OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2); - OLE_RELEASE(pTypeInfo2); - } - } - OLE_RELEASE(pTypeLib); - if (found) { - *pCOTypeInfo = pTypeInfo2; - *pCOTypeAttr = pTypeAttr2; - hr = S_OK; - } else { - hr = E_NOINTERFACE; - } - return hr; -} - -static HRESULT -find_default_source_from_typeinfo( - ITypeInfo *pTypeInfo, - TYPEATTR *pTypeAttr, - ITypeInfo **ppTypeInfo) -{ - int i = 0; - HRESULT hr = E_NOINTERFACE; - int flags; - HREFTYPE hRefType; - /* Enumerate all implemented types of the COCLASS */ - for (i = 0; i < pTypeAttr->cImplTypes; i++) { - hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags); - if (FAILED(hr)) - continue; - - /* - looking for the [default] [source] - we just hope that it is a dispinterface :-) - */ - if ((flags & IMPLTYPEFLAG_FDEFAULT) && - (flags & IMPLTYPEFLAG_FSOURCE)) { - - hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, - i, &hRefType); - if (FAILED(hr)) - continue; - hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, - hRefType, ppTypeInfo); - if (SUCCEEDED(hr)) - break; - } - } - return hr; -} - -static HRESULT -find_default_source(VALUE ole, IID *piid, ITypeInfo **ppTypeInfo) -{ - HRESULT hr; - IProvideClassInfo2 *pProvideClassInfo2; - IProvideClassInfo *pProvideClassInfo; - void *p; - - IDispatch *pDispatch; - ITypeInfo *pTypeInfo; - ITypeInfo *pTypeInfo2 = NULL; - TYPEATTR *pTypeAttr; - TYPEATTR *pTypeAttr2 = NULL; - - struct oledata *pole; - - OLEData_Get_Struct(ole, pole); - pDispatch = pole->pDispatch; - hr = pDispatch->lpVtbl->QueryInterface(pDispatch, - &IID_IProvideClassInfo2, - &p); - if (SUCCEEDED(hr)) { - pProvideClassInfo2 = p; - hr = pProvideClassInfo2->lpVtbl->GetGUID(pProvideClassInfo2, - GUIDKIND_DEFAULT_SOURCE_DISP_IID, - piid); - OLE_RELEASE(pProvideClassInfo2); - if (SUCCEEDED(hr)) { - hr = find_iid(ole, NULL, piid, ppTypeInfo); - } - } - if (SUCCEEDED(hr)) { - return hr; - } - hr = pDispatch->lpVtbl->QueryInterface(pDispatch, - &IID_IProvideClassInfo, - &p); - if (SUCCEEDED(hr)) { - pProvideClassInfo = p; - hr = pProvideClassInfo->lpVtbl->GetClassInfo(pProvideClassInfo, - &pTypeInfo); - OLE_RELEASE(pProvideClassInfo); - } - if (FAILED(hr)) { - hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, cWIN32OLE_lcid, &pTypeInfo ); - } - if (FAILED(hr)) - return hr; - hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr); - if (FAILED(hr)) { - OLE_RELEASE(pTypeInfo); - return hr; - } - - *ppTypeInfo = 0; - hr = find_default_source_from_typeinfo(pTypeInfo, pTypeAttr, ppTypeInfo); - if (!*ppTypeInfo) { - hr = find_coclass(pTypeInfo, pTypeAttr, &pTypeInfo2, &pTypeAttr2); - if (SUCCEEDED(hr)) { - hr = find_default_source_from_typeinfo(pTypeInfo2, pTypeAttr2, ppTypeInfo); - OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2); - OLE_RELEASE(pTypeInfo2); - } - } - OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr); - OLE_RELEASE(pTypeInfo); - /* Now that would be a bad surprise, if we didn't find it, wouldn't it? */ - if (!*ppTypeInfo) { - if (SUCCEEDED(hr)) - hr = E_UNEXPECTED; - return hr; - } - - /* Determine IID of default source interface */ - hr = (*ppTypeInfo)->lpVtbl->GetTypeAttr(*ppTypeInfo, &pTypeAttr); - if (SUCCEEDED(hr)) { - *piid = pTypeAttr->guid; - (*ppTypeInfo)->lpVtbl->ReleaseTypeAttr(*ppTypeInfo, pTypeAttr); - } - else - OLE_RELEASE(*ppTypeInfo); - - return hr; - -} - -static void -ole_event_free(struct oleeventdata *poleev) -{ - if (poleev->pConnectionPoint) { - poleev->pConnectionPoint->lpVtbl->Unadvise(poleev->pConnectionPoint, poleev->dwCookie); - OLE_RELEASE(poleev->pConnectionPoint); - poleev->pConnectionPoint = NULL; - } - free(poleev); -} - -static VALUE -fev_s_allocate(VALUE klass) -{ - VALUE obj; - struct oleeventdata *poleev; - obj = Data_Make_Struct(klass,struct oleeventdata,0,ole_event_free,poleev); - poleev->dwCookie = 0; - poleev->pConnectionPoint = NULL; - poleev->event_id = 0; - return obj; -} - -static VALUE -ev_advise(int argc, VALUE *argv, VALUE self) -{ - - VALUE ole, itf; - struct oledata *pole; - char *pitf; - HRESULT hr; - IID iid; - ITypeInfo *pTypeInfo = 0; - IDispatch *pDispatch; - IConnectionPointContainer *pContainer; - IConnectionPoint *pConnectionPoint; - IEVENTSINKOBJ *pIEV; - DWORD dwCookie; - struct oleeventdata *poleev; - void *p; - - rb_scan_args(argc, argv, "11", &ole, &itf); - - if (!rb_obj_is_kind_of(ole, cWIN32OLE)) { - rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE object"); - } - - if(!RB_TYPE_P(itf, T_NIL)) { - if (rb_safe_level() > 0 && OBJ_TAINTED(itf)) { - rb_raise(rb_eSecurityError, "Insecure Event Creation - %s", - StringValuePtr(itf)); - } - SafeStringValue(itf); - pitf = StringValuePtr(itf); - hr = find_iid(ole, pitf, &iid, &pTypeInfo); - } - else { - hr = find_default_source(ole, &iid, &pTypeInfo); - } - if (FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "interface not found"); - } - - OLEData_Get_Struct(ole, pole); - pDispatch = pole->pDispatch; - hr = pDispatch->lpVtbl->QueryInterface(pDispatch, - &IID_IConnectionPointContainer, - &p); - if (FAILED(hr)) { - OLE_RELEASE(pTypeInfo); - ole_raise(hr, rb_eRuntimeError, - "failed to query IConnectionPointContainer"); - } - pContainer = p; - - hr = pContainer->lpVtbl->FindConnectionPoint(pContainer, - &iid, - &pConnectionPoint); - OLE_RELEASE(pContainer); - if (FAILED(hr)) { - OLE_RELEASE(pTypeInfo); - ole_raise(hr, rb_eRuntimeError, "failed to query IConnectionPoint"); - } - pIEV = EVENTSINK_Constructor(); - pIEV->m_iid = iid; - hr = pConnectionPoint->lpVtbl->Advise(pConnectionPoint, - (IUnknown*)pIEV, - &dwCookie); - if (FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "Advise Error"); - } - - Data_Get_Struct(self, struct oleeventdata, poleev); - pIEV->m_event_id - = NUM2INT(evs_length()); - pIEV->pTypeInfo = pTypeInfo; - poleev->dwCookie = dwCookie; - poleev->pConnectionPoint = pConnectionPoint; - poleev->event_id = pIEV->m_event_id; - - return self; -} - -/* - * call-seq: - * WIN32OLE_EVENT.new(ole, event) #=> WIN32OLE_EVENT object. - * - * Returns OLE event object. - * The first argument specifies WIN32OLE object. - * The second argument specifies OLE event name. - * ie = WIN32OLE.new('InternetExplorer.Application') - * ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents') - */ -static VALUE -fev_initialize(int argc, VALUE *argv, VALUE self) -{ - ev_advise(argc, argv, self); - evs_push(self); - rb_ivar_set(self, id_events, rb_ary_new()); - fev_set_handler(self, Qnil); - return self; -} - -/* - * call-seq: - * WIN32OLE_EVENT.message_loop - * - * Translates and dispatches Windows message. - */ -static VALUE -fev_s_msg_loop(VALUE klass) -{ - ole_msg_loop(); - return Qnil; -} - - -static void -add_event_call_back(VALUE obj, VALUE event, VALUE data) -{ - VALUE events = rb_ivar_get(obj, id_events); - if (NIL_P(events) || !RB_TYPE_P(events, T_ARRAY)) { - events = rb_ary_new(); - rb_ivar_set(obj, id_events, events); - } - ole_delete_event(events, event); - rb_ary_push(events, data); -} - -static VALUE -ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg) -{ - struct oleeventdata *poleev; - VALUE event, args, data; - Data_Get_Struct(self, struct oleeventdata, poleev); - if (poleev->pConnectionPoint == NULL) { - rb_raise(eWIN32OLERuntimeError, "IConnectionPoint not found. You must call advise at first."); - } - rb_scan_args(argc, argv, "01*", &event, &args); - if(!NIL_P(event)) { - if(!RB_TYPE_P(event, T_STRING) && !RB_TYPE_P(event, T_SYMBOL)) { - rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)"); - } - if (RB_TYPE_P(event, T_SYMBOL)) { - event = rb_sym_to_s(event); - } - } - data = rb_ary_new3(4, rb_block_proc(), event, args, is_ary_arg); - add_event_call_back(self, event, data); - return Qnil; -} - -/* - * call-seq: - * WIN32OLE_EVENT#on_event([event]){...} - * - * Defines the callback event. - * If argument is omitted, this method defines the callback of all events. - * If you want to modify reference argument in callback, return hash in - * callback. If you want to return value to OLE server as result of callback - * use `return' or :return. - * - * ie = WIN32OLE.new('InternetExplorer.Application') - * ev = WIN32OLE_EVENT.new(ie) - * ev.on_event("NavigateComplete") {|url| puts url} - * ev.on_event() {|ev, *args| puts "#{ev} fired"} - * - * ev.on_event("BeforeNavigate2") {|*args| - * ... - * # set true to BeforeNavigate reference argument `Cancel'. - * # Cancel is 7-th argument of BeforeNavigate, - * # so you can use 6 as key of hash instead of 'Cancel'. - * # The argument is counted from 0. - * # The hash key of 0 means first argument.) - * {:Cancel => true} # or {'Cancel' => true} or {6 => true} - * } - * - * ev.on_event(...) {|*args| - * {:return => 1, :xxx => yyy} - * } - */ -static VALUE -fev_on_event(int argc, VALUE *argv, VALUE self) -{ - return ev_on_event(argc, argv, self, Qfalse); -} - -/* - * call-seq: - * WIN32OLE_EVENT#on_event_with_outargs([event]){...} - * - * Defines the callback of event. - * If you want modify argument in callback, - * you could use this method instead of WIN32OLE_EVENT#on_event. - * - * ie = WIN32OLE.new('InternetExplorer.Application') - * ev = WIN32OLE_EVENT.new(ie) - * ev.on_event_with_outargs('BeforeNavigate2') {|*args| - * args.last[6] = true - * } - */ -static VALUE -fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self) -{ - return ev_on_event(argc, argv, self, Qtrue); -} - -/* - * call-seq: - * WIN32OLE_EVENT#off_event([event]) - * - * removes the callback of event. - * - * ie = WIN32OLE.new('InternetExplorer.Application') - * ev = WIN32OLE_EVENT.new(ie) - * ev.on_event('BeforeNavigate2') {|*args| - * args.last[6] = true - * } - * ... - * ev.off_event('BeforeNavigate2') - * ... - */ -static VALUE -fev_off_event(int argc, VALUE *argv, VALUE self) -{ - VALUE event = Qnil; - VALUE events; - - rb_scan_args(argc, argv, "01", &event); - if(!NIL_P(event)) { - if(!RB_TYPE_P(event, T_STRING) && !RB_TYPE_P(event, T_SYMBOL)) { - rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)"); - } - if (RB_TYPE_P(event, T_SYMBOL)) { - event = rb_sym_to_s(event); - } - } - events = rb_ivar_get(self, id_events); - if (NIL_P(events)) { - return Qnil; - } - ole_delete_event(events, event); - return Qnil; -} - -/* - * call-seq: - * WIN32OLE_EVENT#unadvise -> nil - * - * disconnects OLE server. If this method called, then the WIN32OLE_EVENT object - * does not receive the OLE server event any more. - * This method is trial implementation. - * - * ie = WIN32OLE.new('InternetExplorer.Application') - * ev = WIN32OLE_EVENT.new(ie) - * ev.on_event() {...} - * ... - * ev.unadvise - * - */ -static VALUE -fev_unadvise(VALUE self) -{ - struct oleeventdata *poleev; - Data_Get_Struct(self, struct oleeventdata, poleev); - if (poleev->pConnectionPoint) { - ole_msg_loop(); - evs_delete(poleev->event_id); - poleev->pConnectionPoint->lpVtbl->Unadvise(poleev->pConnectionPoint, poleev->dwCookie); - OLE_RELEASE(poleev->pConnectionPoint); - poleev->pConnectionPoint = NULL; - } - return Qnil; -} - -static VALUE -evs_push(VALUE ev) -{ - return rb_ary_push(ary_ole_event, ev); -} - -static VALUE -evs_delete(long i) -{ - rb_ary_store(ary_ole_event, i, Qnil); - return Qnil; -} - -static VALUE -evs_entry(long i) -{ - return rb_ary_entry(ary_ole_event, i); -} - -static VALUE -evs_length(void) -{ - return rb_funcall(ary_ole_event, rb_intern("length"), 0); -} - -/* - * call-seq: - * WIN32OLE_EVENT#handler= - * - * sets event handler object. If handler object has onXXX - * method according to XXX event, then onXXX method is called - * when XXX event occurs. - * - * If handler object has method_missing and there is no - * method according to the event, then method_missing - * called and 1-st argument is event name. - * - * If handler object has onXXX method and there is block - * defined by WIN32OLE_EVENT#on_event('XXX'){}, - * then block is executed but handler object method is not called - * when XXX event occurs. - * - * class Handler - * def onStatusTextChange(text) - * puts "StatusTextChanged" - * end - * def onPropertyChange(prop) - * puts "PropertyChanged" - * end - * def method_missing(ev, *arg) - * puts "other event #{ev}" - * end - * end - * - * handler = Handler.new - * ie = WIN32OLE.new('InternetExplorer.Application') - * ev = WIN32OLE_EVENT.new(ie) - * ev.on_event("StatusTextChange") {|*args| - * puts "this block executed." - * puts "handler.onStatusTextChange method is not called." - * } - * ev.handler = handler - * - */ -static VALUE -fev_set_handler(VALUE self, VALUE val) -{ - return rb_ivar_set(self, rb_intern("handler"), val); -} - -/* - * call-seq: - * WIN32OLE_EVENT#handler - * - * returns handler object. - * - */ -static VALUE -fev_get_handler(VALUE self) -{ - return rb_ivar_get(self, rb_intern("handler")); -} - HRESULT typelib_from_val(VALUE obj, ITypeLib **pTypeLib) { @@ -5069,9 +3822,6 @@ Init_win32ole(void) { cWIN32OLE_lcid = LOCALE_SYSTEM_DEFAULT; g_ole_initialized_init(); - ary_ole_event = rb_ary_new(); - rb_gc_register_mark_object(ary_ole_event); - id_events = rb_intern("events"); com_vtbl.QueryInterface = QueryInterface; com_vtbl.AddRef = AddRef; @@ -5229,18 +3979,7 @@ Init_win32ole(void) Init_win32ole_variable(); Init_win32ole_method(); Init_win32ole_param(); - - cWIN32OLE_EVENT = rb_define_class("WIN32OLE_EVENT", rb_cObject); - rb_define_singleton_method(cWIN32OLE_EVENT, "message_loop", fev_s_msg_loop, 0); - rb_define_alloc_func(cWIN32OLE_EVENT, fev_s_allocate); - rb_define_method(cWIN32OLE_EVENT, "initialize", fev_initialize, -1); - rb_define_method(cWIN32OLE_EVENT, "on_event", fev_on_event, -1); - rb_define_method(cWIN32OLE_EVENT, "on_event_with_outargs", fev_on_event_with_outargs, -1); - rb_define_method(cWIN32OLE_EVENT, "off_event", fev_off_event, -1); - rb_define_method(cWIN32OLE_EVENT, "unadvise", fev_unadvise, 0); - rb_define_method(cWIN32OLE_EVENT, "handler=", fev_set_handler, 1); - rb_define_method(cWIN32OLE_EVENT, "handler", fev_get_handler, 0); - + Init_win32ole_event(); Init_win32ole_variant(); Init_win32ole_record(); Init_win32ole_error(); -- cgit v1.2.3