Commit 2ff17114 authored by Robert Shearman's avatar Robert Shearman Committed by Alexandre Julliard

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

the hidden apartment window.
parent 35ae7126
......@@ -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);
}
}
/*****************************************************************************
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment