mirror of
https://github.com/reactos/wine.git
synced 2024-11-28 22:20:26 +00:00
Invoke objects in STA's in the correct thread by sending messages to
the hidden apartment window.
This commit is contained in:
parent
35ae712600
commit
2ff1711487
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user