Commit ef57c4d9 authored by Ove Kaaven's avatar Ove Kaaven Committed by Alexandre Julliard

Preliminary support for COM apartments.

parent 350aa2dc
......@@ -31,7 +31,8 @@
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "objbase.h"
#include "ole2.h"
#include "ole2ver.h"
......@@ -41,6 +42,7 @@
#include "wownt32.h"
#include "wine/unicode.h"
#include "objbase.h"
#include "ole32_main.h"
#include "compobj_private.h"
#include "wine/debug.h"
......@@ -62,45 +64,8 @@ const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0,
static void* StdGlobalInterfaceTableInstance;
/*****************************************************************************
* Apartment management stuff
*
* 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;
*/
APARTMENT MTA, *apts;
static CRITICAL_SECTION csApartment = CRITICAL_SECTION_INIT("csApartment");
/*
* This lock count counts the number of times CoInitialize is called. It is
......@@ -150,19 +115,112 @@ typedef struct tagOpenDll {
static CRITICAL_SECTION csOpenDllList = CRITICAL_SECTION_INIT("csOpenDllList");
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_FreeUnused(int Timeout);
/******************************************************************************
* Initialize/Uninitialize critical sections.
* Initialize/Unitialize threading stuff.
*/
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 )
{
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);
}
/*****************************************************************************
......@@ -282,12 +340,6 @@ HRESULT WINAPI CoInitialize(
* S_FALSE if this function was called already.
* RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
* 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(
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 */
)
{
HRESULT hr;
HRESULT hr = S_OK;
APARTMENT *apt;
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);
}
/*
* Check for unsupported features.
*/
if (dwCoInit!=COINIT_APARTMENTTHREADED)
{
FIXME(":(%p,%x): unsupported flag %x\n", lpReserved, (int)dwCoInit, (int)dwCoInit);
/* Hope for the best and continue anyway */
}
apt = NtCurrentTeb()->ErrorInfo;
if (apt && dwCoInit != apt->model) return RPC_E_CHANGED_MODE;
hr = apt ? S_FALSE : S_OK;
/*
* 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");
COM_InitMTA();
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;
}
......@@ -347,8 +397,18 @@ HRESULT WINAPI CoInitializeEx(
void WINAPI CoUninitialize(void)
{
LONG lCOMRefCnt;
APARTMENT *apt;
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.
* 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_UninitMTA();
}
else if (lCOMRefCnt<1) {
ERR( "CoUninitialize() - not CoInitialized.\n" );
......
......@@ -4,6 +4,7 @@
* Copyright 1999 Francis Beaudet
* Copyright 1999 Sylvain St-Germain
* Copyright 2002 Marcus Meissner
* Copyright 2003 Ove Kven, TransGaming Technologies
*
* This library is free software; you can redistribute it and/or
* 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 */
#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_Destroy(void* self);
......@@ -121,4 +190,25 @@ int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
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 */
......@@ -32,7 +32,7 @@
#include "objbase.h"
#include "wine/unicode.h"
#include "thread.h"
#include "compobj_private.h"
#include "wine/debug.h"
......@@ -483,13 +483,13 @@ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **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 = (IErrorInfo*)(NtCurrentTeb()->ErrorInfo))) return S_FALSE;
if(!(*pperrinfo = (IErrorInfo*)(COM_CurrentInfo()->ErrorInfo))) return S_FALSE;
/* clear thread error state */
NtCurrentTeb()->ErrorInfo = NULL;
COM_CurrentInfo()->ErrorInfo = NULL;
return S_OK;
}
......@@ -502,11 +502,11 @@ HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo)
TRACE("(%ld, %p): stub:\n", dwReserved, perrinfo);
/* release old errorinfo */
pei = (IErrorInfo*)NtCurrentTeb()->ErrorInfo;
pei = (IErrorInfo*)COM_CurrentInfo()->ErrorInfo;
if(pei) IErrorInfo_Release(pei);
/* set to new value */
NtCurrentTeb()->ErrorInfo = perrinfo;
COM_CurrentInfo()->ErrorInfo = perrinfo;
if(perrinfo) IErrorInfo_AddRef(perrinfo);
return S_OK;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment