--- win32ole.c.org Fri Sep 03 23:11:40 2010 +++ win32ole.c Sat Sep 04 08:41:23 2010 @@ -124,9 +124,21 @@ #define OLEData_Get_Struct(obj, pole) {\ Data_Get_Struct(obj, struct oledata, pole);\ - if(!pole->pDispatch) {\ + 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 @@ -214,7 +226,7 @@ static VALUE ary_ole_event; static ID id_events; -static BOOL g_ole_initialized = FALSE; +__declspec(thread) BOOL g_ole_initialized = FALSE; static BOOL g_cp_installed = FALSE; static BOOL g_lcid_installed = FALSE; static HINSTANCE ghhctrl = NULL; @@ -232,6 +244,7 @@ static IMessageFilterVtbl message_filter; static IMessageFilter imessage_filter = { &message_filter }; static IMessageFilter* previous_filter; +static IGlobalInterfaceTable* globalInterfaceTable; #if defined(HAVE_TYPE_IMULTILANGUAGE2) static IMultiLanguage2 *pIMultiLanguage = NULL; @@ -242,6 +255,8 @@ #endif struct oledata { + DWORD orgThread; + DWORD intfCookie; IDispatch *pDispatch; }; @@ -1196,6 +1211,10 @@ void ole_uninitialize() { + if (globalInterfaceTable) { + globalInterfaceTable->lpVtbl->Release(globalInterfaceTable); + globalInterfaceTable = NULL; + } OleUninitialize(); g_ole_initialized = FALSE; } @@ -1610,8 +1629,7 @@ 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); + OLEData_Get_Struct(val, pole); V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = pole->pDispatch; return; @@ -1985,11 +2003,23 @@ { struct oledata *pole; Data_Get_Struct(self, struct oledata, pole); - if (pole->pDispatch) { + if (pole->intfCookie) { + globalInterfaceTable->lpVtbl->RevokeInterfaceFromGlobal( + globalInterfaceTable, pole->intfCookie); + pole->intfCookie = 0; + } else if (pole->pDispatch) { OLE_RELEASE(pole->pDispatch); pole->pDispatch = NULL; } - pole->pDispatch = dispatch; + pole->orgThread = GetCurrentThreadId(); + if (globalInterfaceTable) { + globalInterfaceTable->lpVtbl->RegisterInterfaceInGlobal( + globalInterfaceTable, (IUnknown*)dispatch, + &IID_IDispatch, &pole->intfCookie); + OLE_RELEASE(dispatch); + } else { + pole->pDispatch = dispatch; + } return self; } @@ -2799,6 +2829,7 @@ ole_const_load(pTypeLib, cWIN32OLE, self); } OLE_RELEASE(pTypeLib); + OLE_RELEASE(pole->pDispatch); } else if(TYPE(ole) == T_STRING) { file = typelib_file(ole); @@ -2879,8 +2910,11 @@ fole_s_reference_count(VALUE self, VALUE obj) { struct oledata * pole; + VALUE ret; OLEData_Get_Struct(obj, pole); - return INT2NUM(reference_count(pole)); + ret = INT2NUM(reference_count(pole)); + OLE_RELEASE(pole->pDispatch); + return ret; } /* @@ -2899,8 +2933,13 @@ struct oledata * pole; OLEData_Get_Struct(obj, pole); if(pole->pDispatch) { - if (reference_count(pole) > 0) { + int count = reference_count(pole); + if (count > 0) { n = OLE_RELEASE(pole->pDispatch); + if (n == 1 && globalInterfaceTable) { + globalInterfaceTable->lpVtbl->RevokeInterfaceFromGlobal( + globalInterfaceTable, pole->intfCookie); + } } } return INT2NUM(n); @@ -3130,6 +3169,10 @@ static void ole_pure_uninitialize() { + if (globalInterfaceTable) { + globalInterfaceTable->lpVtbl->Release(globalInterfaceTable); + globalInterfaceTable = NULL; + } OleUninitialize(); } @@ -3540,6 +3583,7 @@ } obj = ole_variant2val(&result); VariantClear(&result); + OLE_RELEASE(pole->pDispatch); return obj; } @@ -3749,6 +3793,7 @@ obj = ole_variant2val(&result); VariantClear(&result); + OLE_RELEASE(pole->pDispatch); return obj; } @@ -3925,6 +3970,7 @@ StringValuePtr(property), StringValuePtr(v)); } + OLE_RELEASE(pole->pDispatch); return Qnil; } @@ -3943,7 +3989,14 @@ struct oledata *pole; rb_secure(4); OLEData_Get_Struct(self, pole); - OLE_FREE(pole->pDispatch); + if (globalInterfaceTable) { + OLE_RELEASE(pole->pDispatch); + globalInterfaceTable->lpVtbl->RevokeInterfaceFromGlobal( + globalInterfaceTable, pole->intfCookie); + } else { + OLE_FREE(pole->pDispatch); + } + pole->intfCookie = 0; pole->pDispatch = NULL; return Qnil; } @@ -4016,7 +4069,7 @@ DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dispParams, &result, &excepinfo, &argErr); - + OLE_RELEASE(pole->pDispatch); if (FAILED(hr)) { VariantClear(&result); ole_raise(hr, eWIN32OLERuntimeError, "failed to get IEnum Interface"); @@ -4262,6 +4315,7 @@ methods = rb_ary_new(); hr = typeinfo_from_ole(pole, &pTypeInfo); + OLE_RELEASE(pole->pDispatch); if(FAILED(hr)) return methods; rb_ary_concat(methods, ole_methods_from_typeinfo(pTypeInfo, mask)); @@ -4380,6 +4434,7 @@ OLEData_Get_Struct(self, pole); hr = pole->pDispatch->lpVtbl->GetTypeInfo( pole->pDispatch, 0, lcid, &pTypeInfo ); + OLE_RELEASE(pole->pDispatch); if(FAILED(hr)) { ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo"); } @@ -4431,6 +4486,7 @@ OLEData_Get_Struct(self, pole); hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch, 0, lcid, &pTypeInfo); + OLE_RELEASE(pole->pDispatch); if(FAILED(hr)) { ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo"); } @@ -4483,7 +4539,7 @@ "failed to get interface `%s'", StringValuePtr(str_iid)); } - + OLE_RELEASE(pole->pDispatch); pDispatch = p; return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0); } @@ -4516,6 +4572,7 @@ hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL, &wcmdname, 1, cWIN32OLE_lcid, &DispID); SysFreeString(wcmdname); + OLE_RELEASE(pole->pDispatch); return SUCCEEDED(hr) ? Qtrue : Qfalse; } @@ -4719,6 +4776,7 @@ hr = typeinfo_from_ole(pole, &pTypeInfo); if(FAILED(hr)) ole_raise(hr, rb_eRuntimeError, "failed to get ITypeInfo"); + OLE_RELEASE(pole->pDispatch); method = folemethod_s_allocate(cWIN32OLE_METHOD); obj = olemethod_from_typeinfo(method, pTypeInfo, cmdname); OLE_RELEASE(pTypeInfo); @@ -4760,6 +4818,7 @@ OLEData_Get_Struct(self, pole); hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &IID_IPersistMemory, &p); + OLE_RELEASE(pole->pDispatch); pPersistMemory = p; if (SUCCEEDED(hr)) { hr = pPersistMemory->lpVtbl->InitNew(pPersistMemory); @@ -7958,6 +8017,7 @@ pDispatch = pole->pDispatch; hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, lcid, &pTypeInfo); + OLE_RELEASE(pole->pDispatch); if (FAILED(hr)) return hr; @@ -8174,6 +8234,7 @@ hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IProvideClassInfo2, &p); + OLE_RELEASE(pole->pDispatch); if (SUCCEEDED(hr)) { pProvideClassInfo2 = p; hr = pProvideClassInfo2->lpVtbl->GetGUID(pProvideClassInfo2, @@ -8308,6 +8369,7 @@ hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IConnectionPointContainer, &p); + OLE_RELEASE(pole->pDispatch); if (FAILED(hr)) { OLE_RELEASE(pTypeInfo); ole_raise(hr, rb_eRuntimeError, @@ -9056,6 +9118,10 @@ static void free_enc2cp() { + if (globalInterfaceTable) { + globalInterfaceTable->lpVtbl->Release(globalInterfaceTable); + globalInterfaceTable = NULL; + } st_free_table(enc2cp_table); } @@ -9301,4 +9367,12 @@ 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; + } }