Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengit.c
Go to the documentation of this file.
00001 /* 00002 * Implementation of the StdGlobalInterfaceTable object 00003 * 00004 * The GlobalInterfaceTable (GIT) object is used to marshal interfaces between 00005 * threading apartments (contexts). When you want to pass an interface but not 00006 * as a parameter, it wouldn't get marshalled automatically, so you can use this 00007 * object to insert the interface into a table, and you get back a cookie. 00008 * Then when it's retrieved, it'll be unmarshalled into the right apartment. 00009 * 00010 * Copyright 2003 Mike Hearn <mike@theoretic.com> 00011 * 00012 * This library is free software; you can redistribute it and/or 00013 * modify it under the terms of the GNU Lesser General Public 00014 * License as published by the Free Software Foundation; either 00015 * version 2.1 of the License, or (at your option) any later version. 00016 * 00017 * This library is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00020 * Lesser General Public License for more details. 00021 * 00022 * You should have received a copy of the GNU Lesser General Public 00023 * License along with this library; if not, write to the Free Software 00024 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00025 */ 00026 00027 #include <stdarg.h> 00028 00029 #define COBJMACROS 00030 #define NONAMELESSUNION 00031 #define NONAMELESSSTRUCT 00032 00033 #include "windef.h" 00034 #include "winbase.h" 00035 #include "winuser.h" 00036 #include "objbase.h" 00037 #include "ole2.h" 00038 #include "winerror.h" 00039 00040 #include "compobj_private.h" 00041 00042 #include "wine/list.h" 00043 #include "wine/debug.h" 00044 00045 WINE_DEFAULT_DEBUG_CHANNEL(ole); 00046 00047 /**************************************************************************** 00048 * StdGlobalInterfaceTable definition 00049 * 00050 * This class implements IGlobalInterfaceTable and is a process-wide singleton 00051 * used for marshalling interfaces between threading apartments using cookies. 00052 */ 00053 00054 /* Each entry in the linked list of GIT entries */ 00055 typedef struct StdGITEntry 00056 { 00057 DWORD cookie; 00058 IID iid; /* IID of the interface */ 00059 IStream* stream; /* Holds the marshalled interface */ 00060 00061 struct list entry; 00062 } StdGITEntry; 00063 00064 /* Class data */ 00065 typedef struct StdGlobalInterfaceTableImpl 00066 { 00067 IGlobalInterfaceTable IGlobalInterfaceTable_iface; 00068 00069 ULONG ref; 00070 struct list list; 00071 ULONG nextCookie; 00072 00073 } StdGlobalInterfaceTableImpl; 00074 00075 void* StdGlobalInterfaceTableInstance; 00076 00077 static CRITICAL_SECTION git_section; 00078 static CRITICAL_SECTION_DEBUG critsect_debug = 00079 { 00080 0, 0, &git_section, 00081 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 00082 0, 0, { (DWORD_PTR)(__FILE__ ": global interface table") } 00083 }; 00084 static CRITICAL_SECTION git_section = { &critsect_debug, -1, 0, 0, 0, 0 }; 00085 00086 00087 static inline StdGlobalInterfaceTableImpl *impl_from_IGlobalInterfaceTable(IGlobalInterfaceTable *iface) 00088 { 00089 return CONTAINING_RECORD(iface, StdGlobalInterfaceTableImpl, IGlobalInterfaceTable_iface); 00090 } 00091 00093 static void StdGlobalInterfaceTable_Destroy(void* This) 00094 { 00095 TRACE("(%p)\n", This); 00096 FIXME("Revoke held interfaces here\n"); 00097 00098 HeapFree(GetProcessHeap(), 0, This); 00099 StdGlobalInterfaceTableInstance = NULL; 00100 } 00101 00102 /*** 00103 * A helper function to traverse the list and find the entry that matches the cookie. 00104 * Returns NULL if not found. Must be called inside git_section critical section. 00105 */ 00106 static StdGITEntry* StdGlobalInterfaceTable_FindEntry(StdGlobalInterfaceTableImpl* This, 00107 DWORD cookie) 00108 { 00109 StdGITEntry* e; 00110 00111 TRACE("This=%p, cookie=0x%x\n", This, cookie); 00112 00113 LIST_FOR_EACH_ENTRY(e, &This->list, StdGITEntry, entry) { 00114 if (e->cookie == cookie) 00115 return e; 00116 } 00117 00118 TRACE("Entry not found\n"); 00119 return NULL; 00120 } 00121 00122 /*** 00123 * Here's the boring boilerplate stuff for IUnknown 00124 */ 00125 00126 static HRESULT WINAPI 00127 StdGlobalInterfaceTable_QueryInterface(IGlobalInterfaceTable* iface, 00128 REFIID riid, void** ppvObject) 00129 { 00130 /* Make sure silly coders can't crash us */ 00131 if (ppvObject == 0) return E_INVALIDARG; 00132 00133 *ppvObject = 0; /* assume we don't have the interface */ 00134 00135 /* Do we implement that interface? */ 00136 if (IsEqualIID(&IID_IUnknown, riid) || 00137 IsEqualIID(&IID_IGlobalInterfaceTable, riid)) 00138 *ppvObject = iface; 00139 else 00140 return E_NOINTERFACE; 00141 00142 /* Now inc the refcount */ 00143 IGlobalInterfaceTable_AddRef(iface); 00144 return S_OK; 00145 } 00146 00147 static ULONG WINAPI 00148 StdGlobalInterfaceTable_AddRef(IGlobalInterfaceTable* iface) 00149 { 00150 StdGlobalInterfaceTableImpl* const This = impl_from_IGlobalInterfaceTable(iface); 00151 00152 /* InterlockedIncrement(&This->ref); */ 00153 return This->ref; 00154 } 00155 00156 static ULONG WINAPI 00157 StdGlobalInterfaceTable_Release(IGlobalInterfaceTable* iface) 00158 { 00159 StdGlobalInterfaceTableImpl* const This = impl_from_IGlobalInterfaceTable(iface); 00160 00161 /* InterlockedDecrement(&This->ref); */ 00162 if (This->ref == 0) { 00163 /* Hey ho, it's time to go, so long again 'till next weeks show! */ 00164 StdGlobalInterfaceTable_Destroy(This); 00165 return 0; 00166 } 00167 00168 return This->ref; 00169 } 00170 00171 /*** 00172 * Now implement the actual IGlobalInterfaceTable interface 00173 */ 00174 00175 static HRESULT WINAPI 00176 StdGlobalInterfaceTable_RegisterInterfaceInGlobal( 00177 IGlobalInterfaceTable* iface, IUnknown* pUnk, 00178 REFIID riid, DWORD* pdwCookie) 00179 { 00180 StdGlobalInterfaceTableImpl* const This = impl_from_IGlobalInterfaceTable(iface); 00181 IStream* stream = NULL; 00182 HRESULT hres; 00183 StdGITEntry* entry; 00184 LARGE_INTEGER zero; 00185 00186 TRACE("iface=%p, pUnk=%p, riid=%s, pdwCookie=0x%p\n", iface, pUnk, debugstr_guid(riid), pdwCookie); 00187 00188 if (pUnk == NULL) return E_INVALIDARG; 00189 00190 /* marshal the interface */ 00191 TRACE("About to marshal the interface\n"); 00192 00193 hres = CreateStreamOnHGlobal(0, TRUE, &stream); 00194 if (hres != S_OK) return hres; 00195 hres = CoMarshalInterface(stream, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG); 00196 if (hres != S_OK) 00197 { 00198 IStream_Release(stream); 00199 return hres; 00200 } 00201 00202 zero.QuadPart = 0; 00203 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); 00204 00205 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGITEntry)); 00206 if (entry == NULL) return E_OUTOFMEMORY; 00207 00208 EnterCriticalSection(&git_section); 00209 00210 entry->iid = *riid; 00211 entry->stream = stream; 00212 entry->cookie = This->nextCookie; 00213 This->nextCookie++; /* inc the cookie count */ 00214 00215 /* insert the new entry at the end of the list */ 00216 list_add_tail(&This->list, &entry->entry); 00217 00218 /* and return the cookie */ 00219 *pdwCookie = entry->cookie; 00220 00221 LeaveCriticalSection(&git_section); 00222 00223 TRACE("Cookie is 0x%x\n", entry->cookie); 00224 return S_OK; 00225 } 00226 00227 static HRESULT WINAPI 00228 StdGlobalInterfaceTable_RevokeInterfaceFromGlobal( 00229 IGlobalInterfaceTable* iface, DWORD dwCookie) 00230 { 00231 StdGlobalInterfaceTableImpl* This = impl_from_IGlobalInterfaceTable(iface); 00232 StdGITEntry* entry; 00233 HRESULT hr; 00234 00235 TRACE("iface=%p, dwCookie=0x%x\n", iface, dwCookie); 00236 00237 EnterCriticalSection(&git_section); 00238 00239 entry = StdGlobalInterfaceTable_FindEntry(This, dwCookie); 00240 if (entry == NULL) { 00241 TRACE("Entry not found\n"); 00242 LeaveCriticalSection(&git_section); 00243 return E_INVALIDARG; /* not found */ 00244 } 00245 00246 list_remove(&entry->entry); 00247 00248 LeaveCriticalSection(&git_section); 00249 00250 /* Free the stream */ 00251 hr = CoReleaseMarshalData(entry->stream); 00252 if (hr != S_OK) 00253 { 00254 WARN("Failed to release marshal data, hr = 0x%08x\n", hr); 00255 return hr; 00256 } 00257 IStream_Release(entry->stream); 00258 00259 HeapFree(GetProcessHeap(), 0, entry); 00260 return S_OK; 00261 } 00262 00263 static HRESULT WINAPI 00264 StdGlobalInterfaceTable_GetInterfaceFromGlobal( 00265 IGlobalInterfaceTable* iface, DWORD dwCookie, 00266 REFIID riid, void **ppv) 00267 { 00268 StdGlobalInterfaceTableImpl* This = impl_from_IGlobalInterfaceTable(iface); 00269 StdGITEntry* entry; 00270 HRESULT hres; 00271 IStream *stream; 00272 00273 TRACE("dwCookie=0x%x, riid=%s, ppv=%p\n", dwCookie, debugstr_guid(riid), ppv); 00274 00275 EnterCriticalSection(&git_section); 00276 00277 entry = StdGlobalInterfaceTable_FindEntry(This, dwCookie); 00278 if (entry == NULL) { 00279 WARN("Entry for cookie 0x%x not found\n", dwCookie); 00280 LeaveCriticalSection(&git_section); 00281 return E_INVALIDARG; 00282 } 00283 00284 TRACE("entry=%p\n", entry); 00285 00286 hres = IStream_Clone(entry->stream, &stream); 00287 00288 LeaveCriticalSection(&git_section); 00289 00290 if (hres != S_OK) { 00291 WARN("Failed to clone stream with error 0x%08x\n", hres); 00292 return hres; 00293 } 00294 00295 /* unmarshal the interface */ 00296 hres = CoUnmarshalInterface(stream, riid, ppv); 00297 IStream_Release(stream); 00298 00299 if (hres) { 00300 WARN("Failed to unmarshal stream\n"); 00301 return hres; 00302 } 00303 00304 TRACE("ppv=%p\n", *ppv); 00305 return S_OK; 00306 } 00307 00308 /* Classfactory definition - despite what MSDN says, some programs need this */ 00309 00310 static HRESULT WINAPI 00311 GITCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) 00312 { 00313 *ppv = NULL; 00314 if (IsEqualIID(riid,&IID_IUnknown) || 00315 IsEqualIID(riid,&IID_IGlobalInterfaceTable)) 00316 { 00317 *ppv = iface; 00318 return S_OK; 00319 } 00320 return E_NOINTERFACE; 00321 } 00322 00323 static ULONG WINAPI GITCF_AddRef(LPCLASSFACTORY iface) 00324 { 00325 return 2; 00326 } 00327 00328 static ULONG WINAPI GITCF_Release(LPCLASSFACTORY iface) 00329 { 00330 return 1; 00331 } 00332 00333 static HRESULT WINAPI 00334 GITCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pUnk, 00335 REFIID riid, LPVOID *ppv) 00336 { 00337 if (IsEqualIID(riid,&IID_IGlobalInterfaceTable)) { 00338 if (StdGlobalInterfaceTableInstance == NULL) 00339 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct(); 00340 return IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, riid, ppv); 00341 } 00342 00343 FIXME("(%s), not supported.\n",debugstr_guid(riid)); 00344 return E_NOINTERFACE; 00345 } 00346 00347 static HRESULT WINAPI GITCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) 00348 { 00349 FIXME("(%d), stub!\n",fLock); 00350 return S_OK; 00351 } 00352 00353 static const IClassFactoryVtbl GITClassFactoryVtbl = { 00354 GITCF_QueryInterface, 00355 GITCF_AddRef, 00356 GITCF_Release, 00357 GITCF_CreateInstance, 00358 GITCF_LockServer 00359 }; 00360 00361 static const IClassFactoryVtbl *PGITClassFactoryVtbl = &GITClassFactoryVtbl; 00362 00363 HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv) 00364 { 00365 *ppv = &PGITClassFactoryVtbl; 00366 TRACE("Returning GIT classfactory\n"); 00367 return S_OK; 00368 } 00369 00370 /* Virtual function table */ 00371 static const IGlobalInterfaceTableVtbl StdGlobalInterfaceTableImpl_Vtbl = 00372 { 00373 StdGlobalInterfaceTable_QueryInterface, 00374 StdGlobalInterfaceTable_AddRef, 00375 StdGlobalInterfaceTable_Release, 00376 StdGlobalInterfaceTable_RegisterInterfaceInGlobal, 00377 StdGlobalInterfaceTable_RevokeInterfaceFromGlobal, 00378 StdGlobalInterfaceTable_GetInterfaceFromGlobal 00379 }; 00380 00382 void* StdGlobalInterfaceTable_Construct(void) 00383 { 00384 StdGlobalInterfaceTableImpl* newGIT; 00385 00386 newGIT = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGlobalInterfaceTableImpl)); 00387 if (newGIT == 0) return newGIT; 00388 00389 newGIT->IGlobalInterfaceTable_iface.lpVtbl = &StdGlobalInterfaceTableImpl_Vtbl; 00390 newGIT->ref = 1; /* Initialise the reference count */ 00391 list_init(&newGIT->list); 00392 newGIT->nextCookie = 0xf100; /* that's where windows starts, so that's where we start */ 00393 TRACE("Created the GIT at %p\n", newGIT); 00394 00395 return (void*)newGIT; 00396 } Generated on Fri May 25 2012 04:23:45 for ReactOS by
1.7.6.1
|