Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405/* * 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 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include <stdarg.h>
#define COBJMACROS
#include "windef.h"#include "winbase.h"#include "winuser.h"#include "objbase.h"#include "ole2.h"#include "winerror.h"
#include "compobj_private.h"
#include "wine/list.h"#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 */
struct list entry;} StdGITEntry;
/* Class data */typedef struct StdGlobalInterfaceTableImpl{ IGlobalInterfaceTable IGlobalInterfaceTable_iface;
struct list list; ULONG nextCookie; } StdGlobalInterfaceTableImpl;
static IGlobalInterfaceTable *std_git;
static CRITICAL_SECTION git_section;static CRITICAL_SECTION_DEBUG critsect_debug ={ 0, 0, &git_section, { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": global interface table") }};static CRITICAL_SECTION git_section = { &critsect_debug, -1, 0, 0, 0, 0 };
static inline StdGlobalInterfaceTableImpl *impl_from_IGlobalInterfaceTable(IGlobalInterfaceTable *iface){ return CONTAINING_RECORD(iface, StdGlobalInterfaceTableImpl, IGlobalInterfaceTable_iface);}
/*** * A helper function to traverse the list and find the entry that matches the cookie. * Returns NULL if not found. Must be called inside git_section critical section. */static StdGITEntry* StdGlobalInterfaceTable_FindEntry(StdGlobalInterfaceTableImpl* This, DWORD cookie){ StdGITEntry* e;
TRACE("This=%p, cookie=0x%x\n", This, cookie);
LIST_FOR_EACH_ENTRY(e, &This->list, StdGITEntry, entry) { if (e->cookie == cookie) return e; }
TRACE("Entry not found\n"); return NULL;}
/*** * Here's the boring boilerplate stuff for IUnknown */
static HRESULT WINAPIStdGlobalInterfaceTable_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 { FIXME("(%s), not supported.\n", debugstr_guid(riid)); return E_NOINTERFACE; }
/* Now inc the refcount */ IGlobalInterfaceTable_AddRef(iface); return S_OK;}
static ULONG WINAPIStdGlobalInterfaceTable_AddRef(IGlobalInterfaceTable* iface){ return 1;}
static ULONG WINAPIStdGlobalInterfaceTable_Release(IGlobalInterfaceTable* iface){ return 1;}
/*** * Now implement the actual IGlobalInterfaceTable interface */
static HRESULT WINAPIStdGlobalInterfaceTable_RegisterInterfaceInGlobal( IGlobalInterfaceTable* iface, IUnknown* pUnk, REFIID riid, DWORD* pdwCookie){ StdGlobalInterfaceTableImpl* const This = impl_from_IGlobalInterfaceTable(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; /* marshal the interface */ TRACE("About to marshal the interface\n");
hres = CreateStreamOnHGlobal(0, TRUE, &stream); if (hres != S_OK) return hres; hres = CoMarshalInterface(stream, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG); if (hres != S_OK) { IStream_Release(stream); return hres; }
zero.QuadPart = 0; IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
entry = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGITEntry)); if (!entry) { CoReleaseMarshalData(stream); IStream_Release(stream); return E_OUTOFMEMORY; }
EnterCriticalSection(&git_section); entry->iid = *riid; entry->stream = stream; entry->cookie = This->nextCookie; This->nextCookie++; /* inc the cookie count */
/* insert the new entry at the end of the list */ list_add_tail(&This->list, &entry->entry);
/* and return the cookie */ *pdwCookie = entry->cookie; LeaveCriticalSection(&git_section); TRACE("Cookie is 0x%x\n", entry->cookie); return S_OK;}
static HRESULT WINAPIStdGlobalInterfaceTable_RevokeInterfaceFromGlobal( IGlobalInterfaceTable* iface, DWORD dwCookie){ StdGlobalInterfaceTableImpl* This = impl_from_IGlobalInterfaceTable(iface); StdGITEntry* entry; HRESULT hr;
TRACE("iface=%p, dwCookie=0x%x\n", iface, dwCookie);
EnterCriticalSection(&git_section);
entry = StdGlobalInterfaceTable_FindEntry(This, dwCookie); if (entry == NULL) { TRACE("Entry not found\n"); LeaveCriticalSection(&git_section); return E_INVALIDARG; /* not found */ }
list_remove(&entry->entry);
LeaveCriticalSection(&git_section); /* Free the stream */ hr = CoReleaseMarshalData(entry->stream); if (hr != S_OK) { WARN("Failed to release marshal data, hr = 0x%08x\n", hr); return hr; } IStream_Release(entry->stream); HeapFree(GetProcessHeap(), 0, entry); return S_OK;}
static HRESULT WINAPIStdGlobalInterfaceTable_GetInterfaceFromGlobal( IGlobalInterfaceTable* iface, DWORD dwCookie, REFIID riid, void **ppv){ StdGlobalInterfaceTableImpl* This = impl_from_IGlobalInterfaceTable(iface); StdGITEntry* entry; HRESULT hres; IStream *stream;
TRACE("dwCookie=0x%x, riid=%s, ppv=%p\n", dwCookie, debugstr_guid(riid), ppv);
EnterCriticalSection(&git_section);
entry = StdGlobalInterfaceTable_FindEntry(This, dwCookie); if (entry == NULL) { WARN("Entry for cookie 0x%x not found\n", dwCookie); LeaveCriticalSection(&git_section); return E_INVALIDARG; }
TRACE("entry=%p\n", entry);
hres = IStream_Clone(entry->stream, &stream);
LeaveCriticalSection(&git_section);
if (hres != S_OK) { WARN("Failed to clone stream with error 0x%08x\n", hres); return hres; }
/* unmarshal the interface */ hres = CoUnmarshalInterface(stream, riid, ppv); IStream_Release(stream);
if (hres != S_OK) { WARN("Failed to unmarshal stream\n"); return hres; }
TRACE("ppv=%p\n", *ppv); return S_OK;}
/* Classfactory definition - despite what MSDN says, some programs need this */
static HRESULT WINAPIGITCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv){ *ppv = NULL; if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) { *ppv = iface; 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 WINAPIGITCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv){ IGlobalInterfaceTable *git = get_std_git(); HRESULT hr = IGlobalInterfaceTable_QueryInterface(git, riid, ppv); IGlobalInterfaceTable_Release(git); return hr;}
static HRESULT WINAPI GITCF_LockServer(LPCLASSFACTORY iface, BOOL fLock){ FIXME("(%d), stub!\n",fLock); return S_OK;}
static const IClassFactoryVtbl GITClassFactoryVtbl = { GITCF_QueryInterface, GITCF_AddRef, GITCF_Release, GITCF_CreateInstance, GITCF_LockServer};
static IClassFactory git_classfactory = { &GITClassFactoryVtbl };
HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv){ *ppv = &git_classfactory; TRACE("Returning GIT classfactory\n"); return S_OK;}
/* Virtual function table */static const IGlobalInterfaceTableVtbl StdGlobalInterfaceTableImpl_Vtbl ={ StdGlobalInterfaceTable_QueryInterface, StdGlobalInterfaceTable_AddRef, StdGlobalInterfaceTable_Release, StdGlobalInterfaceTable_RegisterInterfaceInGlobal, StdGlobalInterfaceTable_RevokeInterfaceFromGlobal, StdGlobalInterfaceTable_GetInterfaceFromGlobal};
IGlobalInterfaceTable* get_std_git(void){ if (!std_git) { StdGlobalInterfaceTableImpl* newGIT;
newGIT = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGlobalInterfaceTableImpl)); if (!newGIT) return NULL;
newGIT->IGlobalInterfaceTable_iface.lpVtbl = &StdGlobalInterfaceTableImpl_Vtbl; list_init(&newGIT->list); newGIT->nextCookie = 0xf100; /* that's where windows starts, so that's where we start */
if (InterlockedCompareExchangePointer((void**)&std_git, &newGIT->IGlobalInterfaceTable_iface, NULL)) { HeapFree(GetProcessHeap(), 0, newGIT); } else TRACE("Created the GIT at %p\n", newGIT); }
return std_git;}
void release_std_git(void){ StdGlobalInterfaceTableImpl *git; StdGITEntry *entry, *entry2;
if (!std_git) return;
git = impl_from_IGlobalInterfaceTable(std_git); LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &git->list, StdGITEntry, entry) { list_remove(&entry->entry);
CoReleaseMarshalData(entry->stream); IStream_Release(entry->stream); HeapFree(GetProcessHeap(), 0, entry); }
HeapFree(GetProcessHeap(), 0, git);}