*** win32ole.c.org Fri Sep 03 23:11:40 2010 --- win32ole.c Fri Sep 10 02:56:05 2010 *************** const IID IID_IMultiLanguage2 = {0xDCCFC *** 107,112 **** --- 107,113 ---- #endif #define OLE_RELEASE(X) (X) ? ((X)->lpVtbl->Release(X)) : 0 + #define OLE_RELEASE_GLOBAL(X) (globalInterfaceTable && X) ? ((X)->lpVtbl->Release(X)) : 0 #define OLE_ADDREF(X) (X) ? ((X)->lpVtbl->AddRef(X)) : 0 *************** const IID IID_IMultiLanguage2 = {0xDCCFC *** 124,132 **** #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");\ }\ } #ifdef HAVE_LONG_LONG --- 125,145 ---- #define OLEData_Get_Struct(obj, pole) {\ Data_Get_Struct(obj, struct oledata, pole);\ ! if(!pole->pDispatch && !pole->intfCookie) {\ rb_raise(rb_eRuntimeError, "failed to get Dispatch Interface");\ }\ + if(!g_ole_initialized) {\ + ole_initialize();\ + }\ + if (!globalInterfaceTable) {\ + if(GetCurrentThreadId() != pole->orgThread) { \ + rb_raise(rb_eRuntimeError, "failed to interchange dispatch");\ + }\ + } else {\ + globalInterfaceTable->lpVtbl->GetInterfaceFromGlobal(\ + globalInterfaceTable,\ + pole->intfCookie, &IID_IDispatch, (void**)&pole->pDispatch);\ + }\ } #ifdef HAVE_LONG_LONG *************** VALUE cWIN32OLE_PROPERTY; *** 214,220 **** static VALUE ary_ole_event; static ID id_events; ! static BOOL g_ole_initialized = FALSE; static BOOL g_cp_installed = FALSE; static BOOL g_lcid_installed = FALSE; static HINSTANCE ghhctrl = NULL; --- 227,233 ---- static VALUE ary_ole_event; static ID id_events; ! __declspec(thread) BOOL g_ole_initialized = FALSE; static BOOL g_cp_installed = FALSE; static BOOL g_lcid_installed = FALSE; static HINSTANCE ghhctrl = NULL; *************** static st_table *enc2cp_table; *** 232,237 **** --- 245,252 ---- static IMessageFilterVtbl message_filter; static IMessageFilter imessage_filter = { &message_filter }; static IMessageFilter* previous_filter; + static IGlobalInterfaceTable* globalInterfaceTable; + static VALUE globalInterfaceCookies; #if defined(HAVE_TYPE_IMULTILANGUAGE2) static IMultiLanguage2 *pIMultiLanguage = NULL; *************** static IMultiLanguage *pIMultiLanguage = *** 242,247 **** --- 257,264 ---- #endif struct oledata { + DWORD orgThread; + DWORD intfCookie; IDispatch *pDispatch; }; *************** static VALUE fole_s_set_locale(VALUE sel *** 372,378 **** static VALUE fole_s_create_guid(VALUE self); static void ole_pure_initialize(); static VALUE fole_s_ole_initialize(VALUE self); ! static void ole_pure_uninitialize(); static VALUE fole_s_ole_uninitialize(VALUE self); static VALUE fole_initialize(int argc, VALUE *argv, VALUE self); static VALUE hash2named_arg(VALUE pair, struct oleparam* pOp); --- 389,395 ---- static VALUE fole_s_create_guid(VALUE self); static void ole_pure_initialize(); static VALUE fole_s_ole_initialize(VALUE self); ! static void ole_pure_uninitialize(VALUE dummy); static VALUE fole_s_ole_uninitialize(VALUE self); static VALUE fole_initialize(int argc, VALUE *argv, VALUE self); static VALUE hash2named_arg(VALUE pair, struct oleparam* pOp); *************** ole_raise(HRESULT hr, VALUE ecs, const c *** 1196,1201 **** --- 1213,1222 ---- void ole_uninitialize() { + if (globalInterfaceTable) { + globalInterfaceTable->lpVtbl->Release(globalInterfaceTable); + globalInterfaceTable = NULL; + } OleUninitialize(); g_ole_initialized = FALSE; } *************** ole_val2variant(VALUE val, VARIANT *var) *** 1610,1617 **** struct oledata *pole; struct olevariantdata *pvar; if(rb_obj_is_kind_of(val, cWIN32OLE)) { ! Data_Get_Struct(val, struct oledata, pole); ! OLE_ADDREF(pole->pDispatch); V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = pole->pDispatch; return; --- 1631,1637 ---- struct oledata *pole; struct olevariantdata *pvar; if(rb_obj_is_kind_of(val, cWIN32OLE)) { ! OLEData_Get_Struct(val, pole); V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = pole->pDispatch; return; *************** ole_set_member(VALUE self, IDispatch *di *** 1985,1995 **** { struct oledata *pole; Data_Get_Struct(self, struct oledata, pole); ! if (pole->pDispatch) { OLE_RELEASE(pole->pDispatch); pole->pDispatch = NULL; } ! pole->pDispatch = dispatch; return self; } --- 2005,2029 ---- { struct oledata *pole; Data_Get_Struct(self, struct oledata, pole); ! if (pole->intfCookie) { ! globalInterfaceTable->lpVtbl->RevokeInterfaceFromGlobal( ! globalInterfaceTable, pole->intfCookie); ! rb_ary_delete(globalInterfaceCookies, INT2FIX(pole->intfCookie)); ! pole->intfCookie = 0; ! } else if (pole->pDispatch) { OLE_RELEASE(pole->pDispatch); pole->pDispatch = NULL; } ! pole->orgThread = GetCurrentThreadId(); ! if (globalInterfaceTable) { ! globalInterfaceTable->lpVtbl->RegisterInterfaceInGlobal( ! globalInterfaceTable, (IUnknown*)dispatch, ! &IID_IDispatch, &pole->intfCookie); ! rb_ary_push(globalInterfaceCookies, INT2FIX(pole->intfCookie)); ! OLE_RELEASE(dispatch); ! } else { ! pole->pDispatch = dispatch; ! } return self; } *************** fole_s_const_load(int argc, VALUE *argv, *** 2799,2804 **** --- 2833,2839 ---- ole_const_load(pTypeLib, cWIN32OLE, self); } OLE_RELEASE(pTypeLib); + OLE_RELEASE_GLOBAL(pole->pDispatch); } else if(TYPE(ole) == T_STRING) { file = typelib_file(ole); *************** static VALUE *** 2879,2886 **** fole_s_reference_count(VALUE self, VALUE obj) { struct oledata * pole; OLEData_Get_Struct(obj, pole); ! return INT2NUM(reference_count(pole)); } /* --- 2914,2924 ---- fole_s_reference_count(VALUE self, VALUE obj) { struct oledata * pole; + VALUE ret; OLEData_Get_Struct(obj, pole); ! ret = INT2NUM(reference_count(pole)); ! OLE_RELEASE_GLOBAL(pole->pDispatch); ! return ret; } /* *************** fole_s_free(VALUE self, VALUE obj) *** 2899,2906 **** struct oledata * pole; OLEData_Get_Struct(obj, pole); if(pole->pDispatch) { ! if (reference_count(pole) > 0) { ! n = OLE_RELEASE(pole->pDispatch); } } return INT2NUM(n); --- 2937,2951 ---- struct oledata * pole; OLEData_Get_Struct(obj, pole); if(pole->pDispatch) { ! n = reference_count(pole); ! if (n > 0) { ! n = OLE_RELEASE_GLOBAL(pole->pDispatch); ! if (globalInterfaceTable) { ! globalInterfaceTable->lpVtbl->RevokeInterfaceFromGlobal( ! globalInterfaceTable, pole->intfCookie); ! rb_ary_delete(globalInterfaceCookies, INT2FIX(pole->intfCookie)); ! n = 0; ! } } } return INT2NUM(n); *************** static void ole_pure_initialize() *** 3128,3135 **** } } ! static void ole_pure_uninitialize() { OleUninitialize(); } --- 3173,3192 ---- } } ! static void ole_pure_uninitialize(VALUE dummy) { + if (globalInterfaceTable) { + int i; + int len = RARRAY_LEN(globalInterfaceCookies); + for (i = 0; i < len; i++) { + DWORD dwCookie = FIX2INT(rb_ary_entry(globalInterfaceCookies, i)); + globalInterfaceTable->lpVtbl->RevokeInterfaceFromGlobal( + globalInterfaceTable, dwCookie); + } + + globalInterfaceTable->lpVtbl->Release(globalInterfaceTable); + globalInterfaceTable = NULL; + } OleUninitialize(); } *************** fole_s_ole_initialize(VALUE self) *** 3145,3151 **** static VALUE fole_s_ole_uninitialize(VALUE self) { ! ole_pure_uninitialize(); return Qnil; } --- 3202,3208 ---- static VALUE fole_s_ole_uninitialize(VALUE self) { ! ole_pure_uninitialize(Qnil); return Qnil; } *************** ole_invoke(int argc, VALUE *argv, VALUE *** 3540,3545 **** --- 3597,3603 ---- } obj = ole_variant2val(&result); VariantClear(&result); + OLE_RELEASE_GLOBAL(pole->pDispatch); return obj; } *************** ole_invoke2(VALUE self, VALUE dispid, VA *** 3749,3754 **** --- 3807,3813 ---- obj = ole_variant2val(&result); VariantClear(&result); + OLE_RELEASE_GLOBAL(pole->pDispatch); return obj; } *************** ole_propertyput(VALUE self, VALUE proper *** 3925,3930 **** --- 3984,3990 ---- StringValuePtr(property), StringValuePtr(v)); } + OLE_RELEASE_GLOBAL(pole->pDispatch); return Qnil; } *************** fole_free(VALUE self) *** 3943,3949 **** struct oledata *pole; rb_secure(4); OLEData_Get_Struct(self, pole); ! OLE_FREE(pole->pDispatch); pole->pDispatch = NULL; return Qnil; } --- 4003,4017 ---- struct oledata *pole; rb_secure(4); OLEData_Get_Struct(self, pole); ! if (globalInterfaceTable) { ! OLE_RELEASE_GLOBAL(pole->pDispatch); ! globalInterfaceTable->lpVtbl->RevokeInterfaceFromGlobal( ! globalInterfaceTable, pole->intfCookie); ! rb_ary_delete(globalInterfaceCookies, INT2FIX(pole->intfCookie)); ! } else { ! OLE_FREE(pole->pDispatch); ! } ! pole->intfCookie = 0; pole->pDispatch = NULL; return Qnil; } *************** fole_each(VALUE self) *** 4016,4022 **** DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dispParams, &result, &excepinfo, &argErr); ! if (FAILED(hr)) { VariantClear(&result); ole_raise(hr, eWIN32OLERuntimeError, "failed to get IEnum Interface"); --- 4084,4090 ---- DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dispParams, &result, &excepinfo, &argErr); ! OLE_RELEASE_GLOBAL(pole->pDispatch); if (FAILED(hr)) { VariantClear(&result); ole_raise(hr, eWIN32OLERuntimeError, "failed to get IEnum Interface"); *************** ole_methods(VALUE self, int mask) *** 4262,4267 **** --- 4330,4336 ---- methods = rb_ary_new(); hr = typeinfo_from_ole(pole, &pTypeInfo); + OLE_RELEASE_GLOBAL(pole->pDispatch); if(FAILED(hr)) return methods; rb_ary_concat(methods, ole_methods_from_typeinfo(pTypeInfo, mask)); *************** fole_type(VALUE self) *** 4380,4385 **** --- 4449,4455 ---- OLEData_Get_Struct(self, pole); hr = pole->pDispatch->lpVtbl->GetTypeInfo( pole->pDispatch, 0, lcid, &pTypeInfo ); + OLE_RELEASE_GLOBAL(pole->pDispatch); if(FAILED(hr)) { ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo"); } *************** fole_typelib(VALUE self) *** 4431,4436 **** --- 4501,4507 ---- OLEData_Get_Struct(self, pole); hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch, 0, lcid, &pTypeInfo); + OLE_RELEASE_GLOBAL(pole->pDispatch); if(FAILED(hr)) { ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo"); } *************** fole_query_interface(VALUE self, VALUE s *** 4483,4489 **** "failed to get interface `%s'", StringValuePtr(str_iid)); } ! pDispatch = p; return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0); } --- 4554,4560 ---- "failed to get interface `%s'", StringValuePtr(str_iid)); } ! OLE_RELEASE_GLOBAL(pole->pDispatch); pDispatch = p; return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0); } *************** fole_respond_to(VALUE self, VALUE method *** 4516,4521 **** --- 4587,4593 ---- hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL, &wcmdname, 1, cWIN32OLE_lcid, &DispID); SysFreeString(wcmdname); + OLE_RELEASE_GLOBAL(pole->pDispatch); return SUCCEEDED(hr) ? Qtrue : Qfalse; } *************** fole_method_help(VALUE self, VALUE cmdna *** 4719,4724 **** --- 4791,4797 ---- hr = typeinfo_from_ole(pole, &pTypeInfo); if(FAILED(hr)) ole_raise(hr, rb_eRuntimeError, "failed to get ITypeInfo"); + OLE_RELEASE_GLOBAL(pole->pDispatch); method = folemethod_s_allocate(cWIN32OLE_METHOD); obj = olemethod_from_typeinfo(method, pTypeInfo, cmdname); OLE_RELEASE(pTypeInfo); *************** fole_activex_initialize(VALUE self) *** 4760,4765 **** --- 4833,4839 ---- OLEData_Get_Struct(self, pole); hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &IID_IPersistMemory, &p); + OLE_RELEASE_GLOBAL(pole->pDispatch); pPersistMemory = p; if (SUCCEEDED(hr)) { hr = pPersistMemory->lpVtbl->InitNew(pPersistMemory); *************** find_iid(VALUE ole, char *pitf, IID *pii *** 7958,7963 **** --- 8032,8038 ---- pDispatch = pole->pDispatch; hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, lcid, &pTypeInfo); + OLE_RELEASE_GLOBAL(pole->pDispatch); if (FAILED(hr)) return hr; *************** find_default_source(VALUE ole, IID *piid *** 8174,8179 **** --- 8249,8255 ---- hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IProvideClassInfo2, &p); + OLE_RELEASE_GLOBAL(pole->pDispatch); if (SUCCEEDED(hr)) { pProvideClassInfo2 = p; hr = pProvideClassInfo2->lpVtbl->GetGUID(pProvideClassInfo2, *************** ev_advise(int argc, VALUE *argv, VALUE s *** 8308,8313 **** --- 8384,8390 ---- hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IConnectionPointContainer, &p); + OLE_RELEASE_GLOBAL(pole->pDispatch); if (FAILED(hr)) { OLE_RELEASE(pTypeInfo); ole_raise(hr, rb_eRuntimeError, *************** folevariant_set_value(VALUE self, VALUE *** 9047,9052 **** --- 9124,9131 ---- return Qnil; } + static unsigned monitor_id; + static void init_enc2cp() { *************** Init_win32ole() *** 9301,9304 **** --- 9380,9396 ---- init_enc2cp(); atexit((void (*)(void))free_enc2cp); ole_init_cp(); + + ole_initialize(); + if (CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, + CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, + (void**)&globalInterfaceTable) != S_OK) + { + globalInterfaceTable = NULL; + } else { + rb_set_end_proc(ole_pure_uninitialize, Qnil); + + globalInterfaceCookies = rb_ary_new(); + rb_gc_register_mark_object(globalInterfaceCookies); + } }