Implemented Local Server COM.

Implemented the Typelib based Marshaler.
This commit is contained in:
Marcus Meissner 2002-02-05 18:11:17 +00:00 committed by Alexandre Julliard
parent 395e8bafc4
commit 0749fc2034
15 changed files with 3285 additions and 58 deletions

View file

@ -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 \

View file

@ -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
*

View file

@ -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();

615
dlls/ole32/marshal.c Normal file
View file

@ -0,0 +1,615 @@
/*
* Marshaling library
*
* Copyright 2002 Marcus Meissner
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#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;i<nrofstubs;i++) {
if (MARSHAL_Compare_Mids_NoInterface(mid,&(stubs[i].mid))) {
*punk = stubs[i].pUnkServer;
IUnknown_AddRef((*punk));
return S_OK;
}
}
return E_FAIL;
}
HRESULT
MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub) {
int i;
for (i=0;i<nrofstubs;i++) {
if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
*stub = stubs[i].stub;
IUnknown_AddRef((*stub));
return S_OK;
}
}
return E_FAIL;
}
HRESULT
MARSHAL_Find_Stub(wine_marshal_id *mid,LPUNKNOWN *pUnk) {
int i;
for (i=0;i<nrofstubs;i++) {
if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) {
*pUnk = stubs[i].pUnkServer;
IUnknown_AddRef((*pUnk));
return S_OK;
}
}
return E_FAIL;
}
HRESULT
MARSHAL_Register_Stub(wine_marshal_id *mid,LPUNKNOWN pUnk,IRpcStubBuffer *stub) {
LPUNKNOWN xPunk;
if (!MARSHAL_Find_Stub(mid,&xPunk)) {
FIXME("Already have entry for (%lx/%s)!\n",mid->objectid,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;i<nrofproxies;i++)
if (MARSHAL_Compare_Mids(mid,&(proxies[i].mid))) {
*punk = proxies[i].pUnk;
IUnknown_AddRef((*punk));
return S_OK;
}
return E_FAIL;
}
HRESULT
MARSHAL_Find_Proxy_Object(wine_marshal_id *mid,LPUNKNOWN *punk) {
int i;
for (i=0;i<nrofproxies;i++)
if (MARSHAL_Compare_Mids_NoInterface(mid,&(proxies[i].mid))) {
*punk = proxies[i].pUnk;
IUnknown_AddRef((*punk));
return S_OK;
}
return E_FAIL;
}
HRESULT
MARSHAL_Register_Proxy(wine_marshal_id *mid,LPUNKNOWN punk) {
int i;
for (i=0;i<nrofproxies;i++) {
if (MARSHAL_Compare_Mids(mid,&(proxies[i].mid))) {
ERR("Already have mid?\n");
return E_FAIL;
}
}
if (nrofproxies)
proxies = HeapReAlloc(GetProcessHeap(),0,proxies,sizeof(proxies[0])*(nrofproxies+1));
else
proxies = HeapAlloc(GetProcessHeap(),0,sizeof(proxies[0]));
memcpy(&(proxies[nrofproxies].mid),mid,sizeof(*mid));
proxies[nrofproxies].pUnk = punk;
nrofproxies++;
IUnknown_AddRef(punk);
return S_OK;
}
/********************** StdMarshal implementation ****************************/
typedef struct _StdMarshalImpl {
ICOM_VTABLE(IMarshal) *lpvtbl;
DWORD ref;
IID iid;
DWORD dwDestContext;
LPVOID pvDestContext;
DWORD mshlflags;
} StdMarshalImpl;
HRESULT WINAPI
StdMarshalImpl_QueryInterface(LPMARSHAL iface,REFIID riid,LPVOID *ppv) {
*ppv = NULL;
if (IsEqualIID(&IID_IUnknown,riid) || IsEqualIID(&IID_IMarshal,riid)) {
*ppv = iface;
IUnknown_AddRef(iface);
return S_OK;
}
FIXME("No interface for %s.\n",debugstr_guid(riid));
return E_NOINTERFACE;
}
ULONG WINAPI
StdMarshalImpl_AddRef(LPMARSHAL iface) {
ICOM_THIS(StdMarshalImpl,iface);
This->ref++;
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;
}

View file

@ -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

496
dlls/ole32/oleproxy.c Normal file
View file

@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#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;
}

693
dlls/ole32/rpc.c Normal file
View file

@ -0,0 +1,693 @@
/*
* (Local) RPC Stuff
*
* Copyright 2002 Marcus Meissner
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#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;i<nrofpipes;i++)
if (pipes[i].mid.processid==mid->processid)
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;i<nrofpipes;i++)
if ((pipes[i].mid.processid==mid->processid) &&
(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;i<nrofpipes;i++) {
if ((pipes[i].mid.processid==mid->processid) &&
(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;i<nrofreqs;i++) { /* try to reuse */
if (reqs[i]->state == 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;i<nrofreqs;i++) {
xreq = reqs[i];
if ((xreq->state==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) {
hPipe = CreateFileA(
pipefn,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
-1
);
if (hPipe == INVALID_HANDLE_VALUE) {
if (tries == 1) {
if ((hres = create_server(rclsid)))
return hres;
Sleep(1000);
} else {
WARN("Could not open named pipe to broker %s, le is %lx\n",pipefn,GetLastError());
Sleep(1000);
}
continue;
}
bufferlen = 0;
if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
Sleep(1000);
continue;
}
CloseHandle(hPipe);
break;
}
if (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 */
}
}

View file

@ -21,6 +21,7 @@ C_SRCS = \
propertyframe.c \
safearray.c \
stubs.c \
tmarshal.c \
typelib.c \
variant.c

View file

@ -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;
}

View file

@ -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

1204
dlls/oleaut32/tmarshal.c Normal file

File diff suppressed because it is too large Load diff

6
dlls/oleaut32/tmarshal.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef TMARSHAL_H
#define TMARSHAL_H
HRESULT WINAPI
TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv);
#endif

View file

@ -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;

View file

@ -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--------------------------------------------*/

View file

@ -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;