ruby-changes:6306
From: suke <ko1@a...>
Date: Thu, 3 Jul 2008 00:35:19 +0900 (JST)
Subject: [ruby-changes:6306] Ruby:r17821 (trunk): * ext/win32ole/win32ole.c: avoid creating Ruby object during
suke 2008-07-03 00:35:04 +0900 (Thu, 03 Jul 2008) New Revision: 17821 Modified files: trunk/ChangeLog trunk/ext/win32ole/win32ole.c trunk/test/win32ole/test_win32ole_event.rb Log: * ext/win32ole/win32ole.c: avoid creating Ruby object during GC. thanks to arton <artonx AT yahoo.co.jp>. [ruby-dev:35313] * test/win32ole/test_win32ole_event.rb: ditto. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=17821 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/win32ole/test_win32ole_event.rb?r1=17821&r2=17820&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=17821&r2=17820&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ext/win32ole/win32ole.c?r1=17821&r2=17820&diff_format=u Index: ChangeLog =================================================================== --- ChangeLog (revision 17820) +++ ChangeLog (revision 17821) @@ -1,3 +1,10 @@ +Thu Jul 3 00:18:00 2008 Masaki Suketa <masaki.suketa@n...> + + * ext/win32ole/win32ole.c: avoid creating Ruby object during + GC. thanks to arton <artonx AT yahoo.co.jp>. [ruby-dev:35313] + + * test/win32ole/test_win32ole_event.rb: ditto. + Thu Jul 3 00:09:31 2008 Masaki Suketa <masaki.suketa@n...> * gc.c: add rb_during_gc(). based on a patch from arton <artonx AT Index: ext/win32ole/win32ole.c =================================================================== --- ext/win32ole/win32ole.c (revision 17820) +++ ext/win32ole/win32ole.c (revision 17821) @@ -31,6 +31,7 @@ #include <varargs.h> #define va_init_list(a,b) va_start(a) #endif +#include <objidl.h> #define DOUT fprintf(stderr,"[%d]\n",__LINE__) #define DOUTS(x) fprintf(stderr,"[%d]:" #x "=%s\n",__LINE__,x) @@ -116,7 +117,7 @@ #define WC2VSTR(x) ole_wc2vstr((x), TRUE) -#define WIN32OLE_VERSION "1.1.7" +#define WIN32OLE_VERSION "1.1.8" typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); @@ -202,6 +203,9 @@ static char g_lcid_to_check[8 + 1]; static VARTYPE g_nil_to = VT_ERROR; static st_table *enc2cp_table; +static IMessageFilterVtbl message_filter; +static IMessageFilter imessage_filter = { &message_filter }; +static IMessageFilter* previous_filter; struct oledata { IDispatch *pDispatch; @@ -523,6 +527,101 @@ static void init_enc2cp(); static void free_enc2cp(); +static HRESULT (STDMETHODCALLTYPE mf_QueryInterface)( + IMessageFilter __RPC_FAR * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +{ + if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0 + || MEMCMP(riid, &IID_IMessageFilter, GUID, 1) == 0) + { + *ppvObject = &message_filter; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG (STDMETHODCALLTYPE mf_AddRef)( + IMessageFilter __RPC_FAR * This) +{ + return 1; +} + +static ULONG (STDMETHODCALLTYPE mf_Release)( + IMessageFilter __RPC_FAR * This) +{ + return 1; +} + +static DWORD (STDMETHODCALLTYPE mf_HandleInComingCall)( + IMessageFilter __RPC_FAR * pThis, + DWORD dwCallType, //Type of incoming call + HTASK threadIDCaller, //Task handle calling this task + DWORD dwTickCount, //Elapsed tick count + LPINTERFACEINFO lpInterfaceInfo //Pointer to INTERFACEINFO structure + ) +{ +#ifdef DEBUG_MESSAGEFILTER + printf("incoming %08X, %08X, %d\n", dwCallType, threadIDCaller, dwTickCount); + fflush(stdout); +#endif + switch (dwCallType) + { + case CALLTYPE_ASYNC: + case CALLTYPE_TOPLEVEL_CALLPENDING: + case CALLTYPE_ASYNC_CALLPENDING: + if (rb_during_gc()) { + return SERVERCALL_RETRYLATER; + } + break; + default: + break; + } + if (previous_filter) { + return previous_filter->lpVtbl->HandleInComingCall(previous_filter, + dwCallType, + threadIDCaller, + dwTickCount, + lpInterfaceInfo); + } + return SERVERCALL_ISHANDLED; +} + +static DWORD (STDMETHODCALLTYPE mf_RetryRejectedCall)( + IMessageFilter* pThis, + HTASK threadIDCallee, //Server task handle + DWORD dwTickCount, //Elapsed tick count + DWORD dwRejectType //Returned rejection message + ) +{ + if (previous_filter) { + return previous_filter->lpVtbl->RetryRejectedCall(previous_filter, + threadIDCallee, + dwTickCount, + dwRejectType); + } + return 1000; +} + +static DWORD (STDMETHODCALLTYPE mf_MessagePending)( + IMessageFilter* pThis, + HTASK threadIDCallee, //Called applications task handle + DWORD dwTickCount, //Elapsed tick count + DWORD dwPendingType //Call type + ) +{ + if (rb_during_gc()) { + return PENDINGMSG_WAITNOPROCESS; + } + if (previous_filter) { + return previous_filter->lpVtbl->MessagePending(previous_filter, + threadIDCallee, + dwTickCount, + dwPendingType); + } + return PENDINGMSG_WAITNOPROCESS; +} + typedef struct _Win32OLEIDispatch { IDispatch dispatch; @@ -1059,6 +1158,11 @@ /* atexit((void (*)(void))ole_uninitialize); */ + hr = CoRegisterMessageFilter(&imessage_filter, &previous_filter); + if(FAILED(hr)) { + previous_filter = NULL; + ole_raise(hr, rb_eRuntimeError, "fail: install OLE MessageFilter"); + } } } @@ -8168,7 +8272,16 @@ com_vtbl.GetTypeInfo = GetTypeInfo; com_vtbl.GetIDsOfNames = GetIDsOfNames; com_vtbl.Invoke = Invoke; + + message_filter.QueryInterface = mf_QueryInterface; + message_filter.AddRef = mf_AddRef; + message_filter.Release = mf_Release; + message_filter.HandleInComingCall = mf_HandleInComingCall; + message_filter.RetryRejectedCall = mf_RetryRejectedCall; + message_filter.MessagePending = mf_MessagePending; + com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable()); + com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable()); rb_register_mark_object(com_hash); cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject); Index: test/win32ole/test_win32ole_event.rb =================================================================== --- test/win32ole/test_win32ole_event.rb (revision 17820) +++ test/win32ole/test_win32ole_event.rb (revision 17821) @@ -35,6 +35,8 @@ ev.on_event {|*args| default_handler(*args)} @ie.navigate("file:///#{@f}") while @ie.busy + WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents') + GC.start sleep 0.1 end assert_match(/BeforeNavigate/, @event) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/