- CoSetState info should be thread local.

- SetErrorInfo should allocate an apartment when no apartment present.
This commit is contained in:
Robert Shearman 2004-02-10 01:36:20 +00:00 committed by Alexandre Julliard
parent 9d956b2395
commit 2eee76703d
3 changed files with 76 additions and 28 deletions

View File

@ -184,16 +184,27 @@ static void COM_UninitMTA(void)
MTA.oxid = 0; MTA.oxid = 0;
} }
static APARTMENT* COM_CreateApartment(DWORD model) /* creates an apartment structure which stores OLE thread-local
* information. Call with COINIT_UNINITIALIZED to create an apartment
* that will be initialized with a model later. Note: do not call
* with COINIT_UNINITIALIZED if the apartment has already been initialized
* with a different COINIT value */
APARTMENT* COM_CreateApartment(DWORD model)
{ {
APARTMENT *apt; APARTMENT *apt;
BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
if (create)
{
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT)); apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
apt->model = model;
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;
apt->model = model;
if (model & COINIT_APARTMENTTHREADED) { if (model & COINIT_APARTMENTTHREADED) {
/* FIXME: how does windoze create OXIDs? */ /* FIXME: how does windoze create OXIDs? */
apt->oxid = MTA.oxid | GetCurrentThreadId(); apt->oxid = MTA.oxid | GetCurrentThreadId();
@ -202,14 +213,17 @@ static APARTMENT* COM_CreateApartment(DWORD model)
0, 0, OLE32_hInstance, NULL); 0, 0, OLE32_hInstance, NULL);
InitializeCriticalSection(&apt->cs); InitializeCriticalSection(&apt->cs);
} }
else { else if (!(model & COINIT_UNINITIALIZED)) {
apt->parent = &MTA; apt->parent = &MTA;
apt->oxid = MTA.oxid; apt->oxid = MTA.oxid;
} }
EnterCriticalSection(&csApartment); EnterCriticalSection(&csApartment);
if (create)
{
if (apts) apts->prev = apt; if (apts) apts->prev = apt;
apt->next = apts; apt->next = apts;
apts = apt; apts = apt;
}
LeaveCriticalSection(&csApartment); LeaveCriticalSection(&csApartment);
NtCurrentTeb()->ReservedForOle = apt; NtCurrentTeb()->ReservedForOle = apt;
return apt; return apt;
@ -384,8 +398,17 @@ HRESULT WINAPI CoInitializeEx(
} }
apt = NtCurrentTeb()->ReservedForOle; apt = NtCurrentTeb()->ReservedForOle;
if (apt && dwCoInit != apt->model) return RPC_E_CHANGED_MODE; if (apt && !(apt->model == COINIT_UNINITIALIZED))
hr = apt ? S_FALSE : S_OK; {
if (dwCoInit != apt->model)
{
WARN("Apartment threading model already initialized with another model\n");
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
@ -405,7 +428,7 @@ HRESULT WINAPI CoInitializeEx(
RunningObjectTableImpl_Initialize(); RunningObjectTableImpl_Initialize();
} }
if (!apt) apt = COM_CreateApartment(dwCoInit); if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
InterlockedIncrement(&apt->inits); InterlockedIncrement(&apt->inits);
if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt; if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
@ -1861,7 +1884,6 @@ HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
return 0; return 0;
} }
static IUnknown * pUnkState = 0; /* FIXME: thread local */
static int nStatCounter = 0; /* global */ static int nStatCounter = 0; /* global */
static HMODULE hOleAut32 = 0; /* global */ static HMODULE hOleAut32 = 0; /* global */
@ -1872,11 +1894,13 @@ static HMODULE hOleAut32 = 0; /* global */
*/ */
HRESULT WINAPI CoGetState(IUnknown ** ppv) HRESULT WINAPI CoGetState(IUnknown ** ppv)
{ {
APARTMENT * apt = COM_CurrentInfo();
FIXME("\n"); FIXME("\n");
if(pUnkState) { if(apt && apt->state) {
IUnknown_AddRef(pUnkState); IUnknown_AddRef(apt->state);
*ppv = pUnkState; *ppv = apt->state;
FIXME("-- %p\n", *ppv); FIXME("-- %p\n", *ppv);
return S_OK; return S_OK;
} }
@ -1892,6 +1916,10 @@ HRESULT WINAPI CoGetState(IUnknown ** ppv)
*/ */
HRESULT WINAPI CoSetState(IUnknown * pv) HRESULT WINAPI CoSetState(IUnknown * pv)
{ {
APARTMENT * apt = COM_CurrentInfo();
if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
FIXME("(%p),stub!\n", pv); FIXME("(%p),stub!\n", pv);
if (pv) { if (pv) {
@ -1900,13 +1928,13 @@ HRESULT WINAPI CoSetState(IUnknown * pv)
if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL"); if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
} }
if (pUnkState) { if (apt->state) {
TRACE("-- release %p now\n", pUnkState); TRACE("-- release %p now\n", apt->state);
IUnknown_Release(pUnkState); IUnknown_Release(apt->state);
nStatCounter--; nStatCounter--;
if (!nStatCounter) FreeLibrary(hOleAut32); if (!nStatCounter) FreeLibrary(hOleAut32);
} }
pUnkState = pv; apt->state = pv;
return S_OK; return S_OK;
} }

View File

@ -35,6 +35,13 @@
#include "winreg.h" #include "winreg.h"
#include "winternl.h" #include "winternl.h"
/* Windows maps COINIT values to 0x80 for apartment threaded, 0x140
* 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 {
struct tagXIF *next; struct tagXIF *next;
@ -96,6 +103,7 @@ typedef struct tagAPARTMENT {
LPMESSAGEFILTER filter; /* message filter */ LPMESSAGEFILTER filter; /* message filter */
XOBJECT *objs; /* exported objects */ XOBJECT *objs; /* exported objects */
IOBJECT *proxies; /* imported objects */ IOBJECT *proxies; /* imported objects */
LPUNKNOWN state; /* state object (see Co[Get,Set]State) */
LPVOID ErrorInfo; /* thread error info */ LPVOID ErrorInfo; /* thread error info */
} APARTMENT; } APARTMENT;
@ -217,6 +225,7 @@ static inline APARTMENT* COM_CurrentApt(void)
} }
/* compobj.c */ /* compobj.c */
APARTMENT* COM_CreateApartment(DWORD model);
HWND COM_GetApartmentWin(OXID oxid); HWND COM_GetApartmentWin(OXID oxid);
#endif /* __WINE_OLE_COMPOBJ_H */ #endif /* __WINE_OLE_COMPOBJ_H */

View File

@ -484,13 +484,20 @@ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo)
*/ */
HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo) HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
{ {
TRACE("(%ld, %p, %p): stub:\n", dwReserved, pperrinfo, COM_CurrentInfo()->ErrorInfo); APARTMENT * apt = COM_CurrentInfo();
if(! pperrinfo ) return E_INVALIDARG; TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->ErrorInfo);
if(!(*pperrinfo = (IErrorInfo*)(COM_CurrentInfo()->ErrorInfo))) return S_FALSE;
if(!pperrinfo) return E_INVALIDARG;
if (!apt || !apt->ErrorInfo)
{
*pperrinfo = NULL;
return S_FALSE;
}
*pperrinfo = (IErrorInfo*)(apt->ErrorInfo);
/* clear thread error state */ /* clear thread error state */
COM_CurrentInfo()->ErrorInfo = NULL; apt->ErrorInfo = NULL;
return S_OK; return S_OK;
} }
@ -500,14 +507,18 @@ 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;
TRACE("(%ld, %p): stub:\n", dwReserved, perrinfo); APARTMENT * apt = COM_CurrentInfo();
TRACE("(%ld, %p)\n", dwReserved, perrinfo);
if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
/* release old errorinfo */ /* release old errorinfo */
pei = (IErrorInfo*)COM_CurrentInfo()->ErrorInfo; pei = (IErrorInfo*)apt->ErrorInfo;
if(pei) IErrorInfo_Release(pei); if(pei) IErrorInfo_Release(pei);
/* set to new value */ /* set to new value */
COM_CurrentInfo()->ErrorInfo = perrinfo; apt->ErrorInfo = perrinfo;
if(perrinfo) IErrorInfo_AddRef(perrinfo); if(perrinfo) IErrorInfo_AddRef(perrinfo);
return S_OK; return S_OK;
} }