- 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;
}
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;
BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
if (create)
{
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
apt->tid = GetCurrentThreadId();
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &apt->thread,
THREAD_ALL_ACCESS, FALSE, 0);
}
else
apt = NtCurrentTeb()->ReservedForOle;
apt->model = model;
apt->tid = GetCurrentThreadId();
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &apt->thread,
THREAD_ALL_ACCESS, FALSE, 0);
if (model & COINIT_APARTMENTTHREADED) {
/* FIXME: how does windoze create OXIDs? */
apt->oxid = MTA.oxid | GetCurrentThreadId();
@ -202,14 +213,17 @@ static APARTMENT* COM_CreateApartment(DWORD model)
0, 0, OLE32_hInstance, NULL);
InitializeCriticalSection(&apt->cs);
}
else {
else if (!(model & COINIT_UNINITIALIZED)) {
apt->parent = &MTA;
apt->oxid = MTA.oxid;
}
EnterCriticalSection(&csApartment);
if (apts) apts->prev = apt;
apt->next = apts;
apts = apt;
if (create)
{
if (apts) apts->prev = apt;
apt->next = apts;
apts = apt;
}
LeaveCriticalSection(&csApartment);
NtCurrentTeb()->ReservedForOle = apt;
return apt;
@ -384,8 +398,17 @@ HRESULT WINAPI CoInitializeEx(
}
apt = NtCurrentTeb()->ReservedForOle;
if (apt && dwCoInit != apt->model) return RPC_E_CHANGED_MODE;
hr = apt ? S_FALSE : S_OK;
if (apt && !(apt->model == COINIT_UNINITIALIZED))
{
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
@ -405,7 +428,7 @@ HRESULT WINAPI CoInitializeEx(
RunningObjectTableImpl_Initialize();
}
if (!apt) apt = COM_CreateApartment(dwCoInit);
if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit);
InterlockedIncrement(&apt->inits);
if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt;
@ -1861,7 +1884,6 @@ HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
return 0;
}
static IUnknown * pUnkState = 0; /* FIXME: thread local */
static int nStatCounter = 0; /* global */
static HMODULE hOleAut32 = 0; /* global */
@ -1872,11 +1894,13 @@ static HMODULE hOleAut32 = 0; /* global */
*/
HRESULT WINAPI CoGetState(IUnknown ** ppv)
{
APARTMENT * apt = COM_CurrentInfo();
FIXME("\n");
if(pUnkState) {
IUnknown_AddRef(pUnkState);
*ppv = pUnkState;
if(apt && apt->state) {
IUnknown_AddRef(apt->state);
*ppv = apt->state;
FIXME("-- %p\n", *ppv);
return S_OK;
}
@ -1892,6 +1916,10 @@ HRESULT WINAPI CoGetState(IUnknown ** ppv)
*/
HRESULT WINAPI CoSetState(IUnknown * pv)
{
APARTMENT * apt = COM_CurrentInfo();
if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
FIXME("(%p),stub!\n", pv);
if (pv) {
@ -1900,13 +1928,13 @@ HRESULT WINAPI CoSetState(IUnknown * pv)
if (nStatCounter == 1) LoadLibraryA("OLEAUT32.DLL");
}
if (pUnkState) {
TRACE("-- release %p now\n", pUnkState);
IUnknown_Release(pUnkState);
if (apt->state) {
TRACE("-- release %p now\n", apt->state);
IUnknown_Release(apt->state);
nStatCounter--;
if (!nStatCounter) FreeLibrary(hOleAut32);
}
pUnkState = pv;
apt->state = pv;
return S_OK;
}

View File

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

View File

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