diff options
Diffstat (limited to 'ext/win32ole/win32ole.c')
-rw-r--r-- | ext/win32ole/win32ole.c | 115 |
1 files changed, 113 insertions, 2 deletions
diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index 662f5f1a87..dc1b77d5e9 100644 --- a/ext/win32ole/win32ole.c +++ b/ext/win32ole/win32ole.c @@ -29,7 +29,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) @@ -79,7 +79,7 @@ #define WC2VSTR(x) ole_wc2vstr((x), TRUE) -#define WIN32OLE_VERSION "0.7.5" +#define WIN32OLE_VERSION "0.7.6" typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); @@ -157,6 +157,9 @@ static VALUE com_hash; static IDispatchVtbl com_vtbl; static UINT cWIN32OLE_cp = CP_ACP; static VARTYPE g_nil_to = VT_ERROR; +static IMessageFilterVtbl message_filter; +static IMessageFilter imessage_filter = { &message_filter }; +static IMessageFilter* previous_filter; struct oledata { IDispatch *pDispatch; @@ -203,6 +206,101 @@ static char *ole_wc2mb(LPWSTR); static VALUE ole_variant2val(VARIANT*); static void ole_val2variant(VALUE, VARIANT*); +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; @@ -625,6 +723,11 @@ ole_initialize() /* 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"); + } } } @@ -6135,6 +6238,14 @@ Init_win32ole() 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()); cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject); |