Implement COM local servers using table marshaling to avoid doing the
marshaling in a child thread where COM has not been initialized.
This commit is contained in:
parent
5475a2e617
commit
2b747d4e50
@ -101,8 +101,7 @@ typedef struct tagRegisteredClass
|
|||||||
DWORD runContext;
|
DWORD runContext;
|
||||||
DWORD connectFlags;
|
DWORD connectFlags;
|
||||||
DWORD dwCookie;
|
DWORD dwCookie;
|
||||||
HANDLE hThread; /* only for localserver */
|
LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
|
||||||
APARTMENT *apt; /* owning apartment */
|
|
||||||
struct tagRegisteredClass* nextClass;
|
struct tagRegisteredClass* nextClass;
|
||||||
} RegisteredClass;
|
} RegisteredClass;
|
||||||
|
|
||||||
@ -1101,116 +1100,12 @@ end:
|
|||||||
return hr;
|
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 classfactory server thread for %s.\n",debugstr_guid(&newClass->classIdentifier));
|
|
||||||
|
|
||||||
/* we need to enter the apartment of the thread which registered
|
|
||||||
* the class object to perform the next stage
|
|
||||||
*/
|
|
||||||
|
|
||||||
assert( newClass->apt );
|
|
||||||
NtCurrentTeb()->ReservedForOle = newClass->apt;
|
|
||||||
|
|
||||||
strcpy(pipefn,PIPEPREF);
|
|
||||||
WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF));
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
while (1) {
|
|
||||||
if (!ConnectNamedPipe(hPipe,NULL)) {
|
|
||||||
ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("marshalling IClassFactory to client\n");
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
IUnknown_Release(classfac); /* is this right? */
|
|
||||||
|
|
||||||
hres = IStream_Stat(pStm,&ststg,0);
|
|
||||||
if (hres) return hres;
|
|
||||||
|
|
||||||
buflen = ststg.cbSize.u.LowPart;
|
|
||||||
buffer = HeapAlloc(GetProcessHeap(),0,buflen);
|
|
||||||
seekto.u.LowPart = 0;
|
|
||||||
seekto.u.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);
|
|
||||||
|
|
||||||
WriteFile(hPipe,buffer,buflen,&res,NULL);
|
|
||||||
FlushFileBuffers(hPipe);
|
|
||||||
DisconnectNamedPipe(hPipe);
|
|
||||||
|
|
||||||
TRACE("done marshalling IClassFactory\n");
|
|
||||||
}
|
|
||||||
CloseHandle(hPipe);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* CoRegisterClassObject [OLE32.@]
|
* CoRegisterClassObject [OLE32.@]
|
||||||
*
|
*
|
||||||
* This method will register the class object for a given class
|
* Registers the class object for a given class ID. Servers housed in EXE
|
||||||
* ID. Servers housed in EXE files use this method instead of
|
* files use this method instead of exporting DllGetClassObject to allow
|
||||||
* exporting DllGetClassObject to allow other code to connect to their
|
* other code to connect to their objects.
|
||||||
* objects.
|
|
||||||
*
|
|
||||||
* When a class object (an object which implements IClassFactory) is
|
|
||||||
* registered in this way, a new thread is started which listens for
|
|
||||||
* connections on a named pipe specific to the registered CLSID. When
|
|
||||||
* something else connects to it, it writes out the marshalled
|
|
||||||
* IClassFactory interface to the pipe. The code on the other end uses
|
|
||||||
* this buffer to unmarshal the class factory, and can then call
|
|
||||||
* methods on it.
|
|
||||||
*
|
|
||||||
* In Windows, such objects are registered with the RPC endpoint
|
|
||||||
* mapper, not with a unique named pipe.
|
|
||||||
*
|
|
||||||
* MSDN claims that multiple interface registrations are legal, but we
|
|
||||||
* can't do that with our current implementation.
|
|
||||||
*
|
*
|
||||||
* RETURNS
|
* RETURNS
|
||||||
* S_OK on success,
|
* S_OK on success,
|
||||||
@ -1219,6 +1114,10 @@ _LocalServerThread(LPVOID param) {
|
|||||||
*
|
*
|
||||||
* SEE ALSO
|
* SEE ALSO
|
||||||
* CoRevokeClassObject, CoGetClassObject
|
* CoRevokeClassObject, CoGetClassObject
|
||||||
|
*
|
||||||
|
* BUGS
|
||||||
|
* MSDN claims that multiple interface registrations are legal, but we
|
||||||
|
* can't do that with our current implementation.
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI CoRegisterClassObject(
|
HRESULT WINAPI CoRegisterClassObject(
|
||||||
REFCLSID rclsid, /* [in] CLSID of the object to register */
|
REFCLSID rclsid, /* [in] CLSID of the object to register */
|
||||||
@ -1264,10 +1163,9 @@ HRESULT WINAPI CoRegisterClassObject(
|
|||||||
newClass->classIdentifier = *rclsid;
|
newClass->classIdentifier = *rclsid;
|
||||||
newClass->runContext = dwClsContext;
|
newClass->runContext = dwClsContext;
|
||||||
newClass->connectFlags = flags;
|
newClass->connectFlags = flags;
|
||||||
newClass->apt = COM_CurrentApt();
|
|
||||||
/*
|
/*
|
||||||
* Use the address of the chain node as the cookie since we are sure it's
|
* Use the address of the chain node as the cookie since we are sure it's
|
||||||
* unique.
|
* unique. FIXME: not on 64-bit platforms.
|
||||||
*/
|
*/
|
||||||
newClass->dwCookie = (DWORD)newClass;
|
newClass->dwCookie = (DWORD)newClass;
|
||||||
newClass->nextClass = firstRegisteredClass;
|
newClass->nextClass = firstRegisteredClass;
|
||||||
@ -1285,10 +1183,30 @@ HRESULT WINAPI CoRegisterClassObject(
|
|||||||
*lpdwRegister = newClass->dwCookie;
|
*lpdwRegister = newClass->dwCookie;
|
||||||
|
|
||||||
if (dwClsContext & CLSCTX_LOCAL_SERVER) {
|
if (dwClsContext & CLSCTX_LOCAL_SERVER) {
|
||||||
DWORD tid;
|
IClassFactory *classfac;
|
||||||
|
|
||||||
start_apartment_listener_thread();
|
hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
|
||||||
newClass->hThread = CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid);
|
(LPVOID*)&classfac);
|
||||||
|
if (hr) return hr;
|
||||||
|
|
||||||
|
hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
|
||||||
|
if (hr) {
|
||||||
|
FIXME("Failed to create stream on hglobal, %lx\n", hr);
|
||||||
|
IUnknown_Release(classfac);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
|
||||||
|
(LPVOID)classfac, MSHCTX_LOCAL, NULL,
|
||||||
|
MSHLFLAGS_TABLESTRONG);
|
||||||
|
if (hr) {
|
||||||
|
FIXME("CoMarshalInterface failed, %lx!\n",hr);
|
||||||
|
IUnknown_Release(classfac);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IUnknown_Release(classfac);
|
||||||
|
|
||||||
|
RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
|
||||||
}
|
}
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
@ -1334,6 +1252,15 @@ HRESULT WINAPI CoRevokeClassObject(
|
|||||||
*/
|
*/
|
||||||
IUnknown_Release(curClass->classObject);
|
IUnknown_Release(curClass->classObject);
|
||||||
|
|
||||||
|
if (curClass->pMarshaledData)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER zero;
|
||||||
|
memset(&zero, 0, sizeof(zero));
|
||||||
|
/* FIXME: stop local server thread */
|
||||||
|
IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
|
||||||
|
CoReleaseMarshalData(curClass->pMarshaledData);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the memory used by the chain node.
|
* Free the memory used by the chain node.
|
||||||
*/
|
*/
|
||||||
|
@ -194,6 +194,7 @@ IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid);
|
|||||||
void start_apartment_listener_thread(void);
|
void start_apartment_listener_thread(void);
|
||||||
|
|
||||||
extern HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf);
|
extern HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf);
|
||||||
|
void RPC_StartLocalServer(REFCLSID clsid, IStream *stream);
|
||||||
|
|
||||||
/* This function initialize the Running Object Table */
|
/* This function initialize the Running Object Table */
|
||||||
HRESULT WINAPI RunningObjectTableImpl_Initialize(void);
|
HRESULT WINAPI RunningObjectTableImpl_Initialize(void);
|
||||||
|
@ -829,3 +829,90 @@ void start_apartment_listener_thread()
|
|||||||
CreateThread(NULL, 0, apartment_listener_thread, apt, 0, &apt->listenertid);
|
CreateThread(NULL, 0, apartment_listener_thread, apt, 0, &apt->listenertid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct local_server_params
|
||||||
|
{
|
||||||
|
CLSID clsid;
|
||||||
|
IStream *stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
static DWORD WINAPI local_server_thread(LPVOID param)
|
||||||
|
{
|
||||||
|
struct local_server_params * lsp = (struct local_server_params *)param;
|
||||||
|
HANDLE hPipe;
|
||||||
|
char pipefn[200];
|
||||||
|
HRESULT hres;
|
||||||
|
IStream *pStm = lsp->stream;
|
||||||
|
STATSTG ststg;
|
||||||
|
unsigned char *buffer;
|
||||||
|
int buflen;
|
||||||
|
LARGE_INTEGER seekto;
|
||||||
|
ULARGE_INTEGER newpos;
|
||||||
|
ULONG res;
|
||||||
|
|
||||||
|
TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
|
||||||
|
|
||||||
|
strcpy(pipefn,PIPEPREF);
|
||||||
|
WINE_StringFromCLSID(&lsp->clsid,pipefn+strlen(PIPEPREF));
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, lsp);
|
||||||
|
|
||||||
|
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 %ld\n",pipefn,GetLastError());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
if (!ConnectNamedPipe(hPipe,NULL)) {
|
||||||
|
ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("marshalling IClassFactory to client\n");
|
||||||
|
|
||||||
|
hres = IStream_Stat(pStm,&ststg,0);
|
||||||
|
if (hres) return hres;
|
||||||
|
|
||||||
|
buflen = ststg.cbSize.u.LowPart;
|
||||||
|
buffer = HeapAlloc(GetProcessHeap(),0,buflen);
|
||||||
|
seekto.u.LowPart = 0;
|
||||||
|
seekto.u.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);
|
||||||
|
|
||||||
|
WriteFile(hPipe,buffer,buflen,&res,NULL);
|
||||||
|
FlushFileBuffers(hPipe);
|
||||||
|
DisconnectNamedPipe(hPipe);
|
||||||
|
|
||||||
|
TRACE("done marshalling IClassFactory\n");
|
||||||
|
}
|
||||||
|
CloseHandle(hPipe);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC_StartLocalServer(REFCLSID clsid, IStream *stream)
|
||||||
|
{
|
||||||
|
DWORD tid;
|
||||||
|
HANDLE thread;
|
||||||
|
struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
|
||||||
|
|
||||||
|
lsp->clsid = *clsid;
|
||||||
|
lsp->stream = stream;
|
||||||
|
|
||||||
|
thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
|
||||||
|
CloseHandle(thread);
|
||||||
|
/* FIXME: failure handling */
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user