2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* Implementation of the StdGlobalInterfaceTable object
|
|
|
|
*
|
|
|
|
* The GlobalInterfaceTable (GIT) object is used to marshal interfaces between
|
|
|
|
* threading apartments (contexts). When you want to pass an interface but not
|
|
|
|
* as a parameter, it wouldn't get marshalled automatically, so you can use this
|
|
|
|
* object to insert the interface into a table, and you get back a cookie.
|
|
|
|
* Then when it's retrieved, it'll be unmarshalled into the right apartment.
|
|
|
|
*
|
|
|
|
* Copyright 2003 Mike Hearn <mike@theoretic.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2007-04-20 12:23:52 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#define COBJMACROS
|
|
|
|
#define NONAMELESSUNION
|
|
|
|
#define NONAMELESSSTRUCT
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "winuser.h"
|
|
|
|
#include "objbase.h"
|
|
|
|
#include "ole2.h"
|
|
|
|
#include "winerror.h"
|
|
|
|
|
2008-01-14 15:45:45 +00:00
|
|
|
#include "compobj_private.h"
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
#include "wine/list.h"
|
2005-07-31 12:11:56 +00:00
|
|
|
#include "wine/debug.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* StdGlobalInterfaceTable definition
|
|
|
|
*
|
|
|
|
* This class implements IGlobalInterfaceTable and is a process-wide singleton
|
|
|
|
* used for marshalling interfaces between threading apartments using cookies.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Each entry in the linked list of GIT entries */
|
|
|
|
typedef struct StdGITEntry
|
|
|
|
{
|
|
|
|
DWORD cookie;
|
|
|
|
IID iid; /* IID of the interface */
|
|
|
|
IStream* stream; /* Holds the marshalled interface */
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
struct list entry;
|
2005-07-31 12:11:56 +00:00
|
|
|
} StdGITEntry;
|
|
|
|
|
|
|
|
/* Class data */
|
|
|
|
typedef struct StdGlobalInterfaceTableImpl
|
|
|
|
{
|
2005-08-03 22:31:39 +00:00
|
|
|
const IGlobalInterfaceTableVtbl *lpVtbl;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
ULONG ref;
|
2007-04-20 12:23:52 +00:00
|
|
|
struct list list;
|
2005-07-31 12:11:56 +00:00
|
|
|
ULONG nextCookie;
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
} StdGlobalInterfaceTableImpl;
|
|
|
|
|
|
|
|
void* StdGlobalInterfaceTableInstance;
|
|
|
|
|
|
|
|
static CRITICAL_SECTION git_section;
|
|
|
|
static CRITICAL_SECTION_DEBUG critsect_debug =
|
|
|
|
{
|
|
|
|
0, 0, &git_section,
|
|
|
|
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
|
2005-11-20 15:01:10 +00:00
|
|
|
0, 0, { (DWORD_PTR)(__FILE__ ": global interface table") }
|
2005-07-31 12:11:56 +00:00
|
|
|
};
|
|
|
|
static CRITICAL_SECTION git_section = { &critsect_debug, -1, 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
|
|
|
|
/** This destroys it again. It should revoke all the held interfaces first **/
|
2007-04-20 12:23:52 +00:00
|
|
|
static void StdGlobalInterfaceTable_Destroy(void* self)
|
|
|
|
{
|
2005-07-31 12:11:56 +00:00
|
|
|
TRACE("(%p)\n", self);
|
|
|
|
FIXME("Revoke held interfaces here\n");
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, self);
|
|
|
|
StdGlobalInterfaceTableInstance = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* A helper function to traverse the list and find the entry that matches the cookie.
|
2007-07-27 09:49:52 +00:00
|
|
|
* Returns NULL if not found. Must be called inside git_section critical section.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
static StdGITEntry*
|
|
|
|
StdGlobalInterfaceTable_FindEntry(IGlobalInterfaceTable* iface, DWORD cookie)
|
|
|
|
{
|
|
|
|
StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface;
|
|
|
|
StdGITEntry* e;
|
|
|
|
|
2008-01-18 17:39:35 +00:00
|
|
|
TRACE("iface=%p, cookie=0x%x\n", iface, cookie);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
LIST_FOR_EACH_ENTRY(e, &self->list, StdGITEntry, entry) {
|
2007-07-27 09:49:52 +00:00
|
|
|
if (e->cookie == cookie)
|
2005-07-31 12:11:56 +00:00
|
|
|
return e;
|
|
|
|
}
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
TRACE("Entry not found\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* Here's the boring boilerplate stuff for IUnknown
|
|
|
|
*/
|
|
|
|
|
|
|
|
static HRESULT WINAPI
|
|
|
|
StdGlobalInterfaceTable_QueryInterface(IGlobalInterfaceTable* iface,
|
|
|
|
REFIID riid, void** ppvObject)
|
|
|
|
{
|
|
|
|
/* Make sure silly coders can't crash us */
|
|
|
|
if (ppvObject == 0) return E_INVALIDARG;
|
|
|
|
|
|
|
|
*ppvObject = 0; /* assume we don't have the interface */
|
|
|
|
|
|
|
|
/* Do we implement that interface? */
|
|
|
|
if (IsEqualIID(&IID_IUnknown, riid) ||
|
|
|
|
IsEqualIID(&IID_IGlobalInterfaceTable, riid))
|
|
|
|
*ppvObject = iface;
|
|
|
|
else
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
|
|
|
|
/* Now inc the refcount */
|
|
|
|
IGlobalInterfaceTable_AddRef(iface);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI
|
|
|
|
StdGlobalInterfaceTable_AddRef(IGlobalInterfaceTable* iface)
|
|
|
|
{
|
|
|
|
StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface;
|
|
|
|
|
|
|
|
/* InterlockedIncrement(&self->ref); */
|
|
|
|
return self->ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI
|
|
|
|
StdGlobalInterfaceTable_Release(IGlobalInterfaceTable* iface)
|
|
|
|
{
|
|
|
|
StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface;
|
|
|
|
|
|
|
|
/* InterlockedDecrement(&self->ref); */
|
|
|
|
if (self->ref == 0) {
|
|
|
|
/* Hey ho, it's time to go, so long again 'till next weeks show! */
|
|
|
|
StdGlobalInterfaceTable_Destroy(self);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self->ref;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* Now implement the actual IGlobalInterfaceTable interface
|
|
|
|
*/
|
|
|
|
|
|
|
|
static HRESULT WINAPI
|
|
|
|
StdGlobalInterfaceTable_RegisterInterfaceInGlobal(
|
|
|
|
IGlobalInterfaceTable* iface, IUnknown* pUnk,
|
|
|
|
REFIID riid, DWORD* pdwCookie)
|
|
|
|
{
|
|
|
|
StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface;
|
|
|
|
IStream* stream = NULL;
|
|
|
|
HRESULT hres;
|
|
|
|
StdGITEntry* entry;
|
|
|
|
LARGE_INTEGER zero;
|
|
|
|
|
|
|
|
TRACE("iface=%p, pUnk=%p, riid=%s, pdwCookie=0x%p\n", iface, pUnk, debugstr_guid(riid), pdwCookie);
|
|
|
|
|
|
|
|
if (pUnk == NULL) return E_INVALIDARG;
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/* marshal the interface */
|
|
|
|
TRACE("About to marshal the interface\n");
|
|
|
|
|
|
|
|
hres = CreateStreamOnHGlobal(0, TRUE, &stream);
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (hres != S_OK) return hres;
|
2005-07-31 12:11:56 +00:00
|
|
|
hres = CoMarshalInterface(stream, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG);
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (hres != S_OK)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
IStream_Release(stream);
|
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
|
|
|
zero.QuadPart = 0;
|
2007-04-20 12:23:52 +00:00
|
|
|
IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
entry = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGITEntry));
|
|
|
|
if (entry == NULL) return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
EnterCriticalSection(&git_section);
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
entry->iid = *riid;
|
|
|
|
entry->stream = stream;
|
|
|
|
entry->cookie = self->nextCookie;
|
|
|
|
self->nextCookie++; /* inc the cookie count */
|
|
|
|
|
|
|
|
/* insert the new entry at the end of the list */
|
2007-04-20 12:23:52 +00:00
|
|
|
list_add_tail(&self->list, &entry->entry);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* and return the cookie */
|
|
|
|
*pdwCookie = entry->cookie;
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
LeaveCriticalSection(&git_section);
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("Cookie is 0x%x\n", entry->cookie);
|
2005-07-31 12:11:56 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI
|
|
|
|
StdGlobalInterfaceTable_RevokeInterfaceFromGlobal(
|
|
|
|
IGlobalInterfaceTable* iface, DWORD dwCookie)
|
|
|
|
{
|
|
|
|
StdGITEntry* entry;
|
|
|
|
HRESULT hr;
|
|
|
|
|
2008-01-18 17:39:35 +00:00
|
|
|
TRACE("iface=%p, dwCookie=0x%x\n", iface, dwCookie);
|
2007-07-27 09:49:52 +00:00
|
|
|
|
|
|
|
EnterCriticalSection(&git_section);
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
entry = StdGlobalInterfaceTable_FindEntry(iface, dwCookie);
|
|
|
|
if (entry == NULL) {
|
|
|
|
TRACE("Entry not found\n");
|
2007-07-27 09:49:52 +00:00
|
|
|
LeaveCriticalSection(&git_section);
|
2005-07-31 12:11:56 +00:00
|
|
|
return E_INVALIDARG; /* not found */
|
|
|
|
}
|
2007-07-27 09:49:52 +00:00
|
|
|
|
|
|
|
list_remove(&entry->entry);
|
|
|
|
|
|
|
|
LeaveCriticalSection(&git_section);
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/* Free the stream */
|
|
|
|
hr = CoReleaseMarshalData(entry->stream);
|
|
|
|
if (hr != S_OK)
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
WARN("Failed to release marshal data, hr = 0x%08x\n", hr);
|
2005-07-31 12:11:56 +00:00
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
IStream_Release(entry->stream);
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, entry);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI
|
|
|
|
StdGlobalInterfaceTable_GetInterfaceFromGlobal(
|
|
|
|
IGlobalInterfaceTable* iface, DWORD dwCookie,
|
|
|
|
REFIID riid, void **ppv)
|
|
|
|
{
|
|
|
|
StdGITEntry* entry;
|
|
|
|
HRESULT hres;
|
2007-07-27 09:49:52 +00:00
|
|
|
IStream *stream;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("dwCookie=0x%x, riid=%s, ppv=%p\n", dwCookie, debugstr_guid(riid), ppv);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-07-27 09:49:52 +00:00
|
|
|
EnterCriticalSection(&git_section);
|
|
|
|
|
|
|
|
entry = StdGlobalInterfaceTable_FindEntry(iface, dwCookie);
|
|
|
|
if (entry == NULL) {
|
|
|
|
WARN("Entry for cookie 0x%x not found\n", dwCookie);
|
|
|
|
LeaveCriticalSection(&git_section);
|
2005-07-31 12:11:56 +00:00
|
|
|
return E_INVALIDARG;
|
|
|
|
}
|
2007-07-27 09:49:52 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
TRACE("entry=%p\n", entry);
|
2007-07-27 09:49:52 +00:00
|
|
|
|
|
|
|
hres = IStream_Clone(entry->stream, &stream);
|
|
|
|
|
|
|
|
LeaveCriticalSection(&git_section);
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (hres != S_OK) {
|
2007-07-27 09:49:52 +00:00
|
|
|
WARN("Failed to clone stream with error 0x%08x\n", hres);
|
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/* unmarshal the interface */
|
2007-07-27 09:49:52 +00:00
|
|
|
hres = CoUnmarshalInterface(stream, riid, ppv);
|
|
|
|
IStream_Release(stream);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (hres) {
|
|
|
|
WARN("Failed to unmarshal stream\n");
|
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
TRACE("ppv=%p\n", *ppv);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Classfactory definition - despite what MSDN says, some programs need this */
|
|
|
|
|
|
|
|
static HRESULT WINAPI
|
|
|
|
GITCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv)
|
|
|
|
{
|
|
|
|
*ppv = NULL;
|
|
|
|
if (IsEqualIID(riid,&IID_IUnknown) ||
|
|
|
|
IsEqualIID(riid,&IID_IGlobalInterfaceTable))
|
|
|
|
{
|
2009-03-03 09:12:43 +00:00
|
|
|
*ppv = iface;
|
2005-07-31 12:11:56 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI GITCF_AddRef(LPCLASSFACTORY iface)
|
|
|
|
{
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI GITCF_Release(LPCLASSFACTORY iface)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI
|
|
|
|
GITCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pUnk,
|
|
|
|
REFIID riid, LPVOID *ppv)
|
|
|
|
{
|
|
|
|
if (IsEqualIID(riid,&IID_IGlobalInterfaceTable)) {
|
2008-01-14 15:45:45 +00:00
|
|
|
if (StdGlobalInterfaceTableInstance == NULL)
|
2005-07-31 12:11:56 +00:00
|
|
|
StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
|
|
|
|
return IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, riid, ppv);
|
|
|
|
}
|
|
|
|
|
|
|
|
FIXME("(%s), not supported.\n",debugstr_guid(riid));
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI GITCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
|
|
|
|
{
|
|
|
|
FIXME("(%d), stub!\n",fLock);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2005-08-03 22:31:39 +00:00
|
|
|
static const IClassFactoryVtbl GITClassFactoryVtbl = {
|
2005-07-31 12:11:56 +00:00
|
|
|
GITCF_QueryInterface,
|
|
|
|
GITCF_AddRef,
|
|
|
|
GITCF_Release,
|
|
|
|
GITCF_CreateInstance,
|
|
|
|
GITCF_LockServer
|
|
|
|
};
|
|
|
|
|
2005-08-03 22:31:39 +00:00
|
|
|
static const IClassFactoryVtbl *PGITClassFactoryVtbl = &GITClassFactoryVtbl;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv)
|
|
|
|
{
|
|
|
|
*ppv = &PGITClassFactoryVtbl;
|
|
|
|
TRACE("Returning GIT classfactory\n");
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Virtual function table */
|
2005-08-03 22:31:39 +00:00
|
|
|
static const IGlobalInterfaceTableVtbl StdGlobalInterfaceTableImpl_Vtbl =
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
StdGlobalInterfaceTable_QueryInterface,
|
|
|
|
StdGlobalInterfaceTable_AddRef,
|
|
|
|
StdGlobalInterfaceTable_Release,
|
|
|
|
StdGlobalInterfaceTable_RegisterInterfaceInGlobal,
|
|
|
|
StdGlobalInterfaceTable_RevokeInterfaceFromGlobal,
|
|
|
|
StdGlobalInterfaceTable_GetInterfaceFromGlobal
|
|
|
|
};
|
|
|
|
|
|
|
|
/** This function constructs the GIT. It should only be called once **/
|
2007-04-20 12:23:52 +00:00
|
|
|
void* StdGlobalInterfaceTable_Construct(void)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
StdGlobalInterfaceTableImpl* newGIT;
|
|
|
|
|
|
|
|
newGIT = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGlobalInterfaceTableImpl));
|
|
|
|
if (newGIT == 0) return newGIT;
|
|
|
|
|
|
|
|
newGIT->lpVtbl = &StdGlobalInterfaceTableImpl_Vtbl;
|
|
|
|
newGIT->ref = 1; /* Initialise the reference count */
|
2007-04-20 12:23:52 +00:00
|
|
|
list_init(&newGIT->list);
|
2005-07-31 12:11:56 +00:00
|
|
|
newGIT->nextCookie = 0xf100; /* that's where windows starts, so that's where we start */
|
|
|
|
TRACE("Created the GIT at %p\n", newGIT);
|
|
|
|
|
|
|
|
return (void*)newGIT;
|
|
|
|
}
|