*** win32ole.c.old Thu Sep 25 08:54:22 2003 --- win32ole.c Fri Feb 13 10:23:14 2004 *************** *** 153,154 **** --- 153,156 ---- static FNCOCREATEINSTANCEEX *gCoCreateInstanceEx = NULL; + static VALUE com_hash; + static IDispatchVtbl com_vtbl; *************** *** 194,196 **** --- 196,329 ---- static HRESULT ole_docinfo_from_type _((ITypeInfo *, BSTR *, BSTR *, DWORD *, BSTR *)); + static char *ole_wc2mb(LPWSTR); + static VALUE ole_variant2val(VARIANT*); + static void ole_val2variant(VALUE, VARIANT*); + typedef struct _Win32OLEIDispatch + { + IDispatch dispatch; + ULONG refcount; + VALUE obj; + } Win32OLEIDispatch; + + static HRESULT ( STDMETHODCALLTYPE QueryInterface )( + IDispatch __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_IDispatch, GUID, 1) == 0) + { + Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; + p->refcount++; + *ppvObject = This; + return S_OK; + } + return E_NOINTERFACE; + } + + static ULONG ( STDMETHODCALLTYPE AddRef )( + IDispatch __RPC_FAR * This) + { + Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; + return ++(p->refcount); + } + + static ULONG ( STDMETHODCALLTYPE Release )( + IDispatch __RPC_FAR * This) + { + Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; + ULONG u = --(p->refcount); + if (u == 0) { + st_data_t key = p->obj; + st_delete(DATA_PTR(com_hash), &key, 0); + free(p); + } + return u; + } + + static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )( + IDispatch __RPC_FAR * This, + /* [out] */ UINT __RPC_FAR *pctinfo) + { + return E_NOTIMPL; + } + + static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )( + IDispatch __RPC_FAR * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) + { + return E_NOTIMPL; + } + + + static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )( + IDispatch __RPC_FAR * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, + /* [in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID __RPC_FAR *rgDispId) + { + Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; + char* psz = ole_wc2mb(*rgszNames); // support only one method + *rgDispId = rb_intern(psz); + free(psz); + return S_OK; + } + + static /* [local] */ HRESULT ( STDMETHODCALLTYPE Invoke )( + IDispatch __RPC_FAR * This, + /* [in] */ DISPID dispIdMember, + /* [in] */ REFIID riid, + /* [in] */ LCID lcid, + /* [in] */ WORD wFlags, + /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams, + /* [out] */ VARIANT __RPC_FAR *pVarResult, + /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, + /* [out] */ UINT __RPC_FAR *puArgErr) + { + VALUE v; + int i; + int args = pDispParams->cArgs; + Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; + VALUE* parg = ALLOCA_N(VALUE, args); + for (i = 0; i < args; i++) { + *(parg + i) = ole_variant2val(&pDispParams->rgvarg[args - i - 1]); + } + if (dispIdMember == DISPID_VALUE) { + if (wFlags == DISPATCH_METHOD) { + dispIdMember = rb_intern("call"); + } else if (wFlags & DISPATCH_PROPERTYGET) { + dispIdMember = rb_intern("value"); + } + } + v = rb_funcall2(p->obj, dispIdMember, args, parg); + ole_val2variant(v, pVarResult); + return S_OK; + } + + static IDispatch* + val2dispatch(val) + VALUE val; + { + struct st_table *tbl = DATA_PTR(com_hash); + Win32OLEIDispatch* pdisp; + st_data_t data; + + if (st_lookup(tbl, val, &data)) { + pdisp = (Win32OLEIDispatch *)(data & ~FIXNUM_FLAG); + pdisp->refcount++; + } + else { + pdisp = ALLOC(Win32OLEIDispatch); + pdisp->dispatch.lpVtbl = &com_vtbl; + pdisp->refcount = 1; + pdisp->obj = val; + st_insert(tbl, val, (VALUE)pdisp | FIXNUM_FLAG); + } + return &pdisp->dispatch; + } + static void *************** *** 700,702 **** default: ! rb_raise(rb_eTypeError, "not valid value"); break; --- 833,836 ---- default: ! V_VT(var) = VT_DISPATCH; ! V_DISPATCH(var) = val2dispatch(val); break; *************** *** 5273,5274 **** --- 5407,5418 ---- id_events = rb_intern("events"); + + com_vtbl.QueryInterface = QueryInterface; + com_vtbl.AddRef = AddRef; + com_vtbl.Release = Release; + com_vtbl.GetTypeInfoCount = GetTypeInfoCount; + com_vtbl.GetTypeInfo = GetTypeInfo; + com_vtbl.GetIDsOfNames = GetIDsOfNames; + com_vtbl.Invoke = Invoke; + com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable()); + rb_global_variable(&com_hash);