- Make apartment access thread-safe by introducing refcounting and
wider usage of the apartment lock. - Rework OLE TLS management to eliminate uninitialised apartments and parent chaining.
This commit is contained in:
parent
a790b2d1c5
commit
a6a416cb4e
|
@ -30,6 +30,8 @@
|
||||||
* - Rewrite the CoLockObjectExternal code, it does totally the wrong
|
* - Rewrite the CoLockObjectExternal code, it does totally the wrong
|
||||||
* thing currently (should be controlling the stub manager)
|
* thing currently (should be controlling the stub manager)
|
||||||
*
|
*
|
||||||
|
* - Make the MTA dynamically allocated and refcounted
|
||||||
|
*
|
||||||
* - Implement the service control manager (in rpcss) to keep track
|
* - Implement the service control manager (in rpcss) to keep track
|
||||||
* of registered class objects: ISCM::ServerRegisterClsid et al
|
* of registered class objects: ISCM::ServerRegisterClsid et al
|
||||||
* - Implement the OXID resolver so we don't need magic pipe names for
|
* - Implement the OXID resolver so we don't need magic pipe names for
|
||||||
|
@ -99,7 +101,8 @@ static void COM_ExternalLockFreeList(void);
|
||||||
|
|
||||||
const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
|
const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
|
||||||
|
|
||||||
APARTMENT MTA, *apts;
|
APARTMENT MTA;
|
||||||
|
struct list apts = LIST_INIT( apts );
|
||||||
|
|
||||||
static CRITICAL_SECTION csApartment;
|
static CRITICAL_SECTION csApartment;
|
||||||
static CRITICAL_SECTION_DEBUG critsect_debug =
|
static CRITICAL_SECTION_DEBUG critsect_debug =
|
||||||
|
@ -236,6 +239,7 @@ static void COM_UninitMTA(void)
|
||||||
MTA.oxid = 0;
|
MTA.oxid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* creates an apartment structure which stores OLE thread-local
|
/* creates an apartment structure which stores OLE thread-local
|
||||||
* information. Call with COINIT_UNINITIALIZED to create an apartment
|
* information. Call with COINIT_UNINITIALIZED to create an apartment
|
||||||
* that will be initialized with a model later. Note: do not call
|
* that will be initialized with a model later. Note: do not call
|
||||||
|
@ -243,100 +247,138 @@ static void COM_UninitMTA(void)
|
||||||
* with a different COINIT value */
|
* with a different COINIT value */
|
||||||
APARTMENT* COM_CreateApartment(DWORD model)
|
APARTMENT* COM_CreateApartment(DWORD model)
|
||||||
{
|
{
|
||||||
APARTMENT *apt;
|
APARTMENT *apt = COM_CurrentApt();
|
||||||
BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
|
|
||||||
|
|
||||||
if (create)
|
if (!apt)
|
||||||
{
|
{
|
||||||
|
if (model & COINIT_MULTITHREADED)
|
||||||
|
{
|
||||||
|
TRACE("thread 0x%lx is entering the multithreaded apartment\n", GetCurrentThreadId());
|
||||||
|
COM_CurrentInfo()->apt = &MTA;
|
||||||
|
return apt;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("creating new apartment, model=%ld\n", model);
|
||||||
|
|
||||||
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
|
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
|
||||||
apt->tid = GetCurrentThreadId();
|
apt->tid = GetCurrentThreadId();
|
||||||
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
||||||
GetCurrentProcess(), &apt->thread,
|
GetCurrentProcess(), &apt->thread,
|
||||||
THREAD_ALL_ACCESS, FALSE, 0);
|
THREAD_ALL_ACCESS, FALSE, 0);
|
||||||
}
|
|
||||||
else
|
|
||||||
apt = NtCurrentTeb()->ReservedForOle;
|
|
||||||
|
|
||||||
list_init(&apt->proxies);
|
list_init(&apt->proxies);
|
||||||
list_init(&apt->stubmgrs);
|
list_init(&apt->stubmgrs);
|
||||||
apt->oidc = 1;
|
apt->oidc = 1;
|
||||||
|
apt->refs = 1;
|
||||||
apt->model = model;
|
InitializeCriticalSection(&apt->cs);
|
||||||
if (model & COINIT_APARTMENTTHREADED) {
|
|
||||||
/* FIXME: how does windoze create OXIDs? */
|
apt->model = model;
|
||||||
apt->oxid = MTA.oxid | GetCurrentThreadId();
|
|
||||||
apt->win = CreateWindowA(aptWinClass, NULL, 0,
|
/* we don't ref the apartment as CoInitializeEx will do it for us */
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 0, OLE32_hInstance, NULL);
|
if (model & COINIT_APARTMENTTHREADED)
|
||||||
InitializeCriticalSection(&apt->cs);
|
{
|
||||||
}
|
/* FIXME: how does windoze create OXIDs? */
|
||||||
else if (!(model & COINIT_UNINITIALIZED)) {
|
apt->oxid = MTA.oxid | GetCurrentThreadId();
|
||||||
apt->parent = &MTA;
|
apt->win = CreateWindowA(aptWinClass, NULL, 0,
|
||||||
apt->oxid = MTA.oxid;
|
0, 0, 0, 0,
|
||||||
|
0, 0, OLE32_hInstance, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection(&csApartment);
|
||||||
|
list_add_head(&apts, &apt->entry);
|
||||||
|
LeaveCriticalSection(&csApartment);
|
||||||
|
|
||||||
|
COM_CurrentInfo()->apt = apt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return apt;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD COM_ApartmentAddRef(struct apartment *apt)
|
||||||
|
{
|
||||||
|
return InterlockedIncrement(&apt->refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD COM_ApartmentRelease(struct apartment *apt)
|
||||||
|
{
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
EnterCriticalSection(&csApartment);
|
EnterCriticalSection(&csApartment);
|
||||||
if (create)
|
|
||||||
|
ret = InterlockedDecrement(&apt->refs);
|
||||||
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
if (apts) apts->prev = apt;
|
TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
|
||||||
apt->next = apts;
|
|
||||||
apts = apt;
|
MARSHAL_Disconnect_Proxies(apt);
|
||||||
|
|
||||||
|
list_remove(&apt->entry);
|
||||||
|
if ((apt->model & COINIT_APARTMENTTHREADED) && apt->win) DestroyWindow(apt->win);
|
||||||
|
|
||||||
|
if (!list_empty(&apt->stubmgrs))
|
||||||
|
{
|
||||||
|
FIXME("PANIC: Apartment being destroyed with outstanding stubs, what do we do now?\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apt->filter) IUnknown_Release(apt->filter);
|
||||||
|
|
||||||
|
|
||||||
|
DeleteCriticalSection(&apt->cs);
|
||||||
|
CloseHandle(apt->thread);
|
||||||
|
HeapFree(GetProcessHeap(), 0, apt);
|
||||||
|
|
||||||
|
apt = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&csApartment);
|
LeaveCriticalSection(&csApartment);
|
||||||
NtCurrentTeb()->ReservedForOle = apt;
|
|
||||||
return apt;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void COM_DestroyApartment(APARTMENT *apt)
|
/* The given OXID must be local to this process: you cannot use
|
||||||
|
* apartment windows to send RPCs to other processes. This all needs
|
||||||
|
* to move to rpcrt4.
|
||||||
|
*
|
||||||
|
* The ref parameter is here mostly to ensure people remember that
|
||||||
|
* they get one, you should normally take a ref for thread safety.
|
||||||
|
*/
|
||||||
|
APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
|
||||||
{
|
{
|
||||||
EnterCriticalSection(&csApartment);
|
APARTMENT *result = NULL;
|
||||||
if (apt->prev) apt->prev->next = apt->next;
|
struct list *cursor;
|
||||||
if (apt->next) apt->next->prev = apt->prev;
|
|
||||||
if (apts == apt) apts = apt->next;
|
|
||||||
apt->prev = NULL; apt->next = NULL;
|
|
||||||
LeaveCriticalSection(&csApartment);
|
|
||||||
if (apt->model & COINIT_APARTMENTTHREADED) {
|
|
||||||
/* disconnect proxies to release the corresponding stubs.
|
|
||||||
* It is confirmed in "Essential COM" in the sub-chapter on
|
|
||||||
* "Lifecycle Management and Marshalling" that the native version also
|
|
||||||
* disconnects proxies in this function. */
|
|
||||||
/* FIXME: this should also be called for MTA destruction, but that
|
|
||||||
* requires restructuring how apartments work slightly. */
|
|
||||||
MARSHAL_Disconnect_Proxies(apt);
|
|
||||||
|
|
||||||
if (apt->win) DestroyWindow(apt->win);
|
|
||||||
DeleteCriticalSection(&apt->cs);
|
|
||||||
}
|
|
||||||
CloseHandle(apt->thread);
|
|
||||||
HeapFree(GetProcessHeap(), 0, apt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The given OXID must be local to this process: you cannot use apartment
|
|
||||||
windows to send RPCs to other processes. This all needs to move to rpcrt4 */
|
|
||||||
|
|
||||||
APARTMENT *COM_ApartmentFromOXID(OXID oxid)
|
|
||||||
{
|
|
||||||
APARTMENT *apt = NULL;
|
|
||||||
|
|
||||||
EnterCriticalSection(&csApartment);
|
EnterCriticalSection(&csApartment);
|
||||||
apt = apts;
|
LIST_FOR_EACH( cursor, &apts )
|
||||||
while (apt && apt->oxid != oxid) apt = apt->next;
|
{
|
||||||
|
struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
|
||||||
|
if (apt->oxid == oxid)
|
||||||
|
{
|
||||||
|
result = apt;
|
||||||
|
if (ref) COM_ApartmentAddRef(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
LeaveCriticalSection(&csApartment);
|
LeaveCriticalSection(&csApartment);
|
||||||
|
|
||||||
return apt;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND COM_GetApartmentWin(OXID oxid)
|
HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
|
||||||
{
|
{
|
||||||
APARTMENT *apt = COM_ApartmentFromOXID(oxid);
|
APARTMENT *apt;
|
||||||
|
|
||||||
return apt ? apt->win : NULL;
|
apt = COM_ApartmentFromOXID(oxid, ref);
|
||||||
|
if (!apt) return NULL;
|
||||||
|
|
||||||
|
return apt->win;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Currently inter-thread marshalling is not fully implemented, so this does nothing */
|
/* 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)
|
static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
return DefWindowProcA(hWnd, msg, wParam, lParam);
|
return DefWindowProcA(hWnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* This section contains OpenDllList implemantation
|
* This section contains OpenDllList implemantation
|
||||||
|
@ -467,8 +509,7 @@ HRESULT WINAPI CoInitialize(
|
||||||
* CoUninitialize
|
* CoUninitialize
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI CoInitializeEx(
|
HRESULT WINAPI CoInitializeEx(
|
||||||
LPVOID lpReserved, /* [in] pointer to win32 malloc interface
|
LPVOID lpReserved, /* [in] pointer to win32 malloc interface (obsolete, should be NULL) */
|
||||||
(obsolete, should be NULL) */
|
|
||||||
DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
|
DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -482,21 +523,6 @@ HRESULT WINAPI CoInitializeEx(
|
||||||
ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
|
ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
apt = NtCurrentTeb()->ReservedForOle;
|
|
||||||
if (apt && !(apt->model == COINIT_UNINITIALIZED))
|
|
||||||
{
|
|
||||||
if (dwCoInit != apt->model)
|
|
||||||
{
|
|
||||||
/* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
|
|
||||||
code then we are probably using the wrong threading model to implement that API. */
|
|
||||||
ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
|
|
||||||
return RPC_E_CHANGED_MODE;
|
|
||||||
}
|
|
||||||
hr = S_FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
hr = S_OK;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the lock count. If this is the first time going through the initialize
|
* Check the lock count. If this is the first time going through the initialize
|
||||||
* process, we have to initialize the libraries.
|
* process, we have to initialize the libraries.
|
||||||
|
@ -512,13 +538,27 @@ HRESULT WINAPI CoInitializeEx(
|
||||||
|
|
||||||
COM_InitMTA();
|
COM_InitMTA();
|
||||||
|
|
||||||
|
/* we may need to defer this until after apartment initialisation */
|
||||||
RunningObjectTableImpl_Initialize();
|
RunningObjectTableImpl_Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
|
if (!(apt = COM_CurrentInfo()->apt))
|
||||||
|
{
|
||||||
|
apt = COM_CreateApartment(dwCoInit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&apt->refs);
|
||||||
|
}
|
||||||
|
|
||||||
InterlockedIncrement(&apt->inits);
|
if (dwCoInit != apt->model)
|
||||||
if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
|
{
|
||||||
|
/* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
|
||||||
|
code then we are probably using the wrong threading model to implement that API. */
|
||||||
|
ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
|
||||||
|
return RPC_E_CHANGED_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -529,14 +569,20 @@ HRESULT WINAPI CoInitializeEx(
|
||||||
void COM_FlushMessageQueue(void)
|
void COM_FlushMessageQueue(void)
|
||||||
{
|
{
|
||||||
MSG message;
|
MSG message;
|
||||||
APARTMENT *apt = NtCurrentTeb()->ReservedForOle;
|
APARTMENT *apt = COM_CurrentApt();
|
||||||
|
|
||||||
if (!apt || !apt->win) return;
|
if (!apt || !apt->win) return;
|
||||||
|
|
||||||
TRACE("Flushing STA message queue\n");
|
TRACE("Flushing STA message queue\n");
|
||||||
|
|
||||||
while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
|
while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
|
||||||
if (message.hwnd != apt->win) continue;
|
{
|
||||||
|
if (message.hwnd != apt->win)
|
||||||
|
{
|
||||||
|
WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
TranslateMessage(&message);
|
TranslateMessage(&message);
|
||||||
DispatchMessageA(&message);
|
DispatchMessageA(&message);
|
||||||
}
|
}
|
||||||
|
@ -561,17 +607,11 @@ void COM_FlushMessageQueue(void)
|
||||||
void WINAPI CoUninitialize(void)
|
void WINAPI CoUninitialize(void)
|
||||||
{
|
{
|
||||||
LONG lCOMRefCnt;
|
LONG lCOMRefCnt;
|
||||||
APARTMENT *apt;
|
|
||||||
|
|
||||||
TRACE("()\n");
|
TRACE("()\n");
|
||||||
|
|
||||||
apt = NtCurrentTeb()->ReservedForOle;
|
if (!COM_ApartmentRelease(COM_CurrentInfo()->apt))
|
||||||
if (!apt) return;
|
COM_CurrentInfo()->apt = NULL;
|
||||||
if (InterlockedDecrement(&apt->inits)==0) {
|
|
||||||
NtCurrentTeb()->ReservedForOle = NULL;
|
|
||||||
COM_DestroyApartment(apt);
|
|
||||||
apt = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decrease the reference count.
|
* Decrease the reference count.
|
||||||
|
@ -1134,14 +1174,14 @@ end:
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* CoRegisterClassObject [OLE32.@]
|
* CoRegisterClassObject [OLE32.@]
|
||||||
*
|
*
|
||||||
* Registers the class object for a given class ID. Servers housed in EXE
|
* Registers the class object for a given class ID. Servers housed in EXE
|
||||||
* files use this method instead of exporting DllGetClassObject to allow
|
* files use this method instead of exporting DllGetClassObject to allow
|
||||||
* other code to connect to their objects.
|
* other code to connect to their objects.
|
||||||
*
|
*
|
||||||
* RETURNS
|
* RETURNS
|
||||||
* S_OK on success,
|
* S_OK on success,
|
||||||
* E_INVALIDARG if lpdwRegister or pUnk are NULL,
|
* E_INVALIDARG if lpdwRegister or pUnk are NULL,
|
||||||
* CO_E_OBJISREG if the object is already registered. We should not return this.
|
* CO_E_OBJISREG if the object is already registered. We should not return this.
|
||||||
*
|
*
|
||||||
* SEE ALSO
|
* SEE ALSO
|
||||||
|
@ -1217,7 +1257,7 @@ HRESULT WINAPI CoRegisterClassObject(
|
||||||
if (dwClsContext & CLSCTX_LOCAL_SERVER) {
|
if (dwClsContext & CLSCTX_LOCAL_SERVER) {
|
||||||
IClassFactory *classfac;
|
IClassFactory *classfac;
|
||||||
|
|
||||||
hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
|
hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
|
||||||
(LPVOID*)&classfac);
|
(LPVOID*)&classfac);
|
||||||
if (hr) return hr;
|
if (hr) return hr;
|
||||||
|
|
||||||
|
@ -1556,7 +1596,7 @@ HRESULT WINAPI CoCreateInstance(
|
||||||
LPCLASSFACTORY lpclf = 0;
|
LPCLASSFACTORY lpclf = 0;
|
||||||
|
|
||||||
if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
|
if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sanity check
|
* Sanity check
|
||||||
*/
|
*/
|
||||||
|
@ -1573,15 +1613,15 @@ HRESULT WINAPI CoCreateInstance(
|
||||||
* Rather than create a class factory, we can just check for it here
|
* Rather than create a class factory, we can just check for it here
|
||||||
*/
|
*/
|
||||||
if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
|
if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
|
||||||
if (StdGlobalInterfaceTableInstance == NULL)
|
if (StdGlobalInterfaceTableInstance == NULL)
|
||||||
StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
|
StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
|
||||||
hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
|
hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
|
||||||
if (hres) return hres;
|
if (hres) return hres;
|
||||||
|
|
||||||
TRACE("Retrieved GIT (%p)\n", *ppv);
|
TRACE("Retrieved GIT (%p)\n", *ppv);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a class factory to construct the object we want.
|
* Get a class factory to construct the object we want.
|
||||||
*/
|
*/
|
||||||
|
@ -2000,19 +2040,19 @@ HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI CoGetState(IUnknown ** ppv)
|
HRESULT WINAPI CoGetState(IUnknown ** ppv)
|
||||||
{
|
{
|
||||||
APARTMENT * apt = COM_CurrentInfo();
|
HRESULT hr = E_FAIL;
|
||||||
|
|
||||||
FIXME("\n");
|
*ppv = NULL;
|
||||||
|
|
||||||
if(apt && apt->state) {
|
if (COM_CurrentInfo()->state)
|
||||||
IUnknown_AddRef(apt->state);
|
{
|
||||||
*ppv = apt->state;
|
IUnknown_AddRef(COM_CurrentInfo()->state);
|
||||||
FIXME("-- %p\n", *ppv);
|
*ppv = COM_CurrentInfo()->state;
|
||||||
return S_OK;
|
TRACE("apt->state=%p\n", COM_CurrentInfo()->state);
|
||||||
}
|
hr = S_OK;
|
||||||
*ppv = NULL;
|
}
|
||||||
return E_FAIL;
|
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
@ -2021,22 +2061,17 @@ HRESULT WINAPI CoGetState(IUnknown ** ppv)
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI CoSetState(IUnknown * pv)
|
HRESULT WINAPI CoSetState(IUnknown * pv)
|
||||||
{
|
{
|
||||||
APARTMENT * apt = COM_CurrentInfo();
|
if (pv) IUnknown_AddRef(pv);
|
||||||
|
|
||||||
if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
|
if (COM_CurrentInfo()->state)
|
||||||
|
{
|
||||||
|
TRACE("-- release %p now\n", COM_CurrentInfo()->state);
|
||||||
|
IUnknown_Release(COM_CurrentInfo()->state);
|
||||||
|
}
|
||||||
|
|
||||||
FIXME("(%p),stub!\n", pv);
|
COM_CurrentInfo()->state = pv;
|
||||||
|
|
||||||
if (pv) {
|
return S_OK;
|
||||||
IUnknown_AddRef(pv);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apt->state) {
|
|
||||||
TRACE("-- release %p now\n", apt->state);
|
|
||||||
IUnknown_Release(apt->state);
|
|
||||||
}
|
|
||||||
apt->state = pv;
|
|
||||||
return S_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2191,7 +2226,7 @@ HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
|
||||||
done:
|
done:
|
||||||
if (hkey) RegCloseKey(hkey);
|
if (hkey) RegCloseKey(hkey);
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
|
@ -38,12 +38,8 @@
|
||||||
#include "winreg.h"
|
#include "winreg.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
|
|
||||||
/* Windows maps COINIT values to 0x80 for apartment threaded, 0x140
|
struct apartment;
|
||||||
* for free threaded, and 0 for uninitialized apartments. There is
|
|
||||||
* no real advantage in us doing this and certainly no release version
|
|
||||||
* of an app should be poking around with these flags. So we need a
|
|
||||||
* special value for uninitialized */
|
|
||||||
#define COINIT_UNINITIALIZED 0x100
|
|
||||||
|
|
||||||
/* exported interface */
|
/* exported interface */
|
||||||
typedef struct tagXIF {
|
typedef struct tagXIF {
|
||||||
|
@ -59,7 +55,7 @@ typedef struct tagXIF {
|
||||||
/* exported object */
|
/* exported object */
|
||||||
typedef struct tagXOBJECT {
|
typedef struct tagXOBJECT {
|
||||||
IRpcStubBufferVtbl *lpVtbl;
|
IRpcStubBufferVtbl *lpVtbl;
|
||||||
struct tagAPARTMENT *parent;
|
struct apartment *parent;
|
||||||
struct tagXOBJECT *next;
|
struct tagXOBJECT *next;
|
||||||
LPUNKNOWN obj; /* object identity (IUnknown) */
|
LPUNKNOWN obj; /* object identity (IUnknown) */
|
||||||
OID oid; /* object ID */
|
OID oid; /* object ID */
|
||||||
|
@ -83,7 +79,7 @@ struct ifproxy
|
||||||
struct proxy_manager
|
struct proxy_manager
|
||||||
{
|
{
|
||||||
const IInternalUnknownVtbl *lpVtbl;
|
const IInternalUnknownVtbl *lpVtbl;
|
||||||
struct tagAPARTMENT *parent;
|
struct apartment *parent;
|
||||||
struct list entry;
|
struct list entry;
|
||||||
LPRPCCHANNELBUFFER chan; /* channel to object */
|
LPRPCCHANNELBUFFER chan; /* channel to object */
|
||||||
OXID oxid; /* object exported ID */
|
OXID oxid; /* object exported ID */
|
||||||
|
@ -93,11 +89,13 @@ struct proxy_manager
|
||||||
CRITICAL_SECTION cs; /* thread safety for this object and children */
|
CRITICAL_SECTION cs; /* thread safety for this object and children */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* apartment */
|
/* this needs to become a COM object that implements IRemUnknown */
|
||||||
typedef struct tagAPARTMENT {
|
struct apartment
|
||||||
struct tagAPARTMENT *next, *prev, *parent;
|
{
|
||||||
|
struct list entry;
|
||||||
|
|
||||||
|
DWORD refs; /* refcount of the apartment */
|
||||||
DWORD model; /* threading model */
|
DWORD model; /* threading model */
|
||||||
DWORD inits; /* CoInitialize count */
|
|
||||||
DWORD tid; /* thread id */
|
DWORD tid; /* thread id */
|
||||||
HANDLE thread; /* thread handle */
|
HANDLE thread; /* thread handle */
|
||||||
OXID oxid; /* object exporter ID */
|
OXID oxid; /* object exporter ID */
|
||||||
|
@ -107,13 +105,11 @@ typedef struct tagAPARTMENT {
|
||||||
LPMESSAGEFILTER filter; /* message filter */
|
LPMESSAGEFILTER filter; /* message filter */
|
||||||
XOBJECT *objs; /* exported objects */
|
XOBJECT *objs; /* exported objects */
|
||||||
struct list proxies; /* imported objects */
|
struct list proxies; /* imported objects */
|
||||||
LPUNKNOWN state; /* state object (see Co[Get,Set]State) */
|
|
||||||
LPVOID ErrorInfo; /* thread error info */
|
|
||||||
DWORD listenertid; /* id of apartment_listener_thread */
|
DWORD listenertid; /* id of apartment_listener_thread */
|
||||||
struct list stubmgrs; /* stub managers for exported objects */
|
struct list stubmgrs; /* stub managers for exported objects */
|
||||||
} APARTMENT;
|
};
|
||||||
|
|
||||||
extern APARTMENT MTA, *apts;
|
typedef struct apartment APARTMENT;
|
||||||
|
|
||||||
extern void* StdGlobalInterfaceTable_Construct(void);
|
extern void* StdGlobalInterfaceTable_Construct(void);
|
||||||
extern void StdGlobalInterfaceTable_Destroy(void* self);
|
extern void StdGlobalInterfaceTable_Destroy(void* self);
|
||||||
|
@ -196,26 +192,40 @@ int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
|
||||||
|
|
||||||
HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id);
|
HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id);
|
||||||
|
|
||||||
|
/* compobj.c */
|
||||||
|
APARTMENT *COM_CreateApartment(DWORD model);
|
||||||
|
APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref);
|
||||||
|
DWORD COM_ApartmentAddRef(struct apartment *apt);
|
||||||
|
DWORD COM_ApartmentRelease(struct apartment *apt);
|
||||||
|
|
||||||
|
extern CRITICAL_SECTION csApartment;
|
||||||
|
|
||||||
|
/* this is what is stored in TEB->ReservedForOle */
|
||||||
|
struct oletls
|
||||||
|
{
|
||||||
|
struct apartment *apt;
|
||||||
|
IErrorInfo *errorinfo; /* see errorinfo.c */
|
||||||
|
IUnknown *state; /* see CoSetState */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-thread values are stored in the TEB on offset 0xF80,
|
* Per-thread values are stored in the TEB on offset 0xF80,
|
||||||
* see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm
|
* see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm
|
||||||
*/
|
*/
|
||||||
static inline APARTMENT* COM_CurrentInfo(void)
|
|
||||||
|
/* will create if necessary */
|
||||||
|
static inline struct oletls *COM_CurrentInfo(void)
|
||||||
{
|
{
|
||||||
APARTMENT* apt = NtCurrentTeb()->ReservedForOle;
|
if (!NtCurrentTeb()->ReservedForOle)
|
||||||
return apt;
|
NtCurrentTeb()->ReservedForOle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct oletls));
|
||||||
}
|
|
||||||
static inline APARTMENT* COM_CurrentApt(void)
|
return NtCurrentTeb()->ReservedForOle;
|
||||||
{
|
|
||||||
APARTMENT* apt = COM_CurrentInfo();
|
|
||||||
if (apt && apt->parent) apt = apt->parent;
|
|
||||||
return apt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compobj.c */
|
static inline APARTMENT* COM_CurrentApt(void)
|
||||||
APARTMENT *COM_CreateApartment(DWORD model);
|
{
|
||||||
HWND COM_GetApartmentWin(OXID oxid);
|
return COM_CurrentInfo()->apt;
|
||||||
APARTMENT *COM_ApartmentFromOXID(OXID oxid);
|
}
|
||||||
|
|
||||||
#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
|
#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
* NOTES:
|
* NOTES:
|
||||||
*
|
*
|
||||||
* The errorinfo is a per-thread object. The reference is stored in the
|
* The errorinfo is a per-thread object. The reference is stored in the
|
||||||
* TEB at offset 0xf80
|
* TEB at offset 0xf80.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
@ -483,20 +483,20 @@ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo)
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
|
HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
|
||||||
{
|
{
|
||||||
APARTMENT * apt = COM_CurrentInfo();
|
TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo);
|
||||||
|
|
||||||
TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->ErrorInfo);
|
|
||||||
|
|
||||||
if(!pperrinfo) return E_INVALIDARG;
|
if(!pperrinfo) return E_INVALIDARG;
|
||||||
if (!apt || !apt->ErrorInfo)
|
|
||||||
|
if (!COM_CurrentInfo()->errorinfo)
|
||||||
{
|
{
|
||||||
*pperrinfo = NULL;
|
*pperrinfo = NULL;
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pperrinfo = (IErrorInfo*)(apt->ErrorInfo);
|
*pperrinfo = COM_CurrentInfo()->errorinfo;
|
||||||
|
|
||||||
/* clear thread error state */
|
/* clear thread error state */
|
||||||
apt->ErrorInfo = NULL;
|
COM_CurrentInfo()->errorinfo = NULL;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,18 +506,16 @@ HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
|
||||||
HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo)
|
HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo)
|
||||||
{
|
{
|
||||||
IErrorInfo * pei;
|
IErrorInfo * pei;
|
||||||
APARTMENT * apt = COM_CurrentInfo();
|
|
||||||
|
|
||||||
TRACE("(%ld, %p)\n", dwReserved, perrinfo);
|
TRACE("(%ld, %p)\n", dwReserved, perrinfo);
|
||||||
|
|
||||||
if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
|
|
||||||
|
|
||||||
/* release old errorinfo */
|
/* release old errorinfo */
|
||||||
pei = (IErrorInfo*)apt->ErrorInfo;
|
pei = COM_CurrentInfo()->errorinfo;
|
||||||
if(pei) IErrorInfo_Release(pei);
|
if (pei) IErrorInfo_Release(pei);
|
||||||
|
|
||||||
/* set to new value */
|
/* set to new value */
|
||||||
apt->ErrorInfo = perrinfo;
|
COM_CurrentInfo()->errorinfo = perrinfo;
|
||||||
if(perrinfo) IErrorInfo_AddRef(perrinfo);
|
if (perrinfo) IErrorInfo_AddRef(perrinfo);
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,9 +109,13 @@ static HRESULT register_ifstub(wine_marshal_id *mid, IUnknown *obj, IRpcStubBuff
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TRACE("constructing new stub manager\n");
|
struct apartment *apt;
|
||||||
|
|
||||||
manager = new_stub_manager(COM_ApartmentFromOXID(mid->oxid), obj);
|
TRACE("constructing new stub manager\n");
|
||||||
|
|
||||||
|
apt = COM_ApartmentFromOXID(mid->oxid, TRUE);
|
||||||
|
manager = new_stub_manager(apt, obj);
|
||||||
|
COM_ApartmentRelease(apt);
|
||||||
if (!manager) return E_OUTOFMEMORY;
|
if (!manager) return E_OUTOFMEMORY;
|
||||||
|
|
||||||
if (!tablemarshal) stub_manager_ref(manager, 1);
|
if (!tablemarshal) stub_manager_ref(manager, 1);
|
||||||
|
|
|
@ -308,8 +308,6 @@ PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
|
||||||
if (ref)
|
if (ref)
|
||||||
return ref;
|
return ref;
|
||||||
|
|
||||||
FIXME("Free all stuff\n");
|
|
||||||
|
|
||||||
memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id));
|
memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id));
|
||||||
|
|
||||||
pipe = PIPE_FindByMID(&This->mid);
|
pipe = PIPE_FindByMID(&This->mid);
|
||||||
|
@ -892,7 +890,7 @@ static DWORD WINAPI apartment_listener_thread(LPVOID param)
|
||||||
HANDLE listenPipe;
|
HANDLE listenPipe;
|
||||||
APARTMENT *apt = (APARTMENT *) param;
|
APARTMENT *apt = (APARTMENT *) param;
|
||||||
|
|
||||||
/* we must join the marshalling threads apartment */
|
/* we must join the marshalling threads apartment. we already have a ref here */
|
||||||
NtCurrentTeb()->ReservedForOle = apt;
|
NtCurrentTeb()->ReservedForOle = apt;
|
||||||
|
|
||||||
sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid));
|
sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid));
|
||||||
|
@ -926,7 +924,7 @@ static DWORD WINAPI apartment_listener_thread(LPVOID param)
|
||||||
void start_apartment_listener_thread()
|
void start_apartment_listener_thread()
|
||||||
{
|
{
|
||||||
APARTMENT *apt = COM_CurrentApt();
|
APARTMENT *apt = COM_CurrentApt();
|
||||||
|
|
||||||
assert( apt );
|
assert( apt );
|
||||||
|
|
||||||
TRACE("apt->listenertid=%ld\n", apt->listenertid);
|
TRACE("apt->listenertid=%ld\n", apt->listenertid);
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
||||||
|
|
||||||
|
/* this refs the apartment on success, otherwise there is no ref */
|
||||||
struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
|
struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
|
||||||
{
|
{
|
||||||
struct stub_manager *sm;
|
struct stub_manager *sm;
|
||||||
|
@ -71,6 +72,7 @@ struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
|
||||||
list_add_head(&apt->stubmgrs, &sm->entry);
|
list_add_head(&apt->stubmgrs, &sm->entry);
|
||||||
LeaveCriticalSection(&apt->cs);
|
LeaveCriticalSection(&apt->cs);
|
||||||
|
|
||||||
|
COM_ApartmentAddRef(apt);
|
||||||
TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object);
|
TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object);
|
||||||
|
|
||||||
return sm;
|
return sm;
|
||||||
|
@ -82,7 +84,7 @@ struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object)
|
||||||
struct list *cursor;
|
struct list *cursor;
|
||||||
APARTMENT *apt;
|
APARTMENT *apt;
|
||||||
|
|
||||||
if (!(apt = COM_ApartmentFromOXID(oxid)))
|
if (!(apt = COM_ApartmentFromOXID(oxid, TRUE)))
|
||||||
{
|
{
|
||||||
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
|
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -101,6 +103,8 @@ struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object)
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&apt->cs);
|
LeaveCriticalSection(&apt->cs);
|
||||||
|
|
||||||
|
COM_ApartmentRelease(apt);
|
||||||
|
|
||||||
TRACE("found %p from object %p\n", result, object);
|
TRACE("found %p from object %p\n", result, object);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -112,14 +116,13 @@ struct stub_manager *get_stub_manager(OXID oxid, OID oid)
|
||||||
struct list *cursor;
|
struct list *cursor;
|
||||||
APARTMENT *apt;
|
APARTMENT *apt;
|
||||||
|
|
||||||
if (!(apt = COM_ApartmentFromOXID(oxid)))
|
if (!(apt = COM_ApartmentFromOXID(oxid, TRUE)))
|
||||||
{
|
{
|
||||||
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
|
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnterCriticalSection(&apt->cs);
|
EnterCriticalSection(&apt->cs);
|
||||||
|
|
||||||
LIST_FOR_EACH( cursor, &apt->stubmgrs )
|
LIST_FOR_EACH( cursor, &apt->stubmgrs )
|
||||||
{
|
{
|
||||||
struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
|
struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
|
||||||
|
@ -130,9 +133,10 @@ struct stub_manager *get_stub_manager(OXID oxid, OID oid)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&apt->cs);
|
LeaveCriticalSection(&apt->cs);
|
||||||
|
|
||||||
|
COM_ApartmentRelease(apt);
|
||||||
|
|
||||||
TRACE("found %p from oid %s\n", result, wine_dbgstr_longlong(oid));
|
TRACE("found %p from oid %s\n", result, wine_dbgstr_longlong(oid));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
Loading…
Reference in New Issue