diff --git a/dlls/ole32/Makefile.in b/dlls/ole32/Makefile.in index 5bfef5a5669..011754070f4 100644 --- a/dlls/ole32/Makefile.in +++ b/dlls/ole32/Makefile.in @@ -22,6 +22,7 @@ C_SRCS = \ hglobalstream.c \ ifs.c \ itemmoniker.c \ + marshal.c \ memlockbytes.c \ moniker.c \ ole2.c \ @@ -30,6 +31,8 @@ C_SRCS = \ ole2nls.c \ ole32_main.c \ oleobj.c \ + oleproxy.c \ + rpc.c \ stg_bigblockfile.c \ stg_stream.c \ storage.c \ diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 0fecf7e6b48..3cb7905a2eb 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -5,6 +5,7 @@ * Copyright 1998 Justin Bradford * Copyright 1999 Francis Beaudet * Copyright 1999 Sylvain St-Germain + * Copyright 2002 Marcus Meissner */ #include "config.h" @@ -29,6 +30,7 @@ #include "wine/obj_misc.h" #include "wine/obj_marshal.h" #include "wine/obj_storage.h" +#include "wine/obj_channel.h" #include "wine/winbase16.h" #include "compobj_private.h" #include "ifs.h" @@ -138,6 +140,7 @@ typedef struct tagRegisteredClass DWORD runContext; DWORD connectFlags; DWORD dwCookie; + HANDLE hThread; /* only for localserver */ struct tagRegisteredClass* nextClass; } RegisteredClass; @@ -559,7 +562,7 @@ HRESULT WINAPI CLSIDFromString( * RETURNS * the string representation and HRESULT */ -static HRESULT WINE_StringFromCLSID( +HRESULT WINE_StringFromCLSID( const CLSID *id, /* [in] GUID to be converted */ LPSTR idstr /* [out] pointer to buffer to contain converted guid */ ) { @@ -1060,6 +1063,83 @@ end: return hr; } +static DWORD WINAPI +_LocalServerThread(LPVOID param) { + HANDLE hPipe; + char pipefn[200]; + RegisteredClass *newClass = (RegisteredClass*)param; + HRESULT hres; + IStream *pStm; + STATSTG ststg; + unsigned char *buffer; + int buflen; + IClassFactory *classfac; + LARGE_INTEGER seekto; + ULARGE_INTEGER newpos; + ULONG res; + + TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier)); + strcpy(pipefn,PIPEPREF); + WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF)); + + hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac); + if (hres) return hres; + + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) { + FIXME("Failed to create stream on hglobal.\n"); + return hres; + } + hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0); + if (hres) { + FIXME("CoMarshalInterface failed, %lx!\n",hres); + return hres; + } + hres = IStream_Stat(pStm,&ststg,0); + if (hres) return hres; + + buflen = ststg.cbSize.s.LowPart; + buffer = HeapAlloc(GetProcessHeap(),0,buflen); + seekto.s.LowPart = 0; + seekto.s.HighPart = 0; + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { + FIXME("IStream_Seek failed, %lx\n",hres); + return hres; + } + hres = IStream_Read(pStm,buffer,buflen,&res); + if (hres) { + FIXME("Stream Read failed, %lx\n",hres); + return hres; + } + IStream_Release(pStm); + + while (1) { + hPipe = CreateNamedPipeA( + pipefn, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE|PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + 4096, + 4096, + NMPWAIT_USE_DEFAULT_WAIT, + NULL + ); + if (hPipe == INVALID_HANDLE_VALUE) { + FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError()); + return 1; + } + if (!ConnectNamedPipe(hPipe,NULL)) { + ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError()); + CloseHandle(hPipe); + continue; + } + WriteFile(hPipe,buffer,buflen,&res,NULL); + CloseHandle(hPipe); + } + return 0; +} + /****************************************************************************** * CoRegisterClassObject [OLE32.36] * @@ -1078,24 +1158,13 @@ HRESULT WINAPI CoRegisterClassObject( RegisteredClass* newClass; LPUNKNOWN foundObject; HRESULT hr; - char buf[80]; - - WINE_StringFromCLSID(rclsid,buf); TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n", - buf,pUnk,dwClsContext,flags,lpdwRegister); + debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); - /* - * Perform a sanity check on the parameters - */ if ( (lpdwRegister==0) || (pUnk==0) ) - { return E_INVALIDARG; - } - /* - * Initialize the cookie (out parameter) - */ *lpdwRegister = 0; /* @@ -1103,35 +1172,24 @@ HRESULT WINAPI CoRegisterClassObject( * If it is, this should cause an error. */ hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject); - - if (hr == S_OK) - { - /* - * The COM_GetRegisteredClassObject increased the reference count on the - * object so it has to be released. - */ + if (hr == S_OK) { IUnknown_Release(foundObject); - return CO_E_OBJISREG; } - /* - * If it is not registered, we must create a new entry for this class and - * append it to the registered class list. - * We use the address of the chain node as the cookie since we are sure it's - * unique. - */ newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); if ( newClass == NULL ) return E_OUTOFMEMORY; EnterCriticalSection( &csRegisteredClassList ); - /* - * Initialize the node. - */ + newClass->classIdentifier = *rclsid; newClass->runContext = dwClsContext; newClass->connectFlags = flags; + /* + * Use the address of the chain node as the cookie since we are sure it's + * unique. + */ newClass->dwCookie = (DWORD)newClass; newClass->nextClass = firstRegisteredClass; @@ -1143,17 +1201,16 @@ HRESULT WINAPI CoRegisterClassObject( IUnknown_AddRef(newClass->classObject); firstRegisteredClass = newClass; - LeaveCriticalSection( &csRegisteredClassList ); - /* - * Assign the out parameter (cookie) - */ *lpdwRegister = newClass->dwCookie; - /* - * We're successful Yippee! - */ + if (dwClsContext & CLSCTX_LOCAL_SERVER) { + DWORD tid; + + STUBMGR_Start(); + newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid); + } return S_OK; } @@ -1222,6 +1279,42 @@ end: return hr; } +static HRESULT WINAPI Remote_CoGetClassObject( + REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo, + REFIID iid, LPVOID *ppv +) { + HKEY key; + char buf[200]; + HRESULT hres = E_UNEXPECTED; + char xclsid[80]; + WCHAR dllName[MAX_PATH+1]; + DWORD dllNameLen = sizeof(dllName); + STARTUPINFOW sinfo; + PROCESS_INFORMATION pinfo; + + WINE_StringFromCLSID((LPCLSID)rclsid,xclsid); + + sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid); + hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key); + + if (hres != ERROR_SUCCESS) + return REGDB_E_CLASSNOTREG; + + memset(dllName,0,sizeof(dllName)); + hres= RegQueryValueExW(key,NULL,NULL,NULL,(LPBYTE)dllName,&dllNameLen); + if (hres) + return REGDB_E_CLASSNOTREG; /* FIXME: check retval */ + RegCloseKey(key); + + TRACE("found LocalServer32 exe %s\n", debugstr_w(dllName)); + + memset(&sinfo,0,sizeof(sinfo)); + sinfo.cb = sizeof(sinfo); + if (!CreateProcessW(NULL,dllName,NULL,NULL,FALSE,0,NULL,NULL,&sinfo,&pinfo)) + return E_FAIL; + return create_marshalled_proxy(rclsid,iid,ppv); +} + /*********************************************************************** * CoGetClassObject [COMPOBJ.7] * CoGetClassObject [OLE32.16] @@ -1280,9 +1373,22 @@ HRESULT WINAPI CoGetClassObject( return hres; } - /* Then try for in-process */ - if ((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext) - { + if (((CLSCTX_LOCAL_SERVER) & dwClsContext) + && !((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext)) + return Remote_CoGetClassObject(rclsid,dwClsContext,pServerInfo,iid,ppv); + + /* remote servers not supported yet */ + if ( ((CLSCTX_REMOTE_SERVER) & dwClsContext) + && !((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext) + ){ + FIXME("CLSCTX_REMOTE_SERVER not supported!\n"); + return E_NOINTERFACE; + } + + if ((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext) { + HKEY key; + char buf[200]; + memset(ProviderName,0,sizeof(ProviderName)); sprintf(buf,"CLSID\\%s\\InprocServer32",xclsid); if (((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key)) != ERROR_SUCCESS) || @@ -1855,18 +1961,6 @@ HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN* pp return S_OK; } - -/*********************************************************************** - * DllGetClassObject [OLE32.63] - */ -HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) -{ - FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid)); - *ppv = NULL; - return CLASS_E_CLASSNOTAVAILABLE; -} - - /*** * COM_RevokeAllClasses * diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 6dce952b197..6f6d9bf58db 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -5,6 +5,86 @@ #include "wtypes.h" +extern HRESULT WINE_StringFromCLSID(const CLSID *id,LPSTR idstr); +extern HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv); + +inline static HRESULT +get_facbuf_for_iid(REFIID riid,IPSFactoryBuffer **facbuf) { + HRESULT hres; + CLSID pxclsid; + + if ((hres = CoGetPSClsid(riid,&pxclsid))) + return hres; + return CoGetClassObject(&pxclsid,CLSCTX_INPROC_SERVER,NULL,&IID_IPSFactoryBuffer,(LPVOID*)facbuf); +} + +#define PIPEPREF "\\\\.\\pipe\\" +#define OLESTUBMGR PIPEPREF"WINE_OLE_StubMgr" +/* Standard Marshaling definitions */ +typedef struct _wine_marshal_id { + DWORD processid; + DWORD objectid; /* unique value corresp. IUnknown of object */ + IID iid; +} wine_marshal_id; + +inline static BOOL +MARSHAL_Compare_Mids(wine_marshal_id *mid1,wine_marshal_id *mid2) { + return + (mid1->processid == mid2->processid) && + (mid1->objectid == mid2->objectid) && + IsEqualIID(&(mid1->iid),&(mid2->iid)) + ; +} + +/* compare without interface compare */ +inline static BOOL +MARSHAL_Compare_Mids_NoInterface(wine_marshal_id *mid1, wine_marshal_id *mid2) { + return + (mid1->processid == mid2->processid) && + (mid1->objectid == mid2->objectid) + ; +} + +HRESULT MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub); +HRESULT MARSHAL_Find_Stub_Server(wine_marshal_id *mid,LPUNKNOWN *punk); +HRESULT MARSHAL_Register_Stub(wine_marshal_id *mid,LPUNKNOWN punk, IRpcStubBuffer *stub); + +HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv); + +typedef struct _wine_marshal_data { + DWORD dwDestContext; + DWORD mshlflags; +} wine_marshal_data; + + +#define REQTYPE_REQUEST 0 +typedef struct _wine_rpc_request_header { + DWORD reqid; + wine_marshal_id mid; + DWORD iMethod; + DWORD cbBuffer; +} wine_rpc_request_header; + +#define REQTYPE_RESPONSE 1 +typedef struct _wine_rpc_response_header { + DWORD reqid; + DWORD cbBuffer; + DWORD retval; +} wine_rpc_response_header; + +#define REQSTATE_START 0 +#define REQSTATE_REQ_QUEUED 1 +#define REQSTATE_REQ_WAITING_FOR_REPLY 2 +#define REQSTATE_REQ_GOT 3 +#define REQSTATE_INVOKING 4 +#define REQSTATE_RESP_QUEUED 5 +#define REQSTATE_RESP_GOT 6 +#define REQSTATE_DONE 6 + +void STUBMGR_Start(); + +extern HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf); + /* This function initialize the Running Object Table */ HRESULT WINAPI RunningObjectTableImpl_Initialize(); diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c new file mode 100644 index 00000000000..4b8754b382d --- /dev/null +++ b/dlls/ole32/marshal.c @@ -0,0 +1,615 @@ +/* + * Marshaling library + * + * Copyright 2002 Marcus Meissner + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "objbase.h" +#include "ole2.h" +#include "ole2ver.h" +#include "rpc.h" +#include "winerror.h" +#include "winreg.h" +#include "wownt32.h" +#include "wtypes.h" +#include "wine/unicode.h" +#include "wine/obj_base.h" +#include "wine/obj_clientserver.h" +#include "wine/obj_misc.h" +#include "wine/obj_marshal.h" +#include "wine/obj_storage.h" +#include "wine/obj_channel.h" +#include "wine/winbase16.h" +#include "compobj_private.h" +#include "ifs.h" + +#include "debugtools.h" + +DEFAULT_DEBUG_CHANNEL(ole); + +/* Marshaling just passes a unique identifier to the remote client, + * that makes it possible to find the passed interface again. + * + * So basically we need a set of values that make it unique. + * + * Process Identifier, Object IUnknown ptr, IID + * + * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value! + */ + +typedef struct _mid2unknown { + wine_marshal_id mid; + LPUNKNOWN pUnk; +} mid2unknown; + +typedef struct _mid2stub { + wine_marshal_id mid; + IRpcStubBuffer *stub; + LPUNKNOWN pUnkServer; +} mid2stub; + +static mid2stub *stubs = NULL; +static int nrofstubs = 0; + +static mid2unknown *proxies = NULL; +static int nrofproxies = 0; + +HRESULT +MARSHAL_Find_Stub_Server(wine_marshal_id *mid,LPUNKNOWN *punk) { + int i; + + for (i=0;iobjectid,debugstr_guid(&(mid->iid))); + return S_OK; + } + if (nrofstubs) + stubs=HeapReAlloc(GetProcessHeap(),0,stubs,sizeof(stubs[0])*(nrofstubs+1)); + else + stubs=HeapAlloc(GetProcessHeap(),0,sizeof(stubs[0])); + if (!stubs) return E_OUTOFMEMORY; + stubs[nrofstubs].stub = stub; + stubs[nrofstubs].pUnkServer = pUnk; + memcpy(&(stubs[nrofstubs].mid),mid,sizeof(*mid)); + nrofstubs++; + return S_OK; +} + +HRESULT +MARSHAL_Find_Proxy(wine_marshal_id *mid,LPUNKNOWN *punk) { + int i; + + for (i=0;iref++; + return This->ref; +} + +ULONG WINAPI +StdMarshalImpl_Release(LPMARSHAL iface) { + ICOM_THIS(StdMarshalImpl,iface); + This->ref--; + + if (This->ref) + return This->ref; + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +HRESULT WINAPI +StdMarshalImpl_GetUnmarshalClass( + LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags, CLSID* pCid +) { + memcpy(pCid,&CLSID_DfMarshal,sizeof(CLSID_DfMarshal)); + return S_OK; +} + +HRESULT WINAPI +StdMarshalImpl_GetMarshalSizeMax( + LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags, DWORD* pSize +) { + *pSize = sizeof(wine_marshal_id)+sizeof(wine_marshal_data); + return S_OK; +} + +HRESULT WINAPI +StdMarshalImpl_MarshalInterface( + LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags +) { + wine_marshal_id mid; + wine_marshal_data md; + IUnknown *pUnk; + ULONG res; + HRESULT hres; + IRpcStubBuffer *stub; + IPSFactoryBuffer *psfacbuf; + + TRACE("(...,%s,...)\n",debugstr_guid(riid)); + IUnknown_QueryInterface((LPUNKNOWN)pv,&IID_IUnknown,(LPVOID*)&pUnk); + mid.processid = GetCurrentProcessId(); + mid.objectid = (DWORD)pUnk; /* FIXME */ + IUnknown_Release(pUnk); + memcpy(&mid.iid,riid,sizeof(mid.iid)); + md.dwDestContext = dwDestContext; + md.mshlflags = mshlflags; + hres = IStream_Write(pStm,&mid,sizeof(mid),&res); + if (hres) return hres; + hres = IStream_Write(pStm,&md,sizeof(md),&res); + if (hres) return hres; + + if (SUCCEEDED(MARSHAL_Find_Stub(&mid,&pUnk))) { + IUnknown_Release(pUnk); + return S_OK; + } + hres = get_facbuf_for_iid(riid,&psfacbuf); + if (hres) return hres; + hres = IPSFactoryBuffer_CreateStub(psfacbuf,riid,pv,&stub); + IPSFactoryBuffer_Release(psfacbuf); + if (hres) { + FIXME("Failed to create a stub for %s\n",debugstr_guid(riid)); + return hres; + } + IUnknown_QueryInterface((LPUNKNOWN)pv,riid,(LPVOID*)&pUnk); + MARSHAL_Register_Stub(&mid,pUnk,stub); + IUnknown_Release(pUnk); + return S_OK; +} + +HRESULT WINAPI +StdMarshalImpl_UnmarshalInterface( + LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv +) { + wine_marshal_id mid; + wine_marshal_data md; + ULONG res; + HRESULT hres; + IPSFactoryBuffer *psfacbuf; + IRpcProxyBuffer *rpcproxy; + IRpcChannelBuffer *chanbuf; + + TRACE("(...,%s,....)\n",debugstr_guid(riid)); + hres = IStream_Read(pStm,&mid,sizeof(mid),&res); + if (hres) return hres; + hres = IStream_Read(pStm,&md,sizeof(md),&res); + if (hres) return hres; + if (SUCCEEDED(MARSHAL_Find_Stub(&mid,(LPUNKNOWN*)ppv))) { + FIXME("Calling back to ourselves for %s!\n",debugstr_guid(riid)); + return S_OK; + } + hres = get_facbuf_for_iid(riid,&psfacbuf); + if (hres) return hres; + hres = IPSFactoryBuffer_CreateProxy(psfacbuf,NULL,riid,&rpcproxy,ppv); + if (hres) { + FIXME("Failed to create a proxy for %s\n",debugstr_guid(riid)); + return hres; + } + hres = PIPE_GetNewPipeBuf(&mid,&chanbuf); + if (hres) + FIXME("Failed to get an rpc channel buffer for %s\n",debugstr_guid(riid)); + IRpcProxyBuffer_Connect(rpcproxy,chanbuf); + IRpcProxyBuffer_Release(rpcproxy); /* no need */ + IPSFactoryBuffer_Release(psfacbuf); + return S_OK; +} + +HRESULT WINAPI +StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) { + FIXME("(), stub!\n"); + return S_OK; +} + +HRESULT WINAPI +StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) { + FIXME("(), stub!\n"); + return S_OK; +} + +ICOM_VTABLE(IMarshal) stdmvtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + StdMarshalImpl_QueryInterface, + StdMarshalImpl_AddRef, + StdMarshalImpl_Release, + StdMarshalImpl_GetUnmarshalClass, + StdMarshalImpl_GetMarshalSizeMax, + StdMarshalImpl_MarshalInterface, + StdMarshalImpl_UnmarshalInterface, + StdMarshalImpl_ReleaseMarshalData, + StdMarshalImpl_DisconnectObject +}; + +/*********************************************************************** + * CoGetStandardMarshal [OLE32.23] + * + * When the COM library in the client process receives a marshaled + * interface pointer, it looks for a CLSID to be used in creating a proxy + * for the purposes of unmarshaling the packet. If the packet does not + * contain a CLSID for the proxy, COM calls CoGetStandardMarshal, passing a + * NULL pUnk value. + * This function creates a standard proxy in the client process and returns + * a pointer to that proxy's implementation of IMarshal. + * COM uses this pointer to call CoUnmarshalInterface to retrieve the pointer + * to the requested interface. + */ +HRESULT WINAPI +CoGetStandardMarshal( + REFIID riid,IUnknown *pUnk,DWORD dwDestContext,LPVOID pvDestContext, + DWORD mshlflags, LPMARSHAL *pMarshal +) { + StdMarshalImpl *dm; + + if (pUnk == NULL) { + FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n", + debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,pMarshal + ); + return E_FAIL; + } + TRACE("(%s,%p,%lx,%p,%lx,%p)\n", + debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,pMarshal + ); + dm = (StdMarshalImpl*) *pMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); + if (!dm) return E_FAIL; + dm->lpvtbl = &stdmvtbl; + dm->ref = 1; + + memcpy(&dm->iid,riid,sizeof(dm->iid)); + dm->dwDestContext = dwDestContext; + dm->pvDestContext = pvDestContext; + dm->mshlflags = mshlflags; + return S_OK; +} + +/* Helper function for getting Marshaler */ +static HRESULT WINAPI +_GetMarshaller(REFIID riid, IUnknown *pUnk,DWORD dwDestContext, + void *pvDestContext, DWORD mshlFlags, LPMARSHAL *pMarshal +) { + HRESULT hres; + + if (!pUnk) + return E_POINTER; + hres = IUnknown_QueryInterface(pUnk,&IID_IMarshal,(LPVOID*)pMarshal); + if (hres) + hres = CoGetStandardMarshal(riid,pUnk,dwDestContext,pvDestContext,mshlFlags,pMarshal); + return hres; +} + +/*********************************************************************** + * CoGetMarshalSizeMax [OLE32.21] + */ +HRESULT WINAPI +CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk, + DWORD dwDestContext, void *pvDestContext, DWORD mshlFlags +) { + HRESULT hres; + LPMARSHAL pMarshal; + + hres = _GetMarshaller(riid,pUnk,dwDestContext,pvDestContext,mshlFlags,&pMarshal); + if (hres) + return hres; + hres = IMarshal_GetMarshalSizeMax(pMarshal,riid,pUnk,dwDestContext,pvDestContext,mshlFlags,pulSize); + *pulSize += sizeof(wine_marshal_id)+sizeof(wine_marshal_data)+sizeof(CLSID); + IMarshal_Release(pMarshal); + return hres; +} + + +/*********************************************************************** + * CoMarshalInterface [OLE32.34] + */ +HRESULT WINAPI +CoMarshalInterface( IStream *pStm, REFIID riid, IUnknown *pUnk, + DWORD dwDestContext, void *pvDestContext, DWORD mshlflags +) { + HRESULT hres; + LPMARSHAL pMarshal; + CLSID xclsid; + ULONG writeres; + wine_marshal_id mid; + wine_marshal_data md; + ULONG res; + IUnknown *pUnknown; + + TRACE("(%p, %s, %p, %lx, %p, %lx)\n", + pStm,debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags + ); + STUBMGR_Start(); /* Just to be sure we have one running. */ + mid.processid = GetCurrentProcessId(); + IUnknown_QueryInterface(pUnk,&IID_IUnknown,(LPVOID*)&pUnknown); + mid.objectid = (DWORD)pUnknown; + IUnknown_Release(pUnknown); + memcpy(&mid.iid,riid,sizeof(mid.iid)); + md.dwDestContext = dwDestContext; + md.mshlflags = mshlflags; + hres = IStream_Write(pStm,&mid,sizeof(mid),&res); + if (hres) return hres; + hres = IStream_Write(pStm,&md,sizeof(md),&res); + if (hres) return hres; + hres = _GetMarshaller(riid,pUnk,dwDestContext,pvDestContext,mshlflags,&pMarshal); + if (hres) { + FIXME("Failed to get marshaller, %lx?\n",hres); + return hres; + } + hres = IMarshal_GetUnmarshalClass(pMarshal,riid,pUnk,dwDestContext,pvDestContext,mshlflags,&xclsid); + if (hres) { + FIXME("IMarshal:GetUnmarshalClass failed, %lx\n",hres); + goto release_marshal; + } + hres = IStream_Write(pStm,&xclsid,sizeof(xclsid),&writeres); + if (hres) { + FIXME("Stream write failed, %lx\n",hres); + goto release_marshal; + } + hres = IMarshal_MarshalInterface(pMarshal,pStm,riid,pUnk,dwDestContext,pvDestContext,mshlflags); + if (hres) { + FIXME("Failed to Marshal the interface, %lx?\n",hres); + goto release_marshal; + } +release_marshal: + IMarshal_Release(pMarshal); + return hres; +} + + +/*********************************************************************** + * CoUnmarshalInterface [OLE32.50] + */ +HRESULT WINAPI +CoUnmarshalInterface(IStream *pStm, REFIID riid, LPVOID *ppv) { + HRESULT hres; + wine_marshal_id mid; + wine_marshal_data md; + ULONG res; + LPMARSHAL pMarshal; + LPUNKNOWN pUnk; + CLSID xclsid; + + TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(riid),ppv); + + hres = IStream_Read(pStm,&mid,sizeof(mid),&res); + if (hres) { + FIXME("Stream read 1 failed, %lx, (%ld of %d)\n",hres,res,sizeof(mid)); + return hres; + } + hres = IStream_Read(pStm,&md,sizeof(md),&res); + if (hres) { + FIXME("Stream read 2 failed, %lx, (%ld of %d)\n",hres,res,sizeof(md)); + return hres; + } + hres = IStream_Read(pStm,&xclsid,sizeof(xclsid),&res); + if (hres) { + FIXME("Stream read 3 failed, %lx, (%ld of %d)\n",hres,res,sizeof(xclsid)); + return hres; + } + hres=CoCreateInstance(&xclsid,NULL,CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER,&IID_IMarshal,(void**)&pUnk); + if (hres) { + FIXME("Failed to create instance of unmarshaller %s.\n",debugstr_guid(&xclsid)); + return hres; + } + hres = _GetMarshaller(riid,pUnk,md.dwDestContext,NULL,md.mshlflags,&pMarshal); + if (hres) { + FIXME("Failed to get unmarshaller, %lx?\n",hres); + return hres; + } + hres = IMarshal_UnmarshalInterface(pMarshal,pStm,riid,ppv); + if (hres) { + FIXME("Failed to Unmarshal the interface, %lx?\n",hres); + goto release_marshal; + } +release_marshal: + IMarshal_Release(pMarshal); + return hres; +} + +/*********************************************************************** + * CoMarshalInterThreadInterfaceInStream [OLE32.33] + * + * Marshal interfaces across threads. We don't have a thread distinction, + * meaning most interfaces just work across different threads, the RPC + * handles it. + */ +HRESULT WINAPI +CoMarshalInterThreadInterfaceInStream( + REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm +) { + ULONG res; + ULARGE_INTEGER xpos; + LARGE_INTEGER seekto; + HRESULT hres; + + TRACE("(,%s,)\n",debugstr_guid(riid)); + hres = CreateStreamOnHGlobal(0, TRUE, ppStm); + if (hres) return hres; + /* CoMarshalInterface(...); */ + hres = IStream_Write(*ppStm,&pUnk,sizeof(LPUNKNOWN),&res); + if (hres) return hres; + memset(&seekto,0,sizeof(seekto)); + IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos); + return S_OK; +} + +/*********************************************************************** + * CoGetInterfaceAndReleaseStream [OLE32.19] + */ +HRESULT WINAPI +CoGetInterfaceAndReleaseStream(LPSTREAM pStm,REFIID riid, LPVOID *ppv) { + ULONG res; + HRESULT hres; + LPUNKNOWN pUnk; + + TRACE("(,%s,)\n",debugstr_guid(riid)); + /* CoUnmarshalInterface(...); */ + hres = IStream_Read(pStm,&pUnk,sizeof(LPUNKNOWN),&res); + if (hres) return hres; + IStream_Release(pStm); + return IUnknown_QueryInterface(pUnk,riid,ppv); +} + +static WINAPI HRESULT +SMCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { + *ppv = NULL; + if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IClassFactory)) { + *ppv = (LPVOID)iface; + return S_OK; + } + return E_NOINTERFACE; +} +static WINAPI ULONG SMCF_AddRef(LPCLASSFACTORY iface) { return 2; } +static WINAPI ULONG SMCF_Release(LPCLASSFACTORY iface) { return 1; } + +static WINAPI HRESULT +SMCF_CreateInstance( + LPCLASSFACTORY iface, LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv +) { + if (IsEqualIID(riid,&IID_IMarshal)) { + StdMarshalImpl *dm; + dm=(StdMarshalImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); + if (!dm) + return E_FAIL; + dm->lpvtbl = &stdmvtbl; + dm->ref = 1; + *ppv = (LPVOID)dm; + return S_OK; + } + FIXME("(%s), not supported.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static WINAPI HRESULT +SMCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) { + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static ICOM_VTABLE(IClassFactory) dfmarshalcfvtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + SMCF_QueryInterface, + SMCF_AddRef, + SMCF_Release, + SMCF_CreateInstance, + SMCF_LockServer +}; +static ICOM_VTABLE(IClassFactory) *pdfmarshalcfvtbl = &dfmarshalcfvtbl; + +HRESULT +MARSHAL_GetStandardMarshalCF(LPVOID *ppv) { + *ppv = &pdfmarshalcfvtbl; + return S_OK; +} diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index 7b187a1732e..fcdfb66f9d9 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -30,7 +30,7 @@ debug_channels (accel ole relay storage) 16 stdcall CoGetClassObject(ptr long ptr ptr ptr) CoGetClassObject 17 stub CoGetCurrentLogicalThreadId 18 stdcall CoGetCurrentProcess() CoGetCurrentProcess - 19 stub CoGetInterfaceAndReleaseStream # stdcall (ptr ptr ptr) return 0,ERR_NOTIMPLEMENTED + 19 stdcall CoGetInterfaceAndReleaseStream(ptr ptr ptr) CoGetInterfaceAndReleaseStream 20 stdcall CoGetMalloc(long ptr) CoGetMalloc 21 stub CoGetMarshalSizeMax # stdcall (ptr ptr ptr long ptr long) return 0,ERR_NOTIMPLEMENTED 22 stdcall CoGetPSClsid(ptr ptr) CoGetPSClsid @@ -44,8 +44,8 @@ debug_channels (accel ole relay storage) 30 stdcall CoLoadLibrary(wstr long) CoLoadLibrary 31 stdcall CoLockObjectExternal(ptr long long) CoLockObjectExternal 32 stub CoMarshalHresult # stdcall (ptr ptr) return 0,ERR_NOTIMPLEMENTED - 33 stub CoMarshalInterThreadInterfaceInStream # stdcall (ptr ptr ptr) return 0,ERR_NOTIMPLEMENTED - 34 stub CoMarshalInterface # stdcall (ptr ptr ptr long ptr long) return 0,ERR_NOTIMPLEMENTED + 33 stdcall CoMarshalInterThreadInterfaceInStream(ptr ptr ptr) CoMarshalInterThreadInterfaceInStream + 34 stdcall CoMarshalInterface(ptr ptr ptr long ptr long) CoMarshalInterface 35 stub CoQueryReleaseObject 36 stdcall CoRegisterClassObject(ptr ptr long long ptr) CoRegisterClassObject 37 stub CoRegisterMallocSpy # stdcall (ptr) return 0,ERR_NOTIMPLEMENTED @@ -61,7 +61,7 @@ debug_channels (accel ole relay storage) 47 stdcall CoUninitialize() CoUninitialize 48 stub CoUnloadingWOW 49 stub CoUnmarshalHresult # stdcall (ptr ptr) return 0,ERR_NOTIMPLEMENTED - 50 stub CoUnmarshalInterface # stdcall (ptr ptr ptr) return 0,ERR_NOTIMPLEMENTED + 50 stdcall CoUnmarshalInterface(ptr ptr ptr) CoUnmarshalInterface 51 stdcall CreateAntiMoniker(ptr) CreateAntiMoniker 52 stdcall CreateBindCtx(long ptr) CreateBindCtx 53 stdcall CreateDataAdviseHolder(ptr) CreateDataAdviseHolder diff --git a/dlls/ole32/oleproxy.c b/dlls/ole32/oleproxy.c new file mode 100644 index 00000000000..f10838bacc3 --- /dev/null +++ b/dlls/ole32/oleproxy.c @@ -0,0 +1,496 @@ +/* + * OLE32 proxy/stub handler + * + * Copyright 2002 Marcus Meissner + */ + +/* Documentation on MSDN: + * + * (COM Proxy) + * http://msdn.microsoft.com/library/en-us/com/comext_1q0p.asp + * + * (COM Stub) + * http://msdn.microsoft.com/library/en-us/com/comext_1lia.asp + * + * (Marshal) + * http://msdn.microsoft.com/library/en-us/com/comext_1gfn.asp + * + */ + +#include "config.h" + +#include +#include +#include + +#include "windef.h" +#include "objbase.h" +#include "ole2.h" +#include "rpc.h" +#include "winerror.h" +#include "winreg.h" +#include "wtypes.h" +#include "wine/obj_base.h" +#include "wine/obj_marshal.h" +#include "wine/obj_channel.h" + +#include "compobj_private.h" + +#include "debugtools.h" + +DEFAULT_DEBUG_CHANNEL(ole); + +/* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp + * + * The first time a client requests a pointer to an interface on a + * particular object, COM loads an IClassFactory stub in the server + * process and uses it to marshal the first pointer back to the + * client. In the client process, COM loads the generic proxy for the + * class factory object and calls its implementation of IMarshal to + * unmarshal that first pointer. COM then creates the first interface + * proxy and hands it a pointer to the RPC channel. Finally, COM returns + * the IClassFactory pointer to the client, which uses it to call + * IClassFactory::CreateInstance, passing it a reference to the interface. + * + * Back in the server process, COM now creates a new instance of the + * object, along with a stub for the requested interface. This stub marshals + * the interface pointer back to the client process, where another object + * proxy is created, this time for the object itself. Also created is a + * proxy for the requested interface, a pointer to which is returned to + * the client. With subsequent calls to other interfaces on the object, + * COM will load the appropriate interface stubs and proxies as needed. + */ +typedef struct _CFStub { + ICOM_VTABLE(IRpcStubBuffer) *lpvtbl; + DWORD ref; + + LPUNKNOWN pUnkServer; +} CFStub; + +static HRESULT WINAPI +CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) { + if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) { + *ppv = (LPVOID)iface; + IUnknown_AddRef(iface); + return S_OK; + } + FIXME("(%s), interface not supported.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI +CFStub_AddRef(LPRPCSTUBBUFFER iface) { + ICOM_THIS(CFStub,iface); + + This->ref++; + return This->ref; +} + +static ULONG WINAPI +CFStub_Release(LPRPCSTUBBUFFER iface) { + ICOM_THIS(CFStub,iface); + + This->ref--; + if (This->ref) + return This->ref; + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +static HRESULT WINAPI +CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) { + ICOM_THIS(CFStub,iface); + + This->pUnkServer = pUnkServer; + IUnknown_AddRef(pUnkServer); + return S_OK; +} + +static void WINAPI +CFStub_Disconnect(LPRPCSTUBBUFFER iface) { + ICOM_THIS(CFStub,iface); + + IUnknown_Release(This->pUnkServer); + This->pUnkServer = NULL; +} +static HRESULT WINAPI +CFStub_Invoke( + LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf +) { + ICOM_THIS(CFStub,iface); + HRESULT hres; + + if (msg->iMethod == 3) { /* CreateInstance */ + IID iid; + IClassFactory *classfac; + IUnknown *ppv; + IStream *pStm; + STATSTG ststg; + ULARGE_INTEGER newpos; + LARGE_INTEGER seekto; + ULONG res; + + if (msg->cbBuffer < sizeof(IID)) { + FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID)); + return E_FAIL; + } + memcpy(&iid,msg->Buffer,sizeof(iid)); + TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid)); + hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac); + if (hres) { + FIXME("Ole server does not provide a IClassFactory?\n"); + return hres; + } + hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv); + IClassFactory_Release(classfac); + if (hres) { + msg->cbBuffer = 0; + FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid)); + return hres; + } + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) { + FIXME("Failed to create stream on hglobal\n"); + return hres; + } + hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0); + if (hres) { + FIXME("CoMarshalInterface failed, %lx!\n",hres); + msg->cbBuffer = 0; + return hres; + } + hres = IStream_Stat(pStm,&ststg,0); + if (hres) { + FIXME("Stat failed.\n"); + return hres; + } + + msg->cbBuffer = ststg.cbSize.s.LowPart; + msg->Buffer = HeapReAlloc(GetProcessHeap(),0,msg->Buffer,ststg.cbSize.s.LowPart); + seekto.s.LowPart = 0;seekto.s.HighPart = 0; + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { + FIXME("IStream_Seek failed, %lx\n",hres); + return hres; + } + hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res); + if (hres) { + FIXME("Stream Read failed, %lx\n",hres); + return hres; + } + IStream_Release(pStm); + return S_OK; + } + FIXME("(%p,%p), stub!\n",msg,chanbuf); + FIXME("iMethod is %ld\n",msg->iMethod); + FIXME("cbBuffer is %ld\n",msg->cbBuffer); + return E_FAIL; +} + +static LPRPCSTUBBUFFER WINAPI +CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) { + FIXME("(%s), stub!\n",debugstr_guid(riid)); + return NULL; +} + +static ULONG WINAPI +CFStub_CountRefs(LPRPCSTUBBUFFER iface) { + FIXME("(), stub!\n"); + return 1; +} + +static HRESULT WINAPI +CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) { + FIXME("(%p), stub!\n",ppv); + return E_FAIL; +} +static void WINAPI +CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) { + FIXME("(%p), stub!\n",pv); +} + +static ICOM_VTABLE(IRpcStubBuffer) cfstubvt = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + CFStub_QueryInterface, + CFStub_AddRef, + CFStub_Release, + CFStub_Connect, + CFStub_Disconnect, + CFStub_Invoke, + CFStub_IsIIDSupported, + CFStub_CountRefs, + CFStub_DebugServerQueryInterface, + CFStub_DebugServerRelease +}; + +static HRESULT +CFStub_Construct(LPRPCSTUBBUFFER *ppv) { + CFStub *cfstub; + cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub)); + if (!cfstub) + return E_OUTOFMEMORY; + *ppv = (LPRPCSTUBBUFFER)cfstub; + cfstub->lpvtbl = &cfstubvt; + cfstub->ref = 1; + return S_OK; +} + +/* Since we create proxy buffers and classfactory in a pair, there is + * no need for 2 seperate structs. Just put them in one, but remember + * the refcount. + */ +typedef struct _CFProxy { + ICOM_VTABLE(IClassFactory) *lpvtbl_cf; + ICOM_VTABLE(IRpcProxyBuffer) *lpvtbl_proxy; + DWORD ref; + + IRpcChannelBuffer *chanbuf; +} CFProxy; + +static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) { + *ppv = NULL; + if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) { + IRpcProxyBuffer_AddRef(iface); + *ppv = (LPVOID)iface; + return S_OK; + } + FIXME("(%s), no interface.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + return ++(This->ref); +} + +static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + + if (!--(This->ref)) { + IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL; + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return This->ref; +} + +static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + + This->chanbuf = pRpcChannelBuffer; + IRpcChannelBuffer_AddRef(This->chanbuf); + return S_OK; +} +static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + if (This->chanbuf) { + IRpcChannelBuffer_Release(This->chanbuf); + This->chanbuf = NULL; + } +} + +static HRESULT WINAPI +CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { + *ppv = NULL; + if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) { + *ppv = (LPVOID)iface; + IClassFactory_AddRef(iface); + return S_OK; + } + if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debugoutput */ + return E_NOINTERFACE; + FIXME("Unhandled interface: %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + This->ref++; + return This->ref; +} + +static ULONG WINAPI CFProxy_Release(LPCLASSFACTORY iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + This->ref--; + if (This->ref) + return This->ref; + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +static HRESULT WINAPI CFProxy_CreateInstance( + LPCLASSFACTORY iface, + LPUNKNOWN pUnkOuter,/* [in] */ + REFIID riid, /* [in] */ + LPVOID *ppv /* [out] */ +) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + HRESULT hres; + LPSTREAM pStream; + HGLOBAL hGlobal; + ULONG srstatus; + RPCOLEMESSAGE msg; + + TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv); + + /* Send CreateInstance to the remote classfactory. + * + * Data: Only the 'IID'. + */ + msg.iMethod = 3; + msg.cbBuffer = sizeof(*riid); + msg.Buffer = NULL; + hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory); + if (hres) { + FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres); + return hres; + } + memcpy(msg.Buffer,riid,sizeof(*riid)); + hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus); + if (hres) { + FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres); + return hres; + } + + if (!msg.cbBuffer) /* interface not found on remote */ + return srstatus; + + /* We got back: [Marshaled Interface data] */ + TRACE("got %ld bytes data.\n",msg.cbBuffer); + hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer); + memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer); + hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream); + if (hres) { + FIXME("CreateStreamOnHGlobal failed with %lx\n",hres); + return hres; + } + hres = CoUnmarshalInterface( + pStream, + riid, + ppv + ); + IStream_Release(pStream); /* Does GlobalFree hGlobal too. */ + if (hres) { + FIXME("CoMarshalInterface failed, %lx\n",hres); + return hres; + } + return S_OK; +} + +static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) { + /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/ + FIXME("(%d), stub!\n",fLock); + /* basically: write BOOL, read empty */ + return S_OK; +} + +static ICOM_VTABLE(IRpcProxyBuffer) pspbvtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + IRpcProxyBufferImpl_QueryInterface, + IRpcProxyBufferImpl_AddRef, + IRpcProxyBufferImpl_Release, + IRpcProxyBufferImpl_Connect, + IRpcProxyBufferImpl_Disconnect +}; +static ICOM_VTABLE(IClassFactory) cfproxyvt = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + CFProxy_QueryInterface, + CFProxy_AddRef, + CFProxy_Release, + CFProxy_CreateInstance, + CFProxy_LockServer +}; + +static HRESULT +CFProxy_Construct(LPVOID *ppv,LPVOID *ppProxy) { + CFProxy *cf; + + cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy)); + if (!cf) + return E_OUTOFMEMORY; + + cf->lpvtbl_cf = &cfproxyvt; + cf->lpvtbl_proxy = &pspbvtbl; + cf->ref = 2; /* we return 2 references to the object! */ + *ppv = &(cf->lpvtbl_cf); + *ppProxy = &(cf->lpvtbl_proxy); + return S_OK; +} + + +/********************* OLE Proxy/Stub Factory ********************************/ +static HRESULT WINAPI +PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) { + if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) { + *ppv = (LPVOID)iface; + /* No ref counting, static class */ + return S_OK; + } + FIXME("(%s) unknown IID?\n",debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; } +static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; } + +static HRESULT WINAPI +PSFacBuf_CreateProxy( + LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, + IRpcProxyBuffer **ppProxy, LPVOID *ppv +) { + if (IsEqualIID(&IID_IClassFactory,riid)) + return CFProxy_Construct(ppv,(LPVOID*)ppProxy); + FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid)); + return E_FAIL; +} + +static HRESULT WINAPI +PSFacBuf_CreateStub( + LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer, + IRpcStubBuffer** ppStub +) { + HRESULT hres; + + TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub); + + if (IsEqualIID(&IID_IClassFactory,riid)) { + hres = CFStub_Construct(ppStub); + if (!hres) + IRpcStubBuffer_Connect((*ppStub),pUnkServer); + return hres; + } + FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid)); + return E_FAIL; +} + +static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + PSFacBuf_QueryInterface, + PSFacBuf_AddRef, + PSFacBuf_Release, + PSFacBuf_CreateProxy, + PSFacBuf_CreateStub +}; + +/* This is the whole PSFactoryBuffer object, just the vtableptr */ +static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl; + +/*********************************************************************** + * DllGetClassObject [OLE32.63] + */ +HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(rclsid,&CLSID_PSFactoryBuffer)) { + *ppv = &lppsfac; + /* If we create a ps factory, we might need a stub manager later + * anyway + */ + STUBMGR_Start(); + return S_OK; + } + if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&IsEqualIID(iid,&IID_IClassFactory)) + return MARSHAL_GetStandardMarshalCF(ppv); + FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid)); + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c new file mode 100644 index 00000000000..34a6aa14d60 --- /dev/null +++ b/dlls/ole32/rpc.c @@ -0,0 +1,693 @@ +/* + * (Local) RPC Stuff + * + * Copyright 2002 Marcus Meissner + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "objbase.h" +#include "ole2.h" +#include "ole2ver.h" +#include "rpc.h" +#include "winerror.h" +#include "winreg.h" +#include "wownt32.h" +#include "wtypes.h" +#include "wine/unicode.h" +#include "wine/obj_base.h" +#include "wine/obj_clientserver.h" +#include "wine/obj_misc.h" +#include "wine/obj_marshal.h" +#include "wine/obj_storage.h" +#include "wine/obj_channel.h" +#include "wine/winbase16.h" +#include "compobj_private.h" +#include "ifs.h" + +#include "compobj_private.h" + +#include "debugtools.h" + +DEFAULT_DEBUG_CHANNEL(ole); + +typedef struct _wine_rpc_request { + int state; + HANDLE hPipe; /* temp copy of handle */ + wine_rpc_request_header reqh; + wine_rpc_response_header resph; + LPBYTE Buffer; +} wine_rpc_request; + +static wine_rpc_request **reqs = NULL; +static int nrofreqs = 0; + +/* This pipe is _thread_ based */ +typedef struct _wine_pipe { + wine_marshal_id mid; /* target mid */ + DWORD tid; /* thread in which we execute */ + HANDLE hPipe; + + int pending; + HANDLE hThread; + CRITICAL_SECTION crit; +} wine_pipe; + +static wine_pipe *pipes = NULL; +static int nrofpipes = 0; + +typedef struct _PipeBuf { + ICOM_VTABLE(IRpcChannelBuffer) *lpVtbl; + DWORD ref; + + wine_marshal_id mid; + wine_pipe *pipe; +} PipeBuf; + +static int nrofreaders = 0; + +static HRESULT WINAPI +_xread(HANDLE hf, LPVOID ptr, DWORD size) { + DWORD res; + if (!ReadFile(hf,ptr,size,&res,NULL)) { + FIXME("Failed to read from %x, le is %lx\n",hf,GetLastError()); + return E_FAIL; + } + if (res!=size) { + FIXME("Read only %ld of %ld bytes.\n",res,size); + return E_FAIL; + } + return S_OK; +} + +static void +drs(LPCSTR where) { + int i, states[10]; + + return ; + + memset(states,0,sizeof(states)); + for (i=nrofreqs;i--;) + states[reqs[i]->state]++; + FIXME("%lx/%s/%d: rq %d, w %d, rg %d, rsq %d, rsg %d, d %d\n", + GetCurrentProcessId(), + where, + nrofreaders, + states[REQSTATE_REQ_QUEUED], + states[REQSTATE_REQ_WAITING_FOR_REPLY], + states[REQSTATE_REQ_GOT], + states[REQSTATE_RESP_QUEUED], + states[REQSTATE_RESP_GOT], + states[REQSTATE_DONE] + ); +} + +static HRESULT WINAPI +_xwrite(HANDLE hf, LPVOID ptr, DWORD size) { + DWORD res; + if (!WriteFile(hf,ptr,size,&res,NULL)) { + FIXME("Failed to write to %x, le is %lx\n",hf,GetLastError()); + return E_FAIL; + } + if (res!=size) { + FIXME("Wrote only %ld of %ld bytes.\n",res,size); + return E_FAIL; + } + return S_OK; +} + +static DWORD WINAPI _StubReaderThread(LPVOID); + +static HRESULT +PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader) { + int i; + char pipefn[100]; + + for (i=0;iprocessid) + return S_OK; + if (pipes) + pipes=(wine_pipe*)HeapReAlloc(GetProcessHeap(),0,pipes,sizeof(pipes[0])*(nrofpipes+1)); + else + pipes=(wine_pipe*)HeapAlloc(GetProcessHeap(),0,sizeof(pipes[0])); + if (!pipes) return E_OUTOFMEMORY; + sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid); + memcpy(&(pipes[nrofpipes].mid),mid,sizeof(*mid)); + pipes[nrofpipes].hPipe = hPipe; + InitializeCriticalSection(&(pipes[nrofpipes].crit)); + nrofpipes++; + if (startreader) { + pipes[nrofpipes-1].hThread = CreateThread(NULL,0,_StubReaderThread,(LPVOID)pipes+(nrofpipes-1),0,&(pipes[nrofpipes-1].tid)); + } else { + pipes[nrofpipes-1].tid = GetCurrentThreadId(); + } + return S_OK; +} + +static HANDLE +PIPE_FindByMID(wine_marshal_id *mid) { + int i; + for (i=0;iprocessid) && + (GetCurrentThreadId()==pipes[i].tid) + ) + return pipes[i].hPipe; + return INVALID_HANDLE_VALUE; +} + +static wine_pipe* +PIPE_GetFromMID(wine_marshal_id *mid) { + int i; + for (i=0;iprocessid) && + (GetCurrentThreadId()==pipes[i].tid) + ) + return pipes+i; + } + return NULL; +} + +static HRESULT +RPC_GetRequest(wine_rpc_request **req) { + static int reqid = 0xdeadbeef; + int i; + + for (i=0;istate == REQSTATE_DONE) { + reqs[i]->reqh.reqid = reqid++; + reqs[i]->resph.reqid = reqs[i]->reqh.reqid; + reqs[i]->hPipe = INVALID_HANDLE_VALUE; + *req = reqs[i]; + reqs[i]->state = REQSTATE_START; + return S_OK; + } + } + /* create new */ + if (reqs) + reqs = (wine_rpc_request**)HeapReAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + reqs, + sizeof(wine_rpc_request*)*(nrofreqs+1) + ); + else + reqs = (wine_rpc_request**)HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(wine_rpc_request*) + ); + if (!reqs) + return E_OUTOFMEMORY; + reqs[nrofreqs] = (wine_rpc_request*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(wine_rpc_request)); + reqs[nrofreqs]->reqh.reqid = reqid++; + reqs[nrofreqs]->resph.reqid = reqs[nrofreqs]->reqh.reqid; + reqs[nrofreqs]->hPipe = INVALID_HANDLE_VALUE; + *req = reqs[nrofreqs]; + reqs[nrofreqs]->state = REQSTATE_START; + nrofreqs++; + return S_OK; +} + +static void +RPC_FreeRequest(wine_rpc_request *req) { + req->state = REQSTATE_DONE; /* Just reuse slot. */ + return; +} + +static HRESULT WINAPI +PipeBuf_QueryInterface( + LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv +) { + *ppv = NULL; + if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) { + *ppv = (LPVOID)iface; + IUnknown_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI +PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) { + ICOM_THIS(PipeBuf,iface); + This->ref++; + return This->ref; +} + +static ULONG WINAPI +PipeBuf_Release(LPRPCCHANNELBUFFER iface) { + ICOM_THIS(PipeBuf,iface); + This->ref--; + if (This->ref) + return This->ref; + ERR("Free all stuff.\n"); + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +static HRESULT WINAPI +PipeBuf_GetBuffer( + LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid +) { + /*ICOM_THIS(PipeBuf,iface);*/ + + TRACE("(%p,%s), slightly wrong.\n",msg,debugstr_guid(riid)); + /* probably reuses IID in real. */ + if (msg->cbBuffer && (msg->Buffer == NULL)) + msg->Buffer = HeapAlloc(GetProcessHeap(),0,msg->cbBuffer); + return S_OK; +} + +static HRESULT +_invoke_onereq(wine_rpc_request *req) { + IRpcStubBuffer *stub; + RPCOLEMESSAGE msg; + HRESULT hres; + DWORD reqtype; + + hres = MARSHAL_Find_Stub_Buffer(&(req->reqh.mid),&stub); + if (hres) { + ERR("Stub not found?\n"); + return hres; + } + msg.Buffer = req->Buffer; + msg.iMethod = req->reqh.iMethod; + msg.cbBuffer = req->reqh.cbBuffer; + req->state = REQSTATE_INVOKING; + req->resph.retval = IRpcStubBuffer_Invoke(stub,&msg,NULL); + req->Buffer = msg.Buffer; + req->resph.cbBuffer = msg.cbBuffer; + reqtype = REQTYPE_RESPONSE; + hres = _xwrite(req->hPipe,&reqtype,sizeof(reqtype)); + if (hres) return hres; + hres = _xwrite(req->hPipe,&(req->resph),sizeof(req->resph)); + if (hres) return hres; + hres = _xwrite(req->hPipe,req->Buffer,req->resph.cbBuffer); + if (hres) return hres; + req->state = REQSTATE_DONE; + drs("invoke"); + return S_OK; +} + +static HRESULT _read_one(wine_pipe *xpipe); + +static HRESULT +RPC_QueueRequestAndWait(wine_rpc_request *req) { + int i; + wine_rpc_request *xreq; + HRESULT hres; + DWORD reqtype; + wine_pipe *xpipe = PIPE_GetFromMID(&(req->reqh.mid)); + + if (!xpipe) { + FIXME("no pipe found.\n"); + return E_POINTER; + } + if (GetCurrentProcessId() == req->reqh.mid.processid) { + ERR("In current process?\n"); + return E_FAIL; + } + req->hPipe = xpipe->hPipe; + req->state = REQSTATE_REQ_WAITING_FOR_REPLY; + reqtype = REQTYPE_REQUEST; + hres = _xwrite(req->hPipe,&reqtype,sizeof(reqtype)); + if (hres) return hres; + hres = _xwrite(req->hPipe,&(req->reqh),sizeof(req->reqh)); + if (hres) return hres; + hres = _xwrite(req->hPipe,req->Buffer,req->reqh.cbBuffer); + if (hres) return hres; + + while (1) { + /*WaitForSingleObject(hRpcChanged,INFINITE);*/ + hres = _read_one(xpipe); + if (hres) break; + + for (i=0;istate==REQSTATE_REQ_GOT) && (xreq->hPipe==req->hPipe)) { + _invoke_onereq(xreq); + } + } + if (req->state == REQSTATE_RESP_GOT) + return S_OK; + } + return hres; +} + +static HRESULT WINAPI +PipeBuf_SendReceive( + LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status +) { + ICOM_THIS(PipeBuf,iface); + wine_rpc_request *req; + HRESULT hres; + + TRACE("()\n"); + + if (This->mid.processid == GetCurrentProcessId()) { + ERR("Need to call directly!\n"); + return E_FAIL; + } + + hres = RPC_GetRequest(&req); + if (hres) return hres; + req->reqh.iMethod = msg->iMethod; + req->reqh.cbBuffer = msg->cbBuffer; + memcpy(&(req->reqh.mid),&(This->mid),sizeof(This->mid)); + req->Buffer = msg->Buffer; + hres = RPC_QueueRequestAndWait(req); + if (hres) { + RPC_FreeRequest(req); + return hres; + } + msg->cbBuffer = req->resph.cbBuffer; + msg->Buffer = req->Buffer; + *status = req->resph.retval; + RPC_FreeRequest(req); + return S_OK; +} + + +static HRESULT WINAPI +PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) { + FIXME("(%p), stub!\n",msg); + return E_FAIL; +} + +static HRESULT WINAPI +PipeBuf_GetDestCtx( + LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext +) { + FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext); + return E_FAIL; +} + +static HRESULT WINAPI +PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface) { + FIXME("(), stub!\n"); + return S_OK; +} + +static ICOM_VTABLE(IRpcChannelBuffer) pipebufvt = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + PipeBuf_QueryInterface, + PipeBuf_AddRef, + PipeBuf_Release, + PipeBuf_GetBuffer, + PipeBuf_SendReceive, + PipeBuf_FreeBuffer, + PipeBuf_GetDestCtx, + PipeBuf_IsConnected +}; + +HRESULT +PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) { + wine_marshal_id ourid; + DWORD res; + HANDLE hPipe; + HRESULT hres; + PipeBuf *pbuf; + + hPipe = PIPE_FindByMID(mid); + if (hPipe == INVALID_HANDLE_VALUE) { + char pipefn[200]; + sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid); + hPipe = CreateFileA( + pipefn, + GENERIC_READ|GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + -1 + ); + if (hPipe == INVALID_HANDLE_VALUE) { + FIXME("Could not open named pipe %s, le is %lx\n",pipefn,GetLastError()); + return E_FAIL; + } + hres = PIPE_RegisterPipe(mid, hPipe, FALSE); + if (hres) return hres; + memset(&ourid,0,sizeof(ourid)); + ourid.processid = GetCurrentProcessId(); + if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) { + ERR("Failed writing startup mid!\n"); + return E_FAIL; + } + } + pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf)); + pbuf->lpVtbl = &pipebufvt; + pbuf->ref = 1; + memcpy(&(pbuf->mid),mid,sizeof(*mid)); + *pipebuf = (IRpcChannelBuffer*)pbuf; + return S_OK; +} + +static HRESULT +create_server(REFCLSID rclsid) { + HKEY key; + char buf[200]; + HRESULT hres = E_UNEXPECTED; + char xclsid[80]; + WCHAR dllName[MAX_PATH+1]; + DWORD dllNameLen = sizeof(dllName); + STARTUPINFOW sinfo; + PROCESS_INFORMATION pinfo; + + WINE_StringFromCLSID((LPCLSID)rclsid,xclsid); + + sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid); + hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key); + + if (hres != ERROR_SUCCESS) + return REGDB_E_CLASSNOTREG; + + memset(dllName,0,sizeof(dllName)); + hres= RegQueryValueExW(key,NULL,NULL,NULL,(LPBYTE)dllName,&dllNameLen); + if (hres) + return REGDB_E_CLASSNOTREG; /* FIXME: check retval */ + RegCloseKey(key); + memset(&sinfo,0,sizeof(sinfo)); + sinfo.cb = sizeof(sinfo); + if (!CreateProcessW(NULL,dllName,NULL,NULL,FALSE,0,NULL,NULL,&sinfo,&pinfo)) + return E_FAIL; + return S_OK; +} +/* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */ +HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) { + HRESULT hres; + HANDLE hPipe; + char pipefn[200]; + DWORD res,bufferlen; + char marshalbuffer[200]; + IStream *pStm; + LARGE_INTEGER seekto; + ULARGE_INTEGER newpos; + int tries = 0; +#define MAXTRIES 10000 + + strcpy(pipefn,PIPEPREF); + WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF)); + + while (tries++=MAXTRIES) + return E_NOINTERFACE; + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) return hres; + hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res); + if (hres) goto out; + seekto.s.LowPart = 0;seekto.s.HighPart = 0; + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv); +out: + IStream_Release(pStm); + return hres; +} + + +static void WINAPI +PIPE_StartRequestThread(HANDLE xhPipe) { + wine_marshal_id remoteid; + HRESULT hres; + + hres = _xread(xhPipe,&remoteid,sizeof(remoteid)); + if (hres) { + ERR("Failed to read remote mid!\n"); + return; + } + PIPE_RegisterPipe(&remoteid,xhPipe, TRUE); +} + +static HRESULT +_read_one(wine_pipe *xpipe) { + DWORD reqtype; + HRESULT hres = S_OK; + HANDLE xhPipe = xpipe->hPipe; + + /*FIXME("%lx %d reading reqtype\n",GetCurrentProcessId(),xhPipe);*/ + hres = _xread(xhPipe,&reqtype,sizeof(reqtype)); + if (hres) goto end; + EnterCriticalSection(&(xpipe->crit)); + /*FIXME("%lx got reqtype %ld\n",GetCurrentProcessId(),reqtype);*/ + + if (reqtype == REQTYPE_REQUEST) { + wine_rpc_request *xreq; + RPC_GetRequest(&xreq); + xreq->hPipe = xhPipe; + hres = _xread(xhPipe,&(xreq->reqh),sizeof(xreq->reqh)); + if (hres) goto end; + xreq->resph.reqid = xreq->reqh.reqid; + xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer); + hres = _xread(xhPipe,xreq->Buffer,xreq->reqh.cbBuffer); + if (hres) goto end; + xreq->state = REQSTATE_REQ_GOT; + goto end; + } + if (reqtype == REQTYPE_RESPONSE) { + wine_rpc_response_header resph; + int i; + + hres = _xread(xhPipe,&resph,sizeof(resph)); + if (hres) goto end; + for (i=nrofreqs;i--;) { + wine_rpc_request *xreq = reqs[i]; + if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY) + continue; + if (xreq->reqh.reqid == resph.reqid) { + memcpy(&(xreq->resph),&resph,sizeof(resph)); + xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer); + hres = _xread(xhPipe,xreq->Buffer,xreq->resph.cbBuffer); + if (hres) goto end; + xreq->state = REQSTATE_RESP_GOT; + /*PulseEvent(hRpcChanged);*/ + goto end; + } + } + ERR("Did not find request for id %lx\n",resph.reqid); + hres = S_OK; + goto end; + } + ERR("Unknown reqtype %ld\n",reqtype); + hres = E_FAIL; +end: + LeaveCriticalSection(&(xpipe->crit)); + return hres; +} + +static DWORD WINAPI +_StubReaderThread(LPVOID param) { + wine_pipe *xpipe = (wine_pipe*)param; + HANDLE xhPipe = xpipe->hPipe; + HRESULT hres; + + TRACE("STUB reader thread %lx\n",GetCurrentProcessId()); + while (1) { + int i; + hres = _read_one(xpipe); + if (hres) break; + + for (i=nrofreqs;i--;) { + wine_rpc_request *xreq = reqs[i]; + if ((xreq->state == REQSTATE_REQ_GOT) && (xreq->hPipe == xhPipe)) { + _invoke_onereq(xreq); + } + } + } + FIXME("Failed with hres %lx\n",hres); + CloseHandle(xhPipe); + return 0; +} + +static DWORD WINAPI +_StubMgrThread(LPVOID param) { + char pipefn[200]; + HANDLE listenPipe; + + sprintf(pipefn,OLESTUBMGR"_%08lx",GetCurrentProcessId()); + TRACE("Stub Manager Thread starting on (%s)\n",pipefn); + + listenPipe = CreateNamedPipeA( + pipefn, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE|PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + 4096, + 4096, + NMPWAIT_USE_DEFAULT_WAIT, + NULL + ); + if (listenPipe == INVALID_HANDLE_VALUE) { + FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError()); + return 1; /* permanent failure, so quit stubmgr thread */ + } + + while (1) { + if (!ConnectNamedPipe(listenPipe,NULL)) { + ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError()); + CloseHandle(listenPipe); + continue; + } + PIPE_StartRequestThread(listenPipe); + listenPipe = CreateNamedPipeA( + pipefn, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE|PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + 4096, + 4096, + NMPWAIT_USE_DEFAULT_WAIT, + NULL + ); + if (listenPipe == INVALID_HANDLE_VALUE) { + FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError()); + return 1; /* permanent failure, so quit stubmgr thread */ + } + } + return 0; +} + +void +STUBMGR_Start() { + static BOOL stubMgrRunning = FALSE; + DWORD tid; + + if (!stubMgrRunning) { + stubMgrRunning = TRUE; + CreateThread(NULL,0,_StubMgrThread,NULL,0,&tid); + Sleep(2000); /* actually we just try opening the pipe until it succeeds */ + } +} diff --git a/dlls/oleaut32/Makefile.in b/dlls/oleaut32/Makefile.in index 4bc354065b4..f8af0be5982 100644 --- a/dlls/oleaut32/Makefile.in +++ b/dlls/oleaut32/Makefile.in @@ -21,6 +21,7 @@ C_SRCS = \ propertyframe.c \ safearray.c \ stubs.c \ + tmarshal.c \ typelib.c \ variant.c diff --git a/dlls/oleaut32/oleaut.c b/dlls/oleaut32/oleaut.c index c5ab05b7a52..fb04c438381 100644 --- a/dlls/oleaut32/oleaut.c +++ b/dlls/oleaut32/oleaut.c @@ -14,6 +14,9 @@ #include "olectl.h" #include "wine/obj_oleaut.h" #include "wine/obj_olefont.h" + +#include "tmarshal.h" + #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(ole); @@ -162,6 +165,11 @@ HRESULT WINAPI OLEAUT32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *pp return S_OK; } } + if (IsEqualGUID(rclsid,&CLSID_PSOAInterface)) { + if (S_OK==TypeLibFac_DllGetClassObject(rclsid,iid,ppv)) + return S_OK; + /*FALLTHROUGH*/ + } FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid)); return CLASS_E_CLASSNOTAVAILABLE; } diff --git a/dlls/oleaut32/oleaut32.spec b/dlls/oleaut32/oleaut32.spec index 8bbb2ea7217..737c54df531 100644 --- a/dlls/oleaut32/oleaut32.spec +++ b/dlls/oleaut32/oleaut32.spec @@ -10,7 +10,7 @@ import advapi32.dll import kernel32.dll import ntdll.dll -debug_channels (ole typelib) +debug_channels (ole olerelay typelib) 1 stdcall DllGetClassObject(ptr ptr ptr) OLEAUT32_DllGetClassObject 2 stdcall SysAllocString(wstr) SysAllocString diff --git a/dlls/oleaut32/tmarshal.c b/dlls/oleaut32/tmarshal.c new file mode 100644 index 00000000000..47057ed4d22 --- /dev/null +++ b/dlls/oleaut32/tmarshal.c @@ -0,0 +1,1204 @@ +/* + * TYPELIB Marshaler + * + * Copyright 2002 Marcus Meissner + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "winerror.h" +#include "winnls.h" +#include "winreg.h" +#include "winuser.h" + +#include "ole2.h" +#include "wine/unicode.h" +#include "wine/obj_base.h" +#include "wine/obj_channel.h" +#include "wine/obj_storage.h" +#include "heap.h" +#include "ole2disp.h" +#include "typelib.h" +#include "debugtools.h" +#include "ntddk.h" + +static const WCHAR riidW[5] = {'r','i','i','d',0}; + +DEFAULT_DEBUG_CHANNEL(ole); +DECLARE_DEBUG_CHANNEL(olerelay); + +typedef struct _marshal_state { + LPBYTE base; + int size; + int curoff; + + BOOL thisisiid; + IID iid; /* HACK: for VT_VOID */ +} marshal_state; + +static HRESULT +xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) { + while (buf->size - buf->curoff < size) { + if (buf->base) { + buf->size += 100; + buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size); + if (!buf->base) + return E_OUTOFMEMORY; + } else { + buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32); + buf->size = 32; + if (!buf->base) + return E_OUTOFMEMORY; + } + } + memcpy(buf->base+buf->curoff,stuff,size); + buf->curoff += size; + return S_OK; +} + +static HRESULT +xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) { + if (buf->size < buf->curoff+size) return E_FAIL; + memcpy(stuff,buf->base+buf->curoff,size); + buf->curoff += size; + return S_OK; +} + +static HRESULT +xbuf_skip(marshal_state *buf, DWORD size) { + if (buf->size < buf->curoff+size) return E_FAIL; + buf->curoff += size; + return S_OK; +} + +static HRESULT +_unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) { + IStream *pStm; + ULARGE_INTEGER newpos; + LARGE_INTEGER seekto; + ULONG res; + HRESULT hres; + DWORD xsize; + + TRACE("...%s...\n",debugstr_guid(riid)); + *pUnk = NULL; + hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize)); + if (hres) return hres; + if (xsize == 0) return S_OK; + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) { + FIXME("Stream create failed %lx\n",hres); + return hres; + } + hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res); + if (hres) { FIXME("stream write %lx\n",hres); return hres; } + memset(&seekto,0,sizeof(seekto)); + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { FIXME("Failed Seek %lx\n",hres); return hres;} + hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk); + if (hres) { + FIXME("Marshaling interface %s failed with %lx\n",debugstr_guid(riid),hres); + return hres; + } + IStream_Release(pStm); + return xbuf_skip(buf,xsize); +} + +static HRESULT +_marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) { + LPUNKNOWN newiface; + LPBYTE tempbuf; + IStream *pStm; + STATSTG ststg; + ULARGE_INTEGER newpos; + LARGE_INTEGER seekto; + ULONG res; + DWORD xsize; + HRESULT hres; + + hres = S_OK; + if (!pUnk) + goto fail; + + TRACE("...%s...\n",debugstr_guid(riid)); + hres=IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface); + if (hres) { + TRACE("%p does not support iface %s\n",pUnk,debugstr_guid(riid)); + goto fail; + } + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) { + FIXME("Stream create failed %lx\n",hres); + goto fail; + } + hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0); + IUnknown_Release(newiface); + if (hres) { + FIXME("Marshaling interface %s failed with %lx\n", + debugstr_guid(riid),hres + ); + goto fail; + } + hres = IStream_Stat(pStm,&ststg,0); + tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.s.LowPart); + memset(&seekto,0,sizeof(seekto)); + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { FIXME("Failed Seek %lx\n",hres); goto fail;} + hres = IStream_Read(pStm,tempbuf,ststg.cbSize.s.LowPart,&res); + if (hres) { FIXME("Failed Read %lx\n",hres); goto fail;} + IStream_Release(pStm); + xsize = ststg.cbSize.s.LowPart; + xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); + hres = xbuf_add(buf,tempbuf,ststg.cbSize.s.LowPart); + HeapFree(GetProcessHeap(),0,tempbuf); + return hres; +fail: + xsize = 0; + xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); + return hres; +} + +/********************* OLE Proxy/Stub Factory ********************************/ +static HRESULT WINAPI +PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) { + if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) { + *ppv = (LPVOID)iface; + /* No ref counting, static class */ + return S_OK; + } + FIXME("(%s) unknown IID?\n",debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; } +static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; } + +static HRESULT +_get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) { + HRESULT hres; + HKEY ikey; + char tlguid[200],typelibkey[300],interfacekey[300],ver[100]; + char tlfn[260]; + OLECHAR tlfnW[260]; + DWORD tlguidlen, verlen, type, tlfnlen; + ITypeLib *tl; + + sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib", + riid->Data1, riid->Data2, riid->Data3, + riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3], + riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] + ); + + if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) { + FIXME("No %s key found.\n",interfacekey); + return E_FAIL; + } + type = (1<oVft/4 > max) + max = fdesc->oVft/4; + if (hres) + return max+1; + n++; + } + /*NOTREACHED*/ +} + +typedef struct _TMAsmProxy { + BYTE popleax; + BYTE pushlval; + BYTE nr; + BYTE pushleax; + BYTE lcall; + DWORD xcall; + BYTE lret; + WORD bytestopop; +} WINE_PACKED TMAsmProxy; + +typedef struct _TMProxyImpl { + DWORD *lpvtbl; + ICOM_VTABLE(IRpcProxyBuffer) *lpvtbl2; + DWORD ref; + + TMAsmProxy *asmstubs; + ITypeInfo* tinfo; + IRpcChannelBuffer* chanbuf; + IID iid; +} TMProxyImpl; + +static HRESULT WINAPI +TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv) { + TRACE("()\n"); + if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) { + *ppv = (LPVOID)iface; + IRpcProxyBuffer_AddRef(iface); + return S_OK; + } + FIXME("no interface for %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI +TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); + + TRACE("()\n"); + This->ref++; + return This->ref; +} + +static ULONG WINAPI +TMProxyImpl_Release(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); + + TRACE("()\n"); + This->ref--; + if (This->ref) return This->ref; + if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +static HRESULT WINAPI +TMProxyImpl_Connect( + LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer +) { + ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); + + TRACE("(%p)\n",pRpcChannelBuffer); + This->chanbuf = pRpcChannelBuffer; + IRpcChannelBuffer_AddRef(This->chanbuf); + return S_OK; +} + +static void WINAPI +TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); + + FIXME("()\n"); + IRpcChannelBuffer_Release(This->chanbuf); + This->chanbuf = NULL; +} + + +static ICOM_VTABLE(IRpcProxyBuffer) tmproxyvtable = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + TMProxyImpl_QueryInterface, + TMProxyImpl_AddRef, + TMProxyImpl_Release, + TMProxyImpl_Connect, + TMProxyImpl_Disconnect +}; + +static HRESULT +marshall_param( + ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf +) { + int relaydeb = TRACE_ON(olerelay); + HRESULT hres; + + if (!tdesc) tdesc = &(elem->tdesc); + switch (tdesc->vt) { + case VT_NULL: + return S_OK; + case VT_BSTR: { /* DWORD size, string data */ + DWORD *bstr = ((DWORD*)(*arg))-1; + + if (relaydeb) MESSAGE("%s",debugstr_w((LPWSTR)(bstr+1))); + return xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4); + } + case VT_BOOL: + case VT_I4: + if (relaydeb) MESSAGE("%ld",*arg); + return xbuf_add(buf,(LPBYTE)arg,4); + case VT_VARIANT: { + /* We use ourselves to marshal the value further */ + TYPEDESC tdesc2; + VARIANT *vt = (VARIANT*)arg; + DWORD vttype = V_VT(vt); + + hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype)); + if (hres) return hres; + tdesc2.vt = vttype; + if (relaydeb) MESSAGE("Vt %ld ",vttype); + /* shield your eyes, bad pointer voodoo below */ + return marshall_param(tinfo,elem,&tdesc2,(DWORD*)&(V_I4(vt)),buf); + } + case VT_PTR: + return marshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf); + case VT_VOID: + hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)arg); + if (hres) { + FIXME("Failed unmarshaling VT_VOID with guid %s?\n",debugstr_guid(&(buf->iid))); + } + return hres; + case VT_USERDEFINED: { + ITypeInfo *tinfo2; + TYPEATTR *tattr; + + /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/ + hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); + if (hres) { + FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); + return hres; + } + ITypeInfo_GetTypeAttr(tinfo2,&tattr); + switch (tattr->typekind) { + case TKIND_INTERFACE: + if (relaydeb) MESSAGE("if(%p), vtbl %p",arg,(LPVOID)*arg); + hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg); + break; + case TKIND_RECORD: + if (relaydeb) MESSAGE("record %p",arg); + if (buf->thisisiid) + memcpy(&(buf->iid),arg,sizeof(buf->iid)); + hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance); + break; + default: + FIXME("Don't know how to marshal type kind %d\n",tattr->typekind); + hres = E_FAIL; + break; + } + ITypeInfo_Release(tinfo2); + return hres; + } + default: + ERR("Cannot marshal type %d\n",tdesc->vt); + /*dump_ELEMDESC(elem);*/ + return E_FAIL; + } + return S_OK; +} + +static HRESULT +unmarshall_param( + ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf +) { + HRESULT hres = S_OK; + int relaydeb = TRACE_ON(olerelay); + + if (!tdesc) tdesc = &(elem->tdesc); + switch (tdesc->vt) { + case VT_I4: { + DWORD x; + xbuf_get(buf,(LPBYTE)&x,sizeof(x)); + *arg = x; + if (relaydeb) MESSAGE("%ld ",x); + return S_OK; + } + case VT_PTR: + if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) && + (tdesc->u.lptdesc->vt != VT_VOID) + ) + hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)(*arg),buf); + else + hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,arg,buf); + if (relaydeb) MESSAGE("%p ",(LPVOID)*arg); + return S_OK; + case VT_USERDEFINED: { + ITypeInfo *tinfo2; + TYPEATTR *tattr; + + if (relaydeb) MESSAGE("%p",arg); + hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); + if (hres) { + FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); + return hres; + } + hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr); + if (hres) { + FIXME("Could not get typeattr in VT_USERDEFINED.\n"); + return hres; + } + switch (tattr->typekind) { + case TKIND_INTERFACE: + hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg); + break; + case TKIND_RECORD: + hres = xbuf_get(buf,(LPBYTE)arg,tattr->cbSizeInstance); + break; + default: + hres = E_FAIL; + FIXME("Don't know how to marshal type kind %d\n",tattr->typekind); + } + ITypeInfo_Release(tinfo2); + return hres; + } + case VT_VOID: + /* Hacky. If we are LPVOID* we apparently have to guess the IID + * for the interface. This sucks pretty badly. */ + return _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg); + default: ERR("Cannot unmarshal type %d\n",tdesc->vt); + return E_FAIL; + } + return S_OK; +} + +/* Searches function, also in inherited interfaces */ +static HRESULT +_get_funcdesc( + ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, + BSTR *iname, BSTR *fname +) { + int i = 0, j = 0; + HRESULT hres; + + if (fname) *fname = NULL; + if (iname) *iname = NULL; + + while (1) { + hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc); + if (hres) { + ITypeInfo *tinfo2; + HREFTYPE href; + TYPEATTR *attr; + + hres = ITypeInfo_GetTypeAttr(tinfo, &attr); + if (hres) { + FIXME("GetTypeAttr failed with %lx\n",hres); + return hres; + } + /* Not found, so look in inherited ifaces. */ + for (j=0;jcImplTypes;j++) { + hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href); + if (hres) { + FIXME("Did not find a reftype for interface offset %d?\n",j); + break; + } + hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2); + if (hres) { + FIXME("Did not find a typeinfo for reftype %ld?\n",href); + continue; + } + hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname); + ITypeInfo_Release(tinfo2); + if (!hres) return S_OK; + } + return E_FAIL; + } + if (((*fdesc)->oVft/4) == iMethod) { + if (fname) + ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL); + if (iname) + ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL); + return S_OK; + } + i++; + } + return E_FAIL; +} + +/* how much space do we use on stack in DWORD steps. */ +static int +_argsize(DWORD vt_type) { + switch (vt_type) { + case VT_VARIANT: + return (sizeof(VARIANT)+3)/sizeof(DWORD); + default: + return 1; + } +} + +static DWORD +xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) { + DWORD *args = ((DWORD*)&tpinfo)+1, *xargs; + FUNCDESC *fdesc; + HRESULT hres; + int i, relaydeb = TRACE_ON(olerelay); + marshal_state buf; + RPCOLEMESSAGE msg; + ULONG status; + BSTR fname,iname; + BSTR names[10]; + int nrofnames; + + hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname); + if (hres) { + ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method); + return 0; + } + + /*dump_FUNCDESC(fdesc);*/ + if (relaydeb) { + TRACE_(olerelay)("->"); + if (iname) + MESSAGE("%s:",debugstr_w(iname)); + if (fname) + MESSAGE("%s(%d)",debugstr_w(fname),method); + else + MESSAGE("%d",method); + MESSAGE("("); + if (iname) SysFreeString(iname); + if (fname) SysFreeString(fname); + } + /* Need them for hack below */ + memset(names,0,sizeof(names)); + ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames); + if (nrofnames > sizeof(names)/sizeof(names[0])) { + ERR("Need more names!\n"); + } + memset(&buf,0,sizeof(buf)); + buf.iid = IID_IUnknown; + if (method == 0) { + xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID)); + if (relaydeb) MESSAGE("riid=%s,[out]",debugstr_guid((REFIID)args[0])); + } else { + xargs = args; + for (i=0;icParams;i++) { + ELEMDESC *elem = fdesc->lprgelemdescParam+i; + if (relaydeb) { + if (i) MESSAGE(","); + if (i+1tinfo,elem,NULL,xargs,&buf); + xargs+=_argsize(elem->tdesc.vt); + if (hres) { + FIXME("Failed to marshall param, hres %lx\n",hres); + break; + } + } + } + if (relaydeb) MESSAGE(")"); + memset(&msg,0,sizeof(msg)); + msg.cbBuffer = buf.curoff; + msg.iMethod = method; + hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid)); + if (hres) { + FIXME("RpcChannelBuffer GetBuffer failed, %lx\n",hres); + return hres; + } + memcpy(msg.Buffer,buf.base,buf.curoff); + hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status); + if (hres) { + FIXME("RpcChannelBuffer SendReceive failed, %lx\n",hres); + return hres; + } + if (relaydeb) MESSAGE(" = %08lx (",status); + if (buf.base) + buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer); + else + buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer); + buf.size = msg.cbBuffer; + memcpy(buf.base,msg.Buffer,buf.size); + buf.curoff = 0; + if (method == 0) { + _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]); + if (relaydeb) MESSAGE("[in],%p",*((DWORD**)args[1])); + } else { + xargs = args; + for (i=0;icParams;i++) { + ELEMDESC *elem = fdesc->lprgelemdescParam+i; + + if (relaydeb) { + if (i) MESSAGE(","); + if (i+1tinfo,elem,&(elem->tdesc),xargs,&buf); + xargs += _argsize(elem->tdesc.vt); + if (hres) { + FIXME("Failed to unmarshall param, hres %lx\n",hres); + break; + } + } + } + if (relaydeb) MESSAGE(")\n"); + HeapFree(GetProcessHeap(),0,buf.base); + return status; +} + +static HRESULT WINAPI +PSFacBuf_CreateProxy( + LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, + IRpcProxyBuffer **ppProxy, LPVOID *ppv +) { + HRESULT hres; + ITypeInfo *tinfo; + int i, nroffuncs; + FUNCDESC *fdesc; + TMProxyImpl *proxy; + + TRACE("(...%s...)\n",debugstr_guid(riid)); + hres = _get_typeinfo_for_iid(riid,&tinfo); + if (hres) { + FIXME("No typeinfo for %s?\n",debugstr_guid(riid)); + return hres; + } + nroffuncs = _nroffuncs(tinfo); + proxy = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMProxyImpl)); + if (!proxy) return E_OUTOFMEMORY; + proxy->asmstubs=HeapAlloc(GetProcessHeap(),0,sizeof(TMAsmProxy)*nroffuncs); + + assert(sizeof(TMAsmProxy) == 12); + + proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs); + for (i=0;iasmstubs+i; + + /* nrofargs without This */ + switch (i) { + case 0: nrofargs = 2; + break; + case 1: case 2: nrofargs = 0; + break; + default: { + int j; + hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL); + if (hres) { + FIXME("GetFuncDesc %lx should not fail here.\n",hres); + return hres; + } + /* some args take more than 4 byte on the stack */ + nrofargs = 0; + for (j=0;jcParams;j++) + nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt); + + if (fdesc->callconv != CC_STDCALL) { + ERR("calling convention is not stdcall????\n"); + return E_FAIL; + } + break; + } + } +/* popl %eax - return ptr + * pushl + * pushl %eax + * call xCall + * lret (+4) + * + * + * arg3 arg2 arg1 + */ + xasm->popleax = 0x58; + xasm->pushlval = 0x6a; + xasm->nr = i; + xasm->pushleax = 0x50; + xasm->lcall = 0xe8; /* relative jump */ + xasm->xcall = (DWORD)xCall; + xasm->xcall -= (DWORD)&(xasm->lret); + xasm->lret = 0xc2; + xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */ + proxy->lpvtbl[i] = (DWORD)xasm; + } + proxy->lpvtbl2 = &tmproxyvtable; + proxy->ref = 2; + proxy->tinfo = tinfo; + memcpy(&proxy->iid,riid,sizeof(*riid)); + *ppv = (LPVOID)proxy; + *ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2); + return S_OK; +} + +typedef struct _TMStubImpl { + ICOM_VTABLE(IRpcStubBuffer) *lpvtbl; + DWORD ref; + + LPUNKNOWN pUnk; + ITypeInfo *tinfo; + IID iid; +} TMStubImpl; + +static HRESULT WINAPI +TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) { + if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){ + *ppv = (LPVOID)iface; + IRpcStubBuffer_AddRef(iface); + return S_OK; + } + FIXME("%s, not supported IID.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI +TMStubImpl_AddRef(LPRPCSTUBBUFFER iface) { + ICOM_THIS(TMStubImpl,iface); + + This->ref++; + return This->ref; +} + +static ULONG WINAPI +TMStubImpl_Release(LPRPCSTUBBUFFER iface) { + ICOM_THIS(TMStubImpl,iface); + + This->ref--; + if (This->ref) + return This->ref; + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +static HRESULT WINAPI +TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) { + ICOM_THIS(TMStubImpl,iface); + + IUnknown_AddRef(pUnkServer); + This->pUnk = pUnkServer; + return S_OK; +} + +static void WINAPI +TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface) { + ICOM_THIS(TMStubImpl,iface); + + IUnknown_Release(This->pUnk); + This->pUnk = NULL; + return; +} + +static HRESULT +stuballoc_param( + ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf +) { + HRESULT hres; + + while (1) { + switch (tdesc->vt) { + case VT_VARIANT: { + DWORD vttype; + VARIANT *vt = (VARIANT*)arg; + TYPEDESC tdesc2; + + hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype)); + if (hres) return hres; + memset(&tdesc2,0,sizeof(tdesc)); + tdesc2.vt = vttype; + V_VT(vt) = vttype; + return stuballoc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf); + } + case VT_BOOL: case VT_I4: + xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD)); + return S_OK; + case VT_BSTR: { + WCHAR *str; + DWORD len; + + hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD)); + if (hres) + return hres; + str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR)); + hres = xbuf_get(buf,(LPBYTE)str,len); + if (hres) return hres; + *arg = (DWORD)SysAllocStringLen(str,len); + HeapFree(GetProcessHeap(),0,str); + return S_OK; + } + case VT_PTR: + if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) && + (tdesc->u.lptdesc->vt != VT_VOID) + ) { + *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID)); + arg = (DWORD*)*arg; + } + tdesc = tdesc->u.lptdesc; + break; + case VT_UNKNOWN: + /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */ + *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); + return S_OK; + case VT_VOID: + *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)); + hres = S_OK; + if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) + hres = _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg); + return hres; + case VT_USERDEFINED: { + if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) { + ITypeInfo *tinfo2; + TYPEATTR *tattr; + + hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); + if (hres) { + FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); + return hres; + } + hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr); + if (hres) { + FIXME("Could not get typeattr in VT_USERDEFINED.\n"); + return hres; + } + switch (tattr->typekind) { + case TKIND_INTERFACE: + hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg); + break; + case TKIND_RECORD: + *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance); + hres = xbuf_get(buf,(LPBYTE)*arg,tattr->cbSizeInstance); + if (buf->thisisiid) + memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid)); + break; + default: + FIXME("Don't know how to marshal type kind %d\n",tattr->typekind); + hres = E_FAIL; + break; + } + ITypeInfo_Release(tinfo2); + return hres; + } else { + *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)); + return S_OK; + } + } + default: + ERR("No handler for VT type %d, just allocating 4 bytes.\n",tdesc->vt); + *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); + return S_OK; + } + } +} + +static HRESULT +stubunalloc_param( + ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf +) { + HRESULT hres = S_OK; + + if (!tdesc) tdesc = &(elem->tdesc); + + switch (tdesc->vt) { + case VT_BOOL: + case VT_I4: + hres = S_OK; + if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) + hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); + return hres; + case VT_VARIANT: { + TYPEDESC tdesc2; + VARIANT *vt = (VARIANT*)arg; + DWORD vttype = V_VT(vt); + + tdesc2.vt = vttype; + if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) { + hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype)); + if (hres) return hres; + } + /* need to recurse since we need to free the stuff */ + hres = stubunalloc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf); + return hres; + } + case VT_BSTR: { + if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) { + DWORD *bstr = ((DWORD*)(*arg))-1; + + hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4); + if (hres) + return hres; + } + SysFreeString((BSTR)*arg); + return S_OK; + } + case VT_PTR: + /*FIXME("VT_PTR *arg is %p\n",(LPVOID)*arg);*/ + if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) && + (tdesc->u.lptdesc->vt != VT_VOID) + ) { + hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,arg,buf); + } else { + hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf); + HeapFree(GetProcessHeap(),0,(LPVOID)*arg); + } + return hres; + case VT_UNKNOWN: + if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) { + FIXME("Marshaling back VT_UNKNOWN %lx\n",*arg); + hres = xbuf_add(buf,(LPBYTE)*arg,sizeof(DWORD)); + } + HeapFree(GetProcessHeap(),0,(LPVOID)*arg); + return hres; + case VT_VOID: + hres = S_OK; + if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) + hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)*arg); + return hres; + case VT_USERDEFINED: { + ITypeInfo *tinfo2; + TYPEATTR *tattr; + + if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) { + /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/ + hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); + if (hres) { + FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); + return hres; + } + ITypeInfo_GetTypeAttr(tinfo2,&tattr); + switch (tattr->typekind) { + case TKIND_INTERFACE: + hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)*arg); + break; + case TKIND_RECORD: + hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance); + break; + default: + FIXME("Don't know how to marshal type kind %d\n",tattr->typekind); + hres = E_FAIL; + break; + } + ITypeInfo_Release(tinfo2); + } + return hres; + } + default: + ERR("Unhandled marshal type %d.\n",tdesc->vt); + HeapFree(GetProcessHeap(),0,(LPVOID)*arg); + return S_OK; + } +} + +static HRESULT WINAPI +TMStubImpl_Invoke( + LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf +) { + int i; + FUNCDESC *fdesc; + ICOM_THIS(TMStubImpl,iface); + HRESULT hres; + DWORD *args, res, *xargs, nrofargs; + marshal_state buf; + int nrofnames; + BSTR names[10]; + + memset(&buf,0,sizeof(buf)); + buf.size = xmsg->cbBuffer; + buf.base = xmsg->Buffer; + buf.curoff = 0; + buf.iid = IID_IUnknown; + + TRACE("...\n"); + if (xmsg->iMethod == 0) { /* QI */ + IID xiid; + /* in: IID, out: */ + + xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid)); + buf.curoff = 0; + hres = _marshal_interface(&buf,&xiid,This->pUnk); + xmsg->Buffer = buf.base; /* Might have been reallocated */ + xmsg->cbBuffer = buf.size; + return hres; + } + hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL); + if (hres) { + FIXME("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres); + return hres; + } + /* Need them for hack below */ + memset(names,0,sizeof(names)); + ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames); + if (nrofnames > sizeof(names)/sizeof(names[0])) { + ERR("Need more names!\n"); + } + + /*dump_FUNCDESC(fdesc);*/ + nrofargs = 0; + for (i=0;icParams;i++) + nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt); + args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD)); + if (!args) return E_OUTOFMEMORY; + + /* Allocate all stuff used by call. */ + xargs = args+1; + for (i=0;icParams;i++) { + ELEMDESC *elem = fdesc->lprgelemdescParam+i; + + if (((i+1)tinfo,elem,&(elem->tdesc),xargs,&buf); + xargs += _argsize(elem->tdesc.vt); + if (hres) { + FIXME("Failed to stuballoc param %s, hres %lx\n",debugstr_w(names[i+1]),hres); + break; + } + } + hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0])); + if (hres) { + ERR("Does not support iface %s\n",debugstr_guid(&(This->iid))); + return hres; + } + res = _invoke( + (*((LPVOID**)args[0]))[fdesc->oVft/4], + fdesc->callconv, + (xargs-args), + args + ); + IUnknown_Release((LPUNKNOWN)args[0]); + buf.curoff = 0; + xargs = args+1; + for (i=0;icParams;i++) { + ELEMDESC *elem = fdesc->lprgelemdescParam+i; + hres = stubunalloc_param(This->tinfo,elem,NULL,xargs,&buf); + xargs += _argsize(elem->tdesc.vt); + if (hres) { + FIXME("Failed to stuballoc param, hres %lx\n",hres); + break; + } + } + /* might need to use IRpcChannelBuffer_GetBuffer ? */ + xmsg->cbBuffer = buf.curoff; + xmsg->Buffer = buf.base; + HeapFree(GetProcessHeap(),0,args); + return res; +} + +static LPRPCSTUBBUFFER WINAPI +TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) { + FIXME("Huh (%s)?\n",debugstr_guid(riid)); + return NULL; +} + +static ULONG WINAPI +TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) { + ICOM_THIS(TMStubImpl,iface); + + return This->ref; /*FIXME? */ +} + +static HRESULT WINAPI +TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) { + return E_NOTIMPL; +} + +static void WINAPI +TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) { + return; +} + +ICOM_VTABLE(IRpcStubBuffer) tmstubvtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + TMStubImpl_QueryInterface, + TMStubImpl_AddRef, + TMStubImpl_Release, + TMStubImpl_Connect, + TMStubImpl_Disconnect, + TMStubImpl_Invoke, + TMStubImpl_IsIIDSupported, + TMStubImpl_CountRefs, + TMStubImpl_DebugServerQueryInterface, + TMStubImpl_DebugServerRelease +}; + +static HRESULT WINAPI +PSFacBuf_CreateStub( + LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer, + IRpcStubBuffer** ppStub +) { + HRESULT hres; + ITypeInfo *tinfo; + TMStubImpl *stub; + + TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub); + hres = _get_typeinfo_for_iid(riid,&tinfo); + if (hres) { + FIXME("No typeinfo for %s?\n",debugstr_guid(riid)); + return hres; + } + stub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMStubImpl)); + if (!stub) + return E_OUTOFMEMORY; + stub->lpvtbl = &tmstubvtbl; + stub->ref = 1; + stub->tinfo = tinfo; + memcpy(&(stub->iid),riid,sizeof(*riid)); + hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer); + *ppStub = (LPRPCSTUBBUFFER)stub; + if (hres) + FIXME("Connect to pUnkServer failed?\n"); + return hres; +} + +static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = { + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + PSFacBuf_QueryInterface, + PSFacBuf_AddRef, + PSFacBuf_Release, + PSFacBuf_CreateProxy, + PSFacBuf_CreateStub +}; + +/* This is the whole PSFactoryBuffer object, just the vtableptr */ +static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl; + +/*********************************************************************** + * DllGetClassObject [OLE32.63] + */ +HRESULT WINAPI +TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) +{ + if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) { + *ppv = &lppsfac; + return S_OK; + } + return E_NOINTERFACE; +} diff --git a/dlls/oleaut32/tmarshal.h b/dlls/oleaut32/tmarshal.h new file mode 100644 index 00000000000..976d66105ac --- /dev/null +++ b/dlls/oleaut32/tmarshal.h @@ -0,0 +1,6 @@ +#ifndef TMARSHAL_H +#define TMARSHAL_H +HRESULT WINAPI +TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv); + +#endif diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index e4cbeae7d51..460db2a373b 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -3917,7 +3917,8 @@ static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface, * Invokes a method, or accesses a property of an object, that implements the * interface described by the type description. */ -static DWORD _invoke(LPVOID func,CALLCONV callconv, int nrargs, DWORD *args) { +DWORD +_invoke(LPVOID func,CALLCONV callconv, int nrargs, DWORD *args) { DWORD res; if (TRACE_ON(ole)) { @@ -3951,6 +3952,26 @@ static DWORD _invoke(LPVOID func,CALLCONV callconv, int nrargs, DWORD *args) { res = xfunc(args[0],args[1],args[2]); break; } + case 4: { + DWORD (WINAPI *xfunc)(DWORD,DWORD,DWORD,DWORD) = func; + res = xfunc(args[0],args[1],args[2],args[3]); + break; + } + case 5: { + DWORD (WINAPI *xfunc)(DWORD,DWORD,DWORD,DWORD,DWORD) = func; + res = xfunc(args[0],args[1],args[2],args[3],args[4]); + break; + } + case 6: { + DWORD (WINAPI *xfunc)(DWORD,DWORD,DWORD,DWORD,DWORD,DWORD) = func; + res = xfunc(args[0],args[1],args[2],args[3],args[4],args[5]); + break; + } + case 7: { + DWORD (WINAPI *xfunc)(DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD) = func; + res = xfunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6]); + break; + } default: FIXME("unsupported number of arguments %d in stdcall\n",nrargs); res = -1; diff --git a/dlls/oleaut32/typelib.h b/dlls/oleaut32/typelib.h index 665e4cc6b59..c8a651ada93 100644 --- a/dlls/oleaut32/typelib.h +++ b/dlls/oleaut32/typelib.h @@ -542,6 +542,8 @@ WORD offset from start of block to SAFEARRAY WORD typeofarray */ +extern DWORD _invoke(LPVOID func,CALLCONV callconv, int nrargs, DWORD *args); + #include "poppack.h" /*---------------------------END--------------------------------------------*/ diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 41b057c82eb..7e8be610d2a 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -1396,6 +1396,10 @@ static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, case( VT_BOOL ): switch( vtFrom ) { + case( VT_EMPTY ): + res = S_OK; + V_UNION(pd,boolVal) = VARIANT_FALSE; + break; case( VT_I1 ): res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) ); break;