Preliminary support for COM apartments.

This commit is contained in:
Ove Kaaven 2003-06-04 20:11:34 +00:00 committed by Alexandre Julliard
parent 350aa2dcc4
commit ef57c4d905
3 changed files with 217 additions and 66 deletions

View File

@ -31,7 +31,8 @@
#define NONAMELESSUNION #define NONAMELESSUNION
#define NONAMELESSSTRUCT #define NONAMELESSSTRUCT
#include "windef.h" #include "winbase.h"
#include "winuser.h"
#include "objbase.h" #include "objbase.h"
#include "ole2.h" #include "ole2.h"
#include "ole2ver.h" #include "ole2ver.h"
@ -41,6 +42,7 @@
#include "wownt32.h" #include "wownt32.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "objbase.h" #include "objbase.h"
#include "ole32_main.h"
#include "compobj_private.h" #include "compobj_private.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -62,45 +64,8 @@ const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0,
static void* StdGlobalInterfaceTableInstance; static void* StdGlobalInterfaceTableInstance;
/***************************************************************************** APARTMENT MTA, *apts;
* Apartment management stuff static CRITICAL_SECTION csApartment = CRITICAL_SECTION_INIT("csApartment");
*
* NOTE:
* per Thread values are stored in the TEB on offset 0xF80
*
* see www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm
*
*/
typedef struct {
unsigned char threadingModell; /* we use the COINIT flags */
unsigned long threadID;
long ApartmentLockCount;
} OleApartmentData;
typedef struct {
OleApartmentData *ApartmentData;
} OleThreadData;
/* not jet used
static CRITICAL_SECTION csApartmentData = CRITICAL_SECTION_INIT("csApartmentData");
*/
/*
* the first STA created in a process is the main STA
*/
/* not jet used
static OleApartmentData * mainSTA;
*/
/*
* a Process can only have one MTA
*/
/* not jet used
static OleApartmentData * processMTA;
*/
/* /*
* This lock count counts the number of times CoInitialize is called. It is * This lock count counts the number of times CoInitialize is called. It is
@ -150,21 +115,114 @@ typedef struct tagOpenDll {
static CRITICAL_SECTION csOpenDllList = CRITICAL_SECTION_INIT("csOpenDllList"); static CRITICAL_SECTION csOpenDllList = CRITICAL_SECTION_INIT("csOpenDllList");
static OpenDll *openDllList = NULL; /* linked list of open dlls */ static OpenDll *openDllList = NULL; /* linked list of open dlls */
static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static void COMPOBJ_DLLList_Add(HANDLE hLibrary); static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
static void COMPOBJ_DllList_FreeUnused(int Timeout); static void COMPOBJ_DllList_FreeUnused(int Timeout);
/****************************************************************************** /******************************************************************************
* Initialize/Uninitialize critical sections. * Initialize/Unitialize threading stuff.
*/ */
void COMPOBJ_InitProcess( void ) void COMPOBJ_InitProcess( void )
{ {
WNDCLASSA wclass;
memset(&wclass, 0, sizeof(wclass));
wclass.lpfnWndProc = &COM_AptWndProc;
wclass.hInstance = OLE32_hInstance;
wclass.lpszClassName = aptWinClass;
RegisterClassA(&wclass);
} }
void COMPOBJ_UninitProcess( void ) void COMPOBJ_UninitProcess( void )
{ {
UnregisterClassA(aptWinClass, OLE32_hInstance);
} }
/******************************************************************************
* Manage apartments.
*/
static void COM_InitMTA(void)
{
/* FIXME: how does windoze create OXIDs?
* this method will only work for local RPC */
MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
InitializeCriticalSection(&MTA.cs);
}
static void COM_UninitMTA(void)
{
DeleteCriticalSection(&MTA.cs);
MTA.oxid = 0;
}
static APARTMENT* COM_CreateApartment(DWORD model)
{
APARTMENT *apt;
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
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();
apt->win = CreateWindowA(aptWinClass, NULL, 0,
0, 0, 0, 0,
0, 0, OLE32_hInstance, NULL);
InitializeCriticalSection(&apt->cs);
}
else {
apt->parent = &MTA;
apt->oxid = MTA.oxid;
}
EnterCriticalSection(&csApartment);
if (apts) apts->prev = apt;
apt->next = apts;
apts = apt;
LeaveCriticalSection(&csApartment);
NtCurrentTeb()->ErrorInfo = apt;
return apt;
}
static void COM_DestroyApartment(APARTMENT *apt)
{
EnterCriticalSection(&csApartment);
if (apt->prev) apt->prev->next = apt->next;
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) {
if (apt->win) DestroyWindow(apt->win);
DeleteCriticalSection(&apt->cs);
}
CloseHandle(apt->thread);
HeapFree(GetProcessHeap(), 0, apt);
}
HWND COM_GetApartmentWin(OXID oxid)
{
APARTMENT *apt;
HWND win = 0;
EnterCriticalSection(&csApartment);
apt = apts;
while (apt && apt->oxid != oxid) apt = apt->next;
if (apt) win = apt->win;
LeaveCriticalSection(&csApartment);
return win;
}
static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProcA(hWnd, msg, wParam, lParam);
}
/***************************************************************************** /*****************************************************************************
* This section contains OpenDllList implemantation * This section contains OpenDllList implemantation
*/ */
@ -282,12 +340,6 @@ HRESULT WINAPI CoInitialize(
* S_FALSE if this function was called already. * S_FALSE if this function was called already.
* RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another * RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
* threading model. * threading model.
*
* BUGS
* Only the single threaded model is supported. As a result RPC_E_CHANGED_MODE
* is never returned.
*
* See the windows documentation for more details.
*/ */
HRESULT WINAPI CoInitializeEx( HRESULT WINAPI CoInitializeEx(
LPVOID lpReserved, /* [in] pointer to win32 malloc interface LPVOID lpReserved, /* [in] pointer to win32 malloc interface
@ -295,7 +347,8 @@ HRESULT WINAPI CoInitializeEx(
DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */ DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
) )
{ {
HRESULT hr; HRESULT hr = S_OK;
APARTMENT *apt;
TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit); TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
@ -304,14 +357,9 @@ 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()->ErrorInfo;
* Check for unsupported features. if (apt && dwCoInit != apt->model) return RPC_E_CHANGED_MODE;
*/ hr = apt ? S_FALSE : S_OK;
if (dwCoInit!=COINIT_APARTMENTTHREADED)
{
FIXME(":(%p,%x): unsupported flag %x\n", lpReserved, (int)dwCoInit, (int)dwCoInit);
/* Hope for the best and continue anyway */
}
/* /*
* 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
@ -326,13 +374,15 @@ HRESULT WINAPI CoInitializeEx(
*/ */
TRACE("() - Initializing the COM libraries\n"); TRACE("() - Initializing the COM libraries\n");
COM_InitMTA();
RunningObjectTableImpl_Initialize(); RunningObjectTableImpl_Initialize();
hr = S_OK;
} }
else
hr = S_FALSE; if (!apt) apt = COM_CreateApartment(dwCoInit);
InterlockedIncrement(&apt->inits);
if (hr == S_OK) NtCurrentTeb()->ErrorInfo = apt;
return hr; return hr;
} }
@ -347,8 +397,18 @@ HRESULT WINAPI CoInitializeEx(
void WINAPI CoUninitialize(void) void WINAPI CoUninitialize(void)
{ {
LONG lCOMRefCnt; LONG lCOMRefCnt;
APARTMENT *apt;
TRACE("()\n"); TRACE("()\n");
apt = NtCurrentTeb()->ErrorInfo;
if (!apt) return;
if (InterlockedDecrement(&apt->inits)==0) {
NtCurrentTeb()->ErrorInfo = NULL;
COM_DestroyApartment(apt);
apt = NULL;
}
/* /*
* Decrease the reference count. * Decrease the reference count.
* If we are back to 0 locks on the COM library, make sure we free * If we are back to 0 locks on the COM library, make sure we free
@ -378,6 +438,7 @@ void WINAPI CoUninitialize(void)
*/ */
COM_ExternalLockFreeList(); COM_ExternalLockFreeList();
COM_UninitMTA();
} }
else if (lCOMRefCnt<1) { else if (lCOMRefCnt<1) {
ERR( "CoUninitialize() - not CoInitialized.\n" ); ERR( "CoUninitialize() - not CoInitialized.\n" );

View File

@ -4,6 +4,7 @@
* Copyright 1999 Francis Beaudet * Copyright 1999 Francis Beaudet
* Copyright 1999 Sylvain St-Germain * Copyright 1999 Sylvain St-Germain
* Copyright 2002 Marcus Meissner * Copyright 2002 Marcus Meissner
* Copyright 2003 Ove Kåven, TransGaming Technologies
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -26,6 +27,74 @@
/* All private prototype functions used by OLE will be added to this header file */ /* All private prototype functions used by OLE will be added to this header file */
#include "wtypes.h" #include "wtypes.h"
#include "dcom.h"
#include "thread.h"
/* exported interface */
typedef struct tagXIF {
struct tagXIF *next;
LPVOID iface; /* interface pointer */
IID iid; /* interface ID */
IPID ipid; /* exported interface ID */
LPRPCSTUBBUFFER stub; /* interface stub */
DWORD refs; /* external reference count */
HRESULT hres; /* result of stub creation attempt */
} XIF;
/* exported object */
typedef struct tagXOBJECT {
ICOM_VTABLE(IRpcStubBuffer) *lpVtbl;
struct tagAPARTMENT *parent;
struct tagXOBJECT *next;
LPUNKNOWN obj; /* object identity (IUnknown) */
OID oid; /* object ID */
DWORD ifc; /* interface ID counter */
XIF *ifaces; /* exported interfaces */
DWORD refs; /* external reference count */
} XOBJECT;
/* imported interface */
typedef struct tagIIF {
struct tagIIF *next;
LPVOID iface; /* interface pointer */
IID iid; /* interface ID */
IPID ipid; /* imported interface ID */
LPRPCPROXYBUFFER proxy; /* interface proxy */
DWORD refs; /* imported (public) references */
HRESULT hres; /* result of proxy creation attempt */
} IIF;
/* imported object */
typedef struct tagIOBJECT {
ICOM_VTABLE(IRemUnknown) *lpVtbl;
struct tagAPARTMENT *parent;
struct tagIOBJECT *next;
LPRPCCHANNELBUFFER chan; /* channel to object */
OXID oxid; /* object exported ID */
OID oid; /* object ID */
IPID ipid; /* first imported interface ID */
IIF *ifaces; /* imported interfaces */
DWORD refs; /* proxy reference count */
} IOBJECT;
/* apartment */
typedef struct tagAPARTMENT {
struct tagAPARTMENT *next, *prev, *parent;
DWORD model; /* threading model */
DWORD inits; /* CoInitialize count */
DWORD tid; /* thread id */
HANDLE thread; /* thread handle */
OXID oxid; /* object exporter ID */
OID oidc; /* object ID counter */
HWND win; /* message window */
CRITICAL_SECTION cs; /* thread safety */
LPMESSAGEFILTER filter; /* message filter */
XOBJECT *objs; /* exported objects */
IOBJECT *proxies; /* imported objects */
LPVOID ErrorInfo; /* thread error info */
} APARTMENT;
extern APARTMENT MTA, *apts;
extern void* StdGlobalInterfaceTable_Construct(); extern void* StdGlobalInterfaceTable_Construct();
extern void StdGlobalInterfaceTable_Destroy(void* self); extern void StdGlobalInterfaceTable_Destroy(void* self);
@ -121,4 +190,25 @@ int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id); HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id);
/*
* Per-thread values are stored in the TEB on offset 0xF80,
* see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm
*/
static inline APARTMENT* COM_CurrentInfo(void) WINE_UNUSED;
static inline APARTMENT* COM_CurrentInfo(void)
{
APARTMENT* apt = NtCurrentTeb()->ErrorInfo;
return apt;
}
static inline APARTMENT* COM_CurrentApt(void) WINE_UNUSED;
static inline APARTMENT* COM_CurrentApt(void)
{
APARTMENT* apt = COM_CurrentInfo();
if (apt && apt->parent) apt = apt->parent;
return apt;
}
/* compobj.c */
HWND COM_GetApartmentWin(OXID oxid);
#endif /* __WINE_OLE_COMPOBJ_H */ #endif /* __WINE_OLE_COMPOBJ_H */

View File

@ -32,7 +32,7 @@
#include "objbase.h" #include "objbase.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "thread.h" #include "compobj_private.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -483,13 +483,13 @@ 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, NtCurrentTeb()->ErrorInfo); TRACE("(%ld, %p, %p): stub:\n", dwReserved, pperrinfo, COM_CurrentInfo()->ErrorInfo);
if(! pperrinfo ) return E_INVALIDARG; if(! pperrinfo ) return E_INVALIDARG;
if(!(*pperrinfo = (IErrorInfo*)(NtCurrentTeb()->ErrorInfo))) return S_FALSE; if(!(*pperrinfo = (IErrorInfo*)(COM_CurrentInfo()->ErrorInfo))) return S_FALSE;
/* clear thread error state */ /* clear thread error state */
NtCurrentTeb()->ErrorInfo = NULL; COM_CurrentInfo()->ErrorInfo = NULL;
return S_OK; return S_OK;
} }
@ -502,11 +502,11 @@ HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo)
TRACE("(%ld, %p): stub:\n", dwReserved, perrinfo); TRACE("(%ld, %p): stub:\n", dwReserved, perrinfo);
/* release old errorinfo */ /* release old errorinfo */
pei = (IErrorInfo*)NtCurrentTeb()->ErrorInfo; pei = (IErrorInfo*)COM_CurrentInfo()->ErrorInfo;
if(pei) IErrorInfo_Release(pei); if(pei) IErrorInfo_Release(pei);
/* set to new value */ /* set to new value */
NtCurrentTeb()->ErrorInfo = perrinfo; COM_CurrentInfo()->ErrorInfo = perrinfo;
if(perrinfo) IErrorInfo_AddRef(perrinfo); if(perrinfo) IErrorInfo_AddRef(perrinfo);
return S_OK; return S_OK;
} }