Invoke objects in STA's in the correct thread by sending messages to

the hidden apartment window.
This commit is contained in:
Robert Shearman 2005-02-14 11:50:51 +00:00 committed by Alexandre Julliard
parent 35ae712600
commit 2ff1711487
4 changed files with 57 additions and 24 deletions

View File

@ -34,8 +34,6 @@
* clients and servers to meet up
* - Flip our marshalling on top of the RPC runtime transport API,
* so we no longer use named pipes to communicate
* - Implement RPC thread affinity (should fix InstallShield painting
* problems)
*
* - Make all ole interface marshaling use NDR to be wire compatible with
* native DCOM
@ -163,7 +161,7 @@ static CRITICAL_SECTION_DEBUG dll_cs_debug =
};
static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
static const WCHAR wszAptWinClass[] = {'W','I','N','E','_','O','L','E','3','2','_','A','P','T','_','C','L','A','S','S',0};
static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
@ -171,7 +169,7 @@ static void COMPOBJ_DllList_FreeUnused(int Timeout);
void COMPOBJ_InitProcess( void )
{
WNDCLASSA wclass;
WNDCLASSW wclass;
/* Dispatching to the correct thread in an apartment is done through
* window messages rather than RPC transports. When an interface is
@ -183,15 +181,15 @@ void COMPOBJ_InitProcess( void )
* was unmarshalled.
*/
memset(&wclass, 0, sizeof(wclass));
wclass.lpfnWndProc = &COM_AptWndProc;
wclass.lpfnWndProc = COM_AptWndProc;
wclass.hInstance = OLE32_hInstance;
wclass.lpszClassName = aptWinClass;
RegisterClassA(&wclass);
wclass.lpszClassName = wszAptWinClass;
RegisterClassW(&wclass);
}
void COMPOBJ_UninitProcess( void )
{
UnregisterClassA(aptWinClass, OLE32_hInstance);
UnregisterClassW(wszAptWinClass, OLE32_hInstance);
}
void COM_TlsDestroy()
@ -239,7 +237,7 @@ static APARTMENT *apartment_construct(DWORD model)
{
/* FIXME: should be randomly generated by in an RPC call to rpcss */
apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
apt->win = CreateWindowA(aptWinClass, NULL, 0,
apt->win = CreateWindowW(wszAptWinClass, NULL, 0,
0, 0, 0, 0,
0, 0, OLE32_hInstance, NULL);
}
@ -425,10 +423,15 @@ HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
return apt->win;
}
/* Currently inter-thread marshalling is not fully implemented, so this does nothing */
static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProcA(hWnd, msg, wParam, lParam);
switch (msg)
{
case DM_EXECUTERPC:
return RPC_ExecuteCall((RPCOLEMESSAGE *)wParam, (IRpcStubBuffer *)lParam);
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
}
/*****************************************************************************

View File

@ -190,7 +190,7 @@ BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid);
BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid);
HRESULT register_ifstub(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags);
HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret);
IRpcStubBuffer *ipid_to_stubbuffer(const IPID *ipid);
IRpcStubBuffer *ipid_to_apt_and_stubbuffer(const IPID *ipid, APARTMENT **stub_apt);
HRESULT start_apartment_remote_unknown(void);
IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid);
@ -199,6 +199,7 @@ void start_apartment_listener_thread(void);
extern HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf);
void RPC_StartLocalServer(REFCLSID clsid, IStream *stream);
HRESULT RPC_ExecuteCall(RPCOLEMESSAGE *msg, IRpcStubBuffer *stub);
/* This function initialize the Running Object Table */
HRESULT WINAPI RunningObjectTableImpl_Initialize(void);
@ -215,6 +216,9 @@ APARTMENT *COM_ApartmentFromTID(DWORD tid);
DWORD COM_ApartmentAddRef(struct apartment *apt);
DWORD COM_ApartmentRelease(struct apartment *apt);
/* messages used by the apartment window (not compatible with native) */
#define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = (RPCOLEMESSAGE *), LPARAM = (IRpcStubBuffer *) */
/*
* Per-thread values are stored in the TEB on offset 0xF80,
* see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm

View File

@ -273,25 +273,48 @@ PipeBuf_GetBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid)
return S_OK;
}
HRESULT RPC_ExecuteCall(RPCOLEMESSAGE *msg, IRpcStubBuffer *stub)
{
return IRpcStubBuffer_Invoke(stub, msg, NULL);
}
static HRESULT
COM_InvokeAndRpcSend(struct rpc *req) {
IRpcStubBuffer *stub;
APARTMENT *apt;
RPCOLEMESSAGE msg;
HRESULT hres;
DWORD reqtype;
if (!(stub = ipid_to_stubbuffer(&(req->reqh.ipid))))
/* ipid_to_stubbuffer will already have logged the error */
return RPC_E_DISCONNECTED;
IUnknown_AddRef(stub);
memset(&msg, 0, sizeof(msg));
msg.Buffer = req->Buffer;
msg.iMethod = req->reqh.iMethod;
msg.cbBuffer = req->reqh.cbBuffer;
msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
req->state = REQSTATE_INVOKING;
req->resph.retval = IRpcStubBuffer_Invoke(stub,&msg,NULL);
IUnknown_Release(stub);
stub = ipid_to_apt_and_stubbuffer(&req->reqh.ipid, &apt);
if (!apt)
/* ipid_to_apt_and_stubbuffer will already have logged the error */
return RPC_E_DISCONNECTED;
if (!stub)
{
/* ipid_to_apt_and_stubbuffer will already have logged the error */
COM_ApartmentRelease(apt);
return RPC_E_DISCONNECTED;
}
/* Note: this is the important difference between STAs and MTAs - we
* always execute RPCs to STAs in the thread that originally created the
* apartment (i.e. the one that pumps messages to the window) */
if (apt->model & COINIT_APARTMENTTHREADED)
req->resph.retval = SendMessageW(apt->win, DM_EXECUTERPC, (WPARAM)&msg, (LPARAM)stub);
else
req->resph.retval = RPC_ExecuteCall(&msg, stub);
COM_ApartmentRelease(apt);
IRpcStubBuffer_Release(stub);
req->Buffer = msg.Buffer;
req->resph.cbBuffer = msg.cbBuffer;
reqtype = REQTYPE_RESPONSE;

View File

@ -321,24 +321,27 @@ HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub
return S_OK;
}
IRpcStubBuffer *ipid_to_stubbuffer(const IPID *ipid)
/* gets the apartment and IRpcStubBuffer from an object. the caller must
* release the references to both objects */
IRpcStubBuffer *ipid_to_apt_and_stubbuffer(const IPID *ipid, APARTMENT **stub_apt)
{
IRpcStubBuffer *ret = NULL;
APARTMENT *apt;
struct stub_manager *stubmgr;
struct ifstub *ifstub;
HRESULT hr;
hr = ipid_to_stub_manager(ipid, &apt, &stubmgr);
*stub_apt = NULL;
hr = ipid_to_stub_manager(ipid, stub_apt, &stubmgr);
if (hr != S_OK) return NULL;
ifstub = stub_manager_ipid_to_ifstub(stubmgr, ipid);
if (ifstub)
ret = ifstub->stubbuffer;
stub_manager_int_release(stubmgr);
if (ret) IRpcStubBuffer_AddRef(ret);
COM_ApartmentRelease(apt);
stub_manager_int_release(stubmgr);
return ret;
}