Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencompobj.c
Go to the documentation of this file.
00001 /* 00002 * COMPOBJ library 00003 * 00004 * Copyright 1995 Martin von Loewis 00005 * Copyright 1998 Justin Bradford 00006 * Copyright 1999 Francis Beaudet 00007 * Copyright 1999 Sylvain St-Germain 00008 * Copyright 2002 Marcus Meissner 00009 * Copyright 2004 Mike Hearn 00010 * Copyright 2005-2006 Robert Shearman (for CodeWeavers) 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 * Note 00027 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED 00028 * Therefore do not test against COINIT_MULTITHREADED 00029 * 00030 * TODO list: (items bunched together depend on each other) 00031 * 00032 * - Implement the service control manager (in rpcss) to keep track 00033 * of registered class objects: ISCM::ServerRegisterClsid et al 00034 * - Implement the OXID resolver so we don't need magic endpoint names for 00035 * clients and servers to meet up 00036 * 00037 */ 00038 00039 #include "config.h" 00040 00041 #include <stdarg.h> 00042 #include <stdio.h> 00043 #include <string.h> 00044 #include <assert.h> 00045 00046 #define COBJMACROS 00047 #define NONAMELESSUNION 00048 #define NONAMELESSSTRUCT 00049 00050 #include "windef.h" 00051 #include "winbase.h" 00052 #include "winerror.h" 00053 #include "winreg.h" 00054 #include "winuser.h" 00055 #define USE_COM_CONTEXT_DEF 00056 #include "objbase.h" 00057 #include "ole2.h" 00058 #include "ole2ver.h" 00059 #include "ctxtcall.h" 00060 #include "dde.h" 00061 00062 #include "initguid.h" 00063 #include "compobj_private.h" 00064 #include "moniker.h" 00065 00066 #include "wine/unicode.h" 00067 #include "wine/debug.h" 00068 00069 WINE_DEFAULT_DEBUG_CHANNEL(ole); 00070 00071 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0])) 00072 00073 #ifdef _MSC_VER 00074 DEFINE_GUID(CLSID_PSFactoryBuffer, 0x00000320, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46); 00075 #endif 00076 00077 /**************************************************************************** 00078 * This section defines variables internal to the COM module. 00079 */ 00080 00081 static APARTMENT *MTA; /* protected by csApartment */ 00082 static APARTMENT *MainApartment; /* the first STA apartment */ 00083 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ 00084 00085 static CRITICAL_SECTION csApartment; 00086 static CRITICAL_SECTION_DEBUG critsect_debug = 00087 { 00088 0, 0, &csApartment, 00089 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 00090 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") } 00091 }; 00092 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 }; 00093 00094 struct registered_psclsid 00095 { 00096 struct list entry; 00097 IID iid; 00098 CLSID clsid; 00099 }; 00100 00101 /* 00102 * This lock count counts the number of times CoInitialize is called. It is 00103 * decreased every time CoUninitialize is called. When it hits 0, the COM 00104 * libraries are freed 00105 */ 00106 static LONG s_COMLockCount = 0; 00107 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */ 00108 static LONG s_COMServerProcessReferences = 0; 00109 00110 /* 00111 * This linked list contains the list of registered class objects. These 00112 * are mostly used to register the factories for out-of-proc servers of OLE 00113 * objects. 00114 * 00115 * TODO: Make this data structure aware of inter-process communication. This 00116 * means that parts of this will be exported to rpcss. 00117 */ 00118 typedef struct tagRegisteredClass 00119 { 00120 struct list entry; 00121 CLSID classIdentifier; 00122 OXID apartment_id; 00123 LPUNKNOWN classObject; 00124 DWORD runContext; 00125 DWORD connectFlags; 00126 DWORD dwCookie; 00127 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */ 00128 void *RpcRegistration; 00129 } RegisteredClass; 00130 00131 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList); 00132 00133 static CRITICAL_SECTION csRegisteredClassList; 00134 static CRITICAL_SECTION_DEBUG class_cs_debug = 00135 { 00136 0, 0, &csRegisteredClassList, 00137 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList }, 00138 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") } 00139 }; 00140 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 }; 00141 00142 /***************************************************************************** 00143 * This section contains OpenDllList definitions 00144 * 00145 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or 00146 * other functions that do LoadLibrary _without_ giving back a HMODULE. 00147 * Without this list these handles would never be freed. 00148 * 00149 * FIXME: a DLL that says OK when asked for unloading is unloaded in the 00150 * next unload-call but not before 600 sec. 00151 */ 00152 00153 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); 00154 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); 00155 00156 typedef struct tagOpenDll 00157 { 00158 LONG refs; 00159 LPWSTR library_name; 00160 HANDLE library; 00161 DllGetClassObjectFunc DllGetClassObject; 00162 DllCanUnloadNowFunc DllCanUnloadNow; 00163 struct list entry; 00164 } OpenDll; 00165 00166 static struct list openDllList = LIST_INIT(openDllList); 00167 00168 static CRITICAL_SECTION csOpenDllList; 00169 static CRITICAL_SECTION_DEBUG dll_cs_debug = 00170 { 00171 0, 0, &csOpenDllList, 00172 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList }, 00173 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") } 00174 }; 00175 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 }; 00176 00177 struct apartment_loaded_dll 00178 { 00179 struct list entry; 00180 OpenDll *dll; 00181 DWORD unload_time; 00182 BOOL multi_threaded; 00183 }; 00184 00185 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ', 00186 '0','x','#','#','#','#','#','#','#','#',' ',0}; 00187 00188 /***************************************************************************** 00189 * This section contains OpenDllList implementation 00190 */ 00191 00192 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name) 00193 { 00194 OpenDll *ptr; 00195 OpenDll *ret = NULL; 00196 EnterCriticalSection(&csOpenDllList); 00197 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry) 00198 { 00199 if (!strcmpiW(library_name, ptr->library_name) && 00200 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */) 00201 { 00202 ret = ptr; 00203 break; 00204 } 00205 } 00206 LeaveCriticalSection(&csOpenDllList); 00207 return ret; 00208 } 00209 00210 /* caller must ensure that library_name is not already in the open dll list */ 00211 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret) 00212 { 00213 OpenDll *entry; 00214 int len; 00215 HRESULT hr = S_OK; 00216 HANDLE hLibrary; 00217 DllCanUnloadNowFunc DllCanUnloadNow; 00218 DllGetClassObjectFunc DllGetClassObject; 00219 00220 TRACE("\n"); 00221 00222 *ret = COMPOBJ_DllList_Get(library_name); 00223 if (*ret) return S_OK; 00224 00225 /* do this outside the csOpenDllList to avoid creating a lock dependency on 00226 * the loader lock */ 00227 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH); 00228 if (!hLibrary) 00229 { 00230 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name)); 00231 /* failure: DLL could not be loaded */ 00232 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ 00233 } 00234 00235 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow"); 00236 /* Note: failing to find DllCanUnloadNow is not a failure */ 00237 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject"); 00238 if (!DllGetClassObject) 00239 { 00240 /* failure: the dll did not export DllGetClassObject */ 00241 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name)); 00242 FreeLibrary(hLibrary); 00243 return CO_E_DLLNOTFOUND; 00244 } 00245 00246 EnterCriticalSection( &csOpenDllList ); 00247 00248 *ret = COMPOBJ_DllList_Get(library_name); 00249 if (*ret) 00250 { 00251 /* another caller to this function already added the dll while we 00252 * weren't in the critical section */ 00253 FreeLibrary(hLibrary); 00254 } 00255 else 00256 { 00257 len = strlenW(library_name); 00258 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); 00259 if (entry) 00260 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); 00261 if (entry && entry->library_name) 00262 { 00263 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR)); 00264 entry->library = hLibrary; 00265 entry->refs = 1; 00266 entry->DllCanUnloadNow = DllCanUnloadNow; 00267 entry->DllGetClassObject = DllGetClassObject; 00268 list_add_tail(&openDllList, &entry->entry); 00269 } 00270 else 00271 { 00272 HeapFree(GetProcessHeap(), 0, entry); 00273 hr = E_OUTOFMEMORY; 00274 FreeLibrary(hLibrary); 00275 } 00276 *ret = entry; 00277 } 00278 00279 LeaveCriticalSection( &csOpenDllList ); 00280 00281 return hr; 00282 } 00283 00284 /* pass FALSE for free_entry to release a reference without destroying the 00285 * entry if it reaches zero or TRUE otherwise */ 00286 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry) 00287 { 00288 if (!InterlockedDecrement(&entry->refs) && free_entry) 00289 { 00290 EnterCriticalSection(&csOpenDllList); 00291 list_remove(&entry->entry); 00292 LeaveCriticalSection(&csOpenDllList); 00293 00294 TRACE("freeing %p\n", entry->library); 00295 FreeLibrary(entry->library); 00296 00297 HeapFree(GetProcessHeap(), 0, entry->library_name); 00298 HeapFree(GetProcessHeap(), 0, entry); 00299 } 00300 } 00301 00302 /* frees memory associated with active dll list */ 00303 static void COMPOBJ_DllList_Free(void) 00304 { 00305 OpenDll *entry, *cursor2; 00306 EnterCriticalSection(&csOpenDllList); 00307 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry) 00308 { 00309 list_remove(&entry->entry); 00310 00311 HeapFree(GetProcessHeap(), 0, entry->library_name); 00312 HeapFree(GetProcessHeap(), 0, entry); 00313 } 00314 LeaveCriticalSection(&csOpenDllList); 00315 DeleteCriticalSection(&csOpenDllList); 00316 } 00317 00318 /****************************************************************************** 00319 * Manage apartments. 00320 */ 00321 00322 static DWORD apartment_addref(struct apartment *apt) 00323 { 00324 DWORD refs = InterlockedIncrement(&apt->refs); 00325 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1); 00326 return refs; 00327 } 00328 00329 /* allocates memory and fills in the necessary fields for a new apartment 00330 * object. must be called inside apartment cs */ 00331 static APARTMENT *apartment_construct(DWORD model) 00332 { 00333 APARTMENT *apt; 00334 00335 TRACE("creating new apartment, model=%d\n", model); 00336 00337 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt)); 00338 apt->tid = GetCurrentThreadId(); 00339 00340 list_init(&apt->proxies); 00341 list_init(&apt->stubmgrs); 00342 list_init(&apt->psclsids); 00343 list_init(&apt->loaded_dlls); 00344 apt->ipidc = 0; 00345 apt->refs = 1; 00346 apt->remunk_exported = FALSE; 00347 apt->oidc = 1; 00348 InitializeCriticalSection(&apt->cs); 00349 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); 00350 00351 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED); 00352 00353 if (apt->multi_threaded) 00354 { 00355 /* FIXME: should be randomly generated by in an RPC call to rpcss */ 00356 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe; 00357 } 00358 else 00359 { 00360 /* FIXME: should be randomly generated by in an RPC call to rpcss */ 00361 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); 00362 } 00363 00364 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); 00365 00366 list_add_head(&apts, &apt->entry); 00367 00368 return apt; 00369 } 00370 00371 /* gets and existing apartment if one exists or otherwise creates an apartment 00372 * structure which stores OLE apartment-local information and stores a pointer 00373 * to it in the thread-local storage */ 00374 static APARTMENT *apartment_get_or_create(DWORD model) 00375 { 00376 APARTMENT *apt = COM_CurrentApt(); 00377 00378 if (!apt) 00379 { 00380 if (model & COINIT_APARTMENTTHREADED) 00381 { 00382 EnterCriticalSection(&csApartment); 00383 00384 apt = apartment_construct(model); 00385 if (!MainApartment) 00386 { 00387 MainApartment = apt; 00388 apt->main = TRUE; 00389 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid)); 00390 } 00391 00392 LeaveCriticalSection(&csApartment); 00393 00394 if (apt->main) 00395 apartment_createwindowifneeded(apt); 00396 } 00397 else 00398 { 00399 EnterCriticalSection(&csApartment); 00400 00401 /* The multi-threaded apartment (MTA) contains zero or more threads interacting 00402 * with free threaded (ie thread safe) COM objects. There is only ever one MTA 00403 * in a process */ 00404 if (MTA) 00405 { 00406 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid)); 00407 apartment_addref(MTA); 00408 } 00409 else 00410 MTA = apartment_construct(model); 00411 00412 apt = MTA; 00413 00414 LeaveCriticalSection(&csApartment); 00415 } 00416 COM_CurrentInfo()->apt = apt; 00417 } 00418 00419 return apt; 00420 } 00421 00422 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model) 00423 { 00424 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); 00425 } 00426 00427 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) 00428 { 00429 list_remove(&curClass->entry); 00430 00431 if (curClass->runContext & CLSCTX_LOCAL_SERVER) 00432 RPC_StopLocalServer(curClass->RpcRegistration); 00433 00434 /* 00435 * Release the reference to the class object. 00436 */ 00437 IUnknown_Release(curClass->classObject); 00438 00439 if (curClass->pMarshaledData) 00440 { 00441 LARGE_INTEGER zero; 00442 memset(&zero, 0, sizeof(zero)); 00443 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL); 00444 CoReleaseMarshalData(curClass->pMarshaledData); 00445 IStream_Release(curClass->pMarshaledData); 00446 } 00447 00448 HeapFree(GetProcessHeap(), 0, curClass); 00449 } 00450 00451 static void COM_RevokeAllClasses(const struct apartment *apt) 00452 { 00453 RegisteredClass *curClass, *cursor; 00454 00455 EnterCriticalSection( &csRegisteredClassList ); 00456 00457 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry) 00458 { 00459 if (curClass->apartment_id == apt->oxid) 00460 COM_RevokeRegisteredClassObject(curClass); 00461 } 00462 00463 LeaveCriticalSection( &csRegisteredClassList ); 00464 } 00465 00466 /****************************************************************************** 00467 * Implementation of the manual reset event object. (CLSID_ManualResetEvent) 00468 */ 00469 00470 typedef struct ManualResetEvent { 00471 ISynchronize ISynchronize_iface; 00472 LONG ref; 00473 HANDLE event; 00474 } MREImpl; 00475 00476 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface) 00477 { 00478 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface); 00479 } 00480 00481 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv) 00482 { 00483 MREImpl *This = impl_from_ISynchronize(iface); 00484 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv); 00485 00486 *ppv = NULL; 00487 if(IsEqualGUID(riid, &IID_IUnknown) || 00488 IsEqualGUID(riid, &IID_ISynchronize)) 00489 *ppv = This; 00490 else 00491 ERR("Unknown interface %s requested.\n", debugstr_guid(riid)); 00492 00493 if(*ppv) 00494 { 00495 IUnknown_AddRef((IUnknown*)*ppv); 00496 return S_OK; 00497 } 00498 00499 return E_NOINTERFACE; 00500 } 00501 00502 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface) 00503 { 00504 MREImpl *This = impl_from_ISynchronize(iface); 00505 LONG ref = InterlockedIncrement(&This->ref); 00506 TRACE("%p - ref %d\n", This, ref); 00507 00508 return ref; 00509 } 00510 00511 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface) 00512 { 00513 MREImpl *This = impl_from_ISynchronize(iface); 00514 LONG ref = InterlockedDecrement(&This->ref); 00515 TRACE("%p - ref %d\n", This, ref); 00516 00517 if(!ref) 00518 { 00519 CloseHandle(This->event); 00520 HeapFree(GetProcessHeap(), 0, This); 00521 } 00522 00523 return ref; 00524 } 00525 00526 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds) 00527 { 00528 MREImpl *This = impl_from_ISynchronize(iface); 00529 UINT index; 00530 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds); 00531 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index); 00532 } 00533 00534 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface) 00535 { 00536 MREImpl *This = impl_from_ISynchronize(iface); 00537 TRACE("%p\n", This); 00538 SetEvent(This->event); 00539 return S_OK; 00540 } 00541 00542 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface) 00543 { 00544 MREImpl *This = impl_from_ISynchronize(iface); 00545 TRACE("%p\n", This); 00546 ResetEvent(This->event); 00547 return S_OK; 00548 } 00549 00550 static ISynchronizeVtbl vt_ISynchronize = { 00551 ISynchronize_fnQueryInterface, 00552 ISynchronize_fnAddRef, 00553 ISynchronize_fnRelease, 00554 ISynchronize_fnWait, 00555 ISynchronize_fnSignal, 00556 ISynchronize_fnReset 00557 }; 00558 00559 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv) 00560 { 00561 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl)); 00562 HRESULT hr; 00563 00564 if(punkouter) 00565 FIXME("Aggregation not implemented.\n"); 00566 00567 This->ref = 1; 00568 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize; 00569 This->event = CreateEventW(NULL, TRUE, FALSE, NULL); 00570 00571 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv); 00572 ISynchronize_Release(&This->ISynchronize_iface); 00573 return hr; 00574 } 00575 00576 /*********************************************************************** 00577 * CoRevokeClassObject [OLE32.@] 00578 * 00579 * Removes a class object from the class registry. 00580 * 00581 * PARAMS 00582 * dwRegister [I] Cookie returned from CoRegisterClassObject(). 00583 * 00584 * RETURNS 00585 * Success: S_OK. 00586 * Failure: HRESULT code. 00587 * 00588 * NOTES 00589 * Must be called from the same apartment that called CoRegisterClassObject(), 00590 * otherwise it will fail with RPC_E_WRONG_THREAD. 00591 * 00592 * SEE ALSO 00593 * CoRegisterClassObject 00594 */ 00595 HRESULT WINAPI CoRevokeClassObject( 00596 DWORD dwRegister) 00597 { 00598 HRESULT hr = E_INVALIDARG; 00599 RegisteredClass *curClass; 00600 APARTMENT *apt; 00601 00602 TRACE("(%08x)\n",dwRegister); 00603 00604 apt = COM_CurrentApt(); 00605 if (!apt) 00606 { 00607 ERR("COM was not initialized\n"); 00608 return CO_E_NOTINITIALIZED; 00609 } 00610 00611 EnterCriticalSection( &csRegisteredClassList ); 00612 00613 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) 00614 { 00615 /* 00616 * Check if we have a match on the cookie. 00617 */ 00618 if (curClass->dwCookie == dwRegister) 00619 { 00620 if (curClass->apartment_id == apt->oxid) 00621 { 00622 COM_RevokeRegisteredClassObject(curClass); 00623 hr = S_OK; 00624 } 00625 else 00626 { 00627 ERR("called from wrong apartment, should be called from %s\n", 00628 wine_dbgstr_longlong(curClass->apartment_id)); 00629 hr = RPC_E_WRONG_THREAD; 00630 } 00631 break; 00632 } 00633 } 00634 00635 LeaveCriticalSection( &csRegisteredClassList ); 00636 00637 return hr; 00638 } 00639 00640 /* frees unused libraries loaded by apartment_getclassobject by calling the 00641 * DLL's DllCanUnloadNow entry point */ 00642 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) 00643 { 00644 struct apartment_loaded_dll *entry, *next; 00645 EnterCriticalSection(&apt->cs); 00646 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry) 00647 { 00648 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK)) 00649 { 00650 DWORD real_delay = delay; 00651 00652 if (real_delay == INFINITE) 00653 { 00654 /* DLLs that return multi-threaded objects aren't unloaded 00655 * straight away to cope for programs that have races between 00656 * last object destruction and threads in the DLLs that haven't 00657 * finished, despite DllCanUnloadNow returning S_OK */ 00658 if (entry->multi_threaded) 00659 real_delay = 10 * 60 * 1000; /* 10 minutes */ 00660 else 00661 real_delay = 0; 00662 } 00663 00664 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount()))) 00665 { 00666 list_remove(&entry->entry); 00667 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE); 00668 HeapFree(GetProcessHeap(), 0, entry); 00669 } 00670 else 00671 entry->unload_time = GetTickCount() + real_delay; 00672 } 00673 else if (entry->unload_time) 00674 entry->unload_time = 0; 00675 } 00676 LeaveCriticalSection(&apt->cs); 00677 } 00678 00679 DWORD apartment_release(struct apartment *apt) 00680 { 00681 DWORD ret; 00682 00683 EnterCriticalSection(&csApartment); 00684 00685 ret = InterlockedDecrement(&apt->refs); 00686 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret); 00687 /* destruction stuff that needs to happen under csApartment CS */ 00688 if (ret == 0) 00689 { 00690 if (apt == MTA) MTA = NULL; 00691 else if (apt == MainApartment) MainApartment = NULL; 00692 list_remove(&apt->entry); 00693 } 00694 00695 LeaveCriticalSection(&csApartment); 00696 00697 if (ret == 0) 00698 { 00699 struct list *cursor, *cursor2; 00700 00701 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); 00702 00703 /* Release the references to the registered class objects */ 00704 COM_RevokeAllClasses(apt); 00705 00706 /* no locking is needed for this apartment, because no other thread 00707 * can access it at this point */ 00708 00709 apartment_disconnectproxies(apt); 00710 00711 if (apt->win) DestroyWindow(apt->win); 00712 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0); 00713 00714 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs) 00715 { 00716 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry); 00717 /* release the implicit reference given by the fact that the 00718 * stub has external references (it must do since it is in the 00719 * stub manager list in the apartment and all non-apartment users 00720 * must have a ref on the apartment and so it cannot be destroyed). 00721 */ 00722 stub_manager_int_release(stubmgr); 00723 } 00724 00725 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids) 00726 { 00727 struct registered_psclsid *registered_psclsid = 00728 LIST_ENTRY(cursor, struct registered_psclsid, entry); 00729 00730 list_remove(®istered_psclsid->entry); 00731 HeapFree(GetProcessHeap(), 0, registered_psclsid); 00732 } 00733 00734 /* if this assert fires, then another thread took a reference to a 00735 * stub manager without taking a reference to the containing 00736 * apartment, which it must do. */ 00737 assert(list_empty(&apt->stubmgrs)); 00738 00739 if (apt->filter) IUnknown_Release(apt->filter); 00740 00741 /* free as many unused libraries as possible... */ 00742 apartment_freeunusedlibraries(apt, 0); 00743 00744 /* ... and free the memory for the apartment loaded dll entry and 00745 * release the dll list reference without freeing the library for the 00746 * rest */ 00747 while ((cursor = list_head(&apt->loaded_dlls))) 00748 { 00749 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry); 00750 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE); 00751 list_remove(cursor); 00752 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); 00753 } 00754 00755 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); 00756 DeleteCriticalSection(&apt->cs); 00757 00758 HeapFree(GetProcessHeap(), 0, apt); 00759 } 00760 00761 return ret; 00762 } 00763 00764 /* The given OXID must be local to this process: 00765 * 00766 * The ref parameter is here mostly to ensure people remember that 00767 * they get one, you should normally take a ref for thread safety. 00768 */ 00769 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref) 00770 { 00771 APARTMENT *result = NULL; 00772 struct list *cursor; 00773 00774 EnterCriticalSection(&csApartment); 00775 LIST_FOR_EACH( cursor, &apts ) 00776 { 00777 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); 00778 if (apt->oxid == oxid) 00779 { 00780 result = apt; 00781 if (ref) apartment_addref(result); 00782 break; 00783 } 00784 } 00785 LeaveCriticalSection(&csApartment); 00786 00787 return result; 00788 } 00789 00790 /* gets the apartment which has a given creator thread ID. The caller must 00791 * release the reference from the apartment as soon as the apartment pointer 00792 * is no longer required. */ 00793 APARTMENT *apartment_findfromtid(DWORD tid) 00794 { 00795 APARTMENT *result = NULL; 00796 struct list *cursor; 00797 00798 EnterCriticalSection(&csApartment); 00799 LIST_FOR_EACH( cursor, &apts ) 00800 { 00801 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); 00802 if (apt->tid == tid) 00803 { 00804 result = apt; 00805 apartment_addref(result); 00806 break; 00807 } 00808 } 00809 LeaveCriticalSection(&csApartment); 00810 00811 return result; 00812 } 00813 00814 /* gets the main apartment if it exists. The caller must 00815 * release the reference from the apartment as soon as the apartment pointer 00816 * is no longer required. */ 00817 static APARTMENT *apartment_findmain(void) 00818 { 00819 APARTMENT *result; 00820 00821 EnterCriticalSection(&csApartment); 00822 00823 result = MainApartment; 00824 if (result) apartment_addref(result); 00825 00826 LeaveCriticalSection(&csApartment); 00827 00828 return result; 00829 } 00830 00831 /* gets the multi-threaded apartment if it exists. The caller must 00832 * release the reference from the apartment as soon as the apartment pointer 00833 * is no longer required. */ 00834 static APARTMENT *apartment_find_multi_threaded(void) 00835 { 00836 APARTMENT *result = NULL; 00837 struct list *cursor; 00838 00839 EnterCriticalSection(&csApartment); 00840 00841 LIST_FOR_EACH( cursor, &apts ) 00842 { 00843 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); 00844 if (apt->multi_threaded) 00845 { 00846 result = apt; 00847 apartment_addref(result); 00848 break; 00849 } 00850 } 00851 00852 LeaveCriticalSection(&csApartment); 00853 return result; 00854 } 00855 00856 /* gets the specified class object by loading the appropriate DLL, if 00857 * necessary and calls the DllGetClassObject function for the DLL */ 00858 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, 00859 BOOL apartment_threaded, 00860 REFCLSID rclsid, REFIID riid, void **ppv) 00861 { 00862 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; 00863 HRESULT hr = S_OK; 00864 BOOL found = FALSE; 00865 struct apartment_loaded_dll *apartment_loaded_dll; 00866 00867 if (!strcmpiW(dllpath, wszOle32)) 00868 { 00869 /* we don't need to control the lifetime of this dll, so use the local 00870 * implementation of DllGetClassObject directly */ 00871 TRACE("calling ole32!DllGetClassObject\n"); 00872 hr = DllGetClassObject(rclsid, riid, ppv); 00873 00874 if (hr != S_OK) 00875 ERR("DllGetClassObject returned error 0x%08x\n", hr); 00876 00877 return hr; 00878 } 00879 00880 EnterCriticalSection(&apt->cs); 00881 00882 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry) 00883 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name)) 00884 { 00885 TRACE("found %s already loaded\n", debugstr_w(dllpath)); 00886 found = TRUE; 00887 break; 00888 } 00889 00890 if (!found) 00891 { 00892 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll)); 00893 if (!apartment_loaded_dll) 00894 hr = E_OUTOFMEMORY; 00895 if (SUCCEEDED(hr)) 00896 { 00897 apartment_loaded_dll->unload_time = 0; 00898 apartment_loaded_dll->multi_threaded = FALSE; 00899 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll ); 00900 if (FAILED(hr)) 00901 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); 00902 } 00903 if (SUCCEEDED(hr)) 00904 { 00905 TRACE("added new loaded dll %s\n", debugstr_w(dllpath)); 00906 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry); 00907 } 00908 } 00909 00910 LeaveCriticalSection(&apt->cs); 00911 00912 if (SUCCEEDED(hr)) 00913 { 00914 /* one component being multi-threaded overrides any number of 00915 * apartment-threaded components */ 00916 if (!apartment_threaded) 00917 apartment_loaded_dll->multi_threaded = TRUE; 00918 00919 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject); 00920 /* OK: get the ClassObject */ 00921 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv); 00922 00923 if (hr != S_OK) 00924 ERR("DllGetClassObject returned error 0x%08x\n", hr); 00925 } 00926 00927 return hr; 00928 } 00929 00930 /*********************************************************************** 00931 * COM_RegReadPath [internal] 00932 * 00933 * Reads a registry value and expands it when necessary 00934 */ 00935 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen) 00936 { 00937 DWORD ret; 00938 HKEY key; 00939 DWORD keytype; 00940 WCHAR src[MAX_PATH]; 00941 DWORD dwLength = dstlen * sizeof(WCHAR); 00942 00943 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) { 00944 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) { 00945 if (keytype == REG_EXPAND_SZ) { 00946 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA; 00947 } else { 00948 const WCHAR *quote_start; 00949 quote_start = strchrW(src, '\"'); 00950 if (quote_start) { 00951 const WCHAR *quote_end = strchrW(quote_start + 1, '\"'); 00952 if (quote_end) { 00953 memmove(src, quote_start + 1, 00954 (quote_end - quote_start - 1) * sizeof(WCHAR)); 00955 src[quote_end - quote_start - 1] = '\0'; 00956 } 00957 } 00958 lstrcpynW(dst, src, dstlen); 00959 } 00960 } 00961 RegCloseKey (key); 00962 } 00963 return ret; 00964 } 00965 00966 struct host_object_params 00967 { 00968 HKEY hkeydll; 00969 CLSID clsid; /* clsid of object to marshal */ 00970 IID iid; /* interface to marshal */ 00971 HANDLE event; /* event signalling when ready for multi-threaded case */ 00972 HRESULT hr; /* result for multi-threaded case */ 00973 IStream *stream; /* stream that the object will be marshaled into */ 00974 BOOL apartment_threaded; /* is the component purely apartment-threaded? */ 00975 }; 00976 00977 static HRESULT apartment_hostobject(struct apartment *apt, 00978 const struct host_object_params *params) 00979 { 00980 IUnknown *object; 00981 HRESULT hr; 00982 static const LARGE_INTEGER llZero; 00983 WCHAR dllpath[MAX_PATH+1]; 00984 00985 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid)); 00986 00987 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) 00988 { 00989 /* failure: CLSID is not found in registry */ 00990 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid)); 00991 return REGDB_E_CLASSNOTREG; 00992 } 00993 00994 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded, 00995 ¶ms->clsid, ¶ms->iid, (void **)&object); 00996 if (FAILED(hr)) 00997 return hr; 00998 00999 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); 01000 if (FAILED(hr)) 01001 IUnknown_Release(object); 01002 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL); 01003 01004 return hr; 01005 } 01006 01007 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 01008 { 01009 switch (msg) 01010 { 01011 case DM_EXECUTERPC: 01012 RPC_ExecuteCall((struct dispatch_params *)lParam); 01013 return 0; 01014 case DM_HOSTOBJECT: 01015 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam); 01016 default: 01017 return DefWindowProcW(hWnd, msg, wParam, lParam); 01018 } 01019 } 01020 01021 struct host_thread_params 01022 { 01023 COINIT threading_model; 01024 HANDLE ready_event; 01025 HWND apartment_hwnd; 01026 }; 01027 01028 /* thread for hosting an object to allow an object to appear to be created in 01029 * an apartment with an incompatible threading model */ 01030 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p) 01031 { 01032 struct host_thread_params *params = p; 01033 MSG msg; 01034 HRESULT hr; 01035 struct apartment *apt; 01036 01037 TRACE("\n"); 01038 01039 hr = CoInitializeEx(NULL, params->threading_model); 01040 if (FAILED(hr)) return hr; 01041 01042 apt = COM_CurrentApt(); 01043 if (params->threading_model == COINIT_APARTMENTTHREADED) 01044 { 01045 apartment_createwindowifneeded(apt); 01046 params->apartment_hwnd = apartment_getwindow(apt); 01047 } 01048 else 01049 params->apartment_hwnd = NULL; 01050 01051 /* force the message queue to be created before signaling parent thread */ 01052 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); 01053 01054 SetEvent(params->ready_event); 01055 params = NULL; /* can't touch params after here as it may be invalid */ 01056 01057 while (GetMessageW(&msg, NULL, 0, 0)) 01058 { 01059 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT)) 01060 { 01061 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam; 01062 obj_params->hr = apartment_hostobject(apt, obj_params); 01063 SetEvent(obj_params->event); 01064 } 01065 else 01066 { 01067 TranslateMessage(&msg); 01068 DispatchMessageW(&msg); 01069 } 01070 } 01071 01072 TRACE("exiting\n"); 01073 01074 CoUninitialize(); 01075 01076 return S_OK; 01077 } 01078 01079 /* finds or creates a host apartment, creates the object inside it and returns 01080 * a proxy to it so that the object can be used in the apartment of the 01081 * caller of this function */ 01082 static HRESULT apartment_hostobject_in_hostapt( 01083 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, 01084 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv) 01085 { 01086 struct host_object_params params; 01087 HWND apartment_hwnd = NULL; 01088 DWORD apartment_tid = 0; 01089 HRESULT hr; 01090 01091 if (!multi_threaded && main_apartment) 01092 { 01093 APARTMENT *host_apt = apartment_findmain(); 01094 if (host_apt) 01095 { 01096 apartment_hwnd = apartment_getwindow(host_apt); 01097 apartment_release(host_apt); 01098 } 01099 } 01100 01101 if (!apartment_hwnd) 01102 { 01103 EnterCriticalSection(&apt->cs); 01104 01105 if (!apt->host_apt_tid) 01106 { 01107 struct host_thread_params thread_params; 01108 HANDLE handles[2]; 01109 DWORD wait_value; 01110 01111 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED; 01112 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); 01113 thread_params.apartment_hwnd = NULL; 01114 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid); 01115 if (!handles[1]) 01116 { 01117 CloseHandle(handles[0]); 01118 LeaveCriticalSection(&apt->cs); 01119 return E_OUTOFMEMORY; 01120 } 01121 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 01122 CloseHandle(handles[0]); 01123 CloseHandle(handles[1]); 01124 if (wait_value == WAIT_OBJECT_0) 01125 apt->host_apt_hwnd = thread_params.apartment_hwnd; 01126 else 01127 { 01128 LeaveCriticalSection(&apt->cs); 01129 return E_OUTOFMEMORY; 01130 } 01131 } 01132 01133 if (multi_threaded || !main_apartment) 01134 { 01135 apartment_hwnd = apt->host_apt_hwnd; 01136 apartment_tid = apt->host_apt_tid; 01137 } 01138 01139 LeaveCriticalSection(&apt->cs); 01140 } 01141 01142 /* another thread may have become the main apartment in the time it took 01143 * us to create the thread for the host apartment */ 01144 if (!apartment_hwnd && !multi_threaded && main_apartment) 01145 { 01146 APARTMENT *host_apt = apartment_findmain(); 01147 if (host_apt) 01148 { 01149 apartment_hwnd = apartment_getwindow(host_apt); 01150 apartment_release(host_apt); 01151 } 01152 } 01153 01154 params.hkeydll = hkeydll; 01155 params.clsid = *rclsid; 01156 params.iid = *riid; 01157 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); 01158 if (FAILED(hr)) 01159 return hr; 01160 params.apartment_threaded = !multi_threaded; 01161 if (multi_threaded) 01162 { 01163 params.hr = S_OK; 01164 params.event = CreateEventW(NULL, FALSE, FALSE, NULL); 01165 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms)) 01166 hr = E_OUTOFMEMORY; 01167 else 01168 { 01169 WaitForSingleObject(params.event, INFINITE); 01170 hr = params.hr; 01171 } 01172 CloseHandle(params.event); 01173 } 01174 else 01175 { 01176 if (!apartment_hwnd) 01177 { 01178 ERR("host apartment didn't create window\n"); 01179 hr = E_OUTOFMEMORY; 01180 } 01181 else 01182 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); 01183 } 01184 if (SUCCEEDED(hr)) 01185 hr = CoUnmarshalInterface(params.stream, riid, ppv); 01186 IStream_Release(params.stream); 01187 return hr; 01188 } 01189 01190 /* create a window for the apartment or return the current one if one has 01191 * already been created */ 01192 HRESULT apartment_createwindowifneeded(struct apartment *apt) 01193 { 01194 if (apt->multi_threaded) 01195 return S_OK; 01196 01197 if (!apt->win) 01198 { 01199 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 01200 0, 0, 0, 0, 01201 HWND_MESSAGE, 0, hProxyDll, NULL); 01202 if (!hwnd) 01203 { 01204 ERR("CreateWindow failed with error %d\n", GetLastError()); 01205 return HRESULT_FROM_WIN32(GetLastError()); 01206 } 01207 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL)) 01208 /* someone beat us to it */ 01209 DestroyWindow(hwnd); 01210 } 01211 01212 return S_OK; 01213 } 01214 01215 /* retrieves the window for the main- or apartment-threaded apartment */ 01216 HWND apartment_getwindow(const struct apartment *apt) 01217 { 01218 assert(!apt->multi_threaded); 01219 return apt->win; 01220 } 01221 01222 void apartment_joinmta(void) 01223 { 01224 apartment_addref(MTA); 01225 COM_CurrentInfo()->apt = MTA; 01226 } 01227 01228 static void COMPOBJ_InitProcess( void ) 01229 { 01230 WNDCLASSW wclass; 01231 01232 /* Dispatching to the correct thread in an apartment is done through 01233 * window messages rather than RPC transports. When an interface is 01234 * marshalled into another apartment in the same process, a window of the 01235 * following class is created. The *caller* of CoMarshalInterface (i.e., the 01236 * application) is responsible for pumping the message loop in that thread. 01237 * The WM_USER messages which point to the RPCs are then dispatched to 01238 * apartment_wndproc by the user's code from the apartment in which the 01239 * interface was unmarshalled. 01240 */ 01241 memset(&wclass, 0, sizeof(wclass)); 01242 wclass.lpfnWndProc = apartment_wndproc; 01243 wclass.hInstance = hProxyDll; 01244 wclass.lpszClassName = wszAptWinClass; 01245 RegisterClassW(&wclass); 01246 } 01247 01248 static void COMPOBJ_UninitProcess( void ) 01249 { 01250 UnregisterClassW(wszAptWinClass, hProxyDll); 01251 } 01252 01253 static void COM_TlsDestroy(void) 01254 { 01255 struct oletls *info = NtCurrentTeb()->ReservedForOle; 01256 if (info) 01257 { 01258 if (info->apt) apartment_release(info->apt); 01259 if (info->errorinfo) IErrorInfo_Release(info->errorinfo); 01260 if (info->state) IUnknown_Release(info->state); 01261 if (info->spy) IUnknown_Release(info->spy); 01262 if (info->context_token) IObjContext_Release(info->context_token); 01263 HeapFree(GetProcessHeap(), 0, info); 01264 NtCurrentTeb()->ReservedForOle = NULL; 01265 } 01266 } 01267 01268 /****************************************************************************** 01269 * CoBuildVersion [OLE32.@] 01270 * 01271 * Gets the build version of the DLL. 01272 * 01273 * PARAMS 01274 * 01275 * RETURNS 01276 * Current build version, hiword is majornumber, loword is minornumber 01277 */ 01278 DWORD WINAPI CoBuildVersion(void) 01279 { 01280 TRACE("Returning version %d, build %d.\n", rmm, rup); 01281 return (rmm<<16)+rup; 01282 } 01283 01284 /****************************************************************************** 01285 * CoRegisterInitializeSpy [OLE32.@] 01286 * 01287 * Add a Spy that watches CoInitializeEx calls 01288 * 01289 * PARAMS 01290 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd. 01291 * cookie [II] cookie receiver 01292 * 01293 * RETURNS 01294 * Success: S_OK if not already initialized, S_FALSE otherwise. 01295 * Failure: HRESULT code. 01296 * 01297 * SEE ALSO 01298 * CoInitializeEx 01299 */ 01300 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie) 01301 { 01302 struct oletls *info = COM_CurrentInfo(); 01303 HRESULT hr; 01304 01305 TRACE("(%p, %p)\n", spy, cookie); 01306 01307 if (!spy || !cookie || !info) 01308 { 01309 if (!info) 01310 WARN("Could not allocate tls\n"); 01311 return E_INVALIDARG; 01312 } 01313 01314 if (info->spy) 01315 { 01316 FIXME("Already registered?\n"); 01317 return E_UNEXPECTED; 01318 } 01319 01320 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy); 01321 if (SUCCEEDED(hr)) 01322 { 01323 cookie->QuadPart = (DWORD_PTR)spy; 01324 return S_OK; 01325 } 01326 return hr; 01327 } 01328 01329 /****************************************************************************** 01330 * CoRevokeInitializeSpy [OLE32.@] 01331 * 01332 * Remove a spy that previously watched CoInitializeEx calls 01333 * 01334 * PARAMS 01335 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call 01336 * 01337 * RETURNS 01338 * Success: S_OK if a spy is removed 01339 * Failure: E_INVALIDARG 01340 * 01341 * SEE ALSO 01342 * CoInitializeEx 01343 */ 01344 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie) 01345 { 01346 struct oletls *info = COM_CurrentInfo(); 01347 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart)); 01348 01349 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy) 01350 return E_INVALIDARG; 01351 01352 IUnknown_Release(info->spy); 01353 info->spy = NULL; 01354 return S_OK; 01355 } 01356 01357 01358 /****************************************************************************** 01359 * CoInitialize [OLE32.@] 01360 * 01361 * Initializes the COM libraries by calling CoInitializeEx with 01362 * COINIT_APARTMENTTHREADED, ie it enters a STA thread. 01363 * 01364 * PARAMS 01365 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). 01366 * 01367 * RETURNS 01368 * Success: S_OK if not already initialized, S_FALSE otherwise. 01369 * Failure: HRESULT code. 01370 * 01371 * SEE ALSO 01372 * CoInitializeEx 01373 */ 01374 HRESULT WINAPI CoInitialize(LPVOID lpReserved) 01375 { 01376 /* 01377 * Just delegate to the newer method. 01378 */ 01379 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED); 01380 } 01381 01382 /****************************************************************************** 01383 * CoInitializeEx [OLE32.@] 01384 * 01385 * Initializes the COM libraries. 01386 * 01387 * PARAMS 01388 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). 01389 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes. 01390 * 01391 * RETURNS 01392 * S_OK if successful, 01393 * S_FALSE if this function was called already. 01394 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another 01395 * threading model. 01396 * 01397 * NOTES 01398 * 01399 * The behavior used to set the IMalloc used for memory management is 01400 * obsolete. 01401 * The dwCoInit parameter must specify one of the following apartment 01402 * threading models: 01403 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA). 01404 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA). 01405 * The parameter may also specify zero or more of the following flags: 01406 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support. 01407 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed. 01408 * 01409 * SEE ALSO 01410 * CoUninitialize 01411 */ 01412 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit) 01413 { 01414 struct oletls *info = COM_CurrentInfo(); 01415 HRESULT hr = S_OK; 01416 APARTMENT *apt; 01417 01418 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit); 01419 01420 if (lpReserved!=NULL) 01421 { 01422 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved); 01423 } 01424 01425 /* 01426 * Check the lock count. If this is the first time going through the initialize 01427 * process, we have to initialize the libraries. 01428 * 01429 * And crank-up that lock count. 01430 */ 01431 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0) 01432 { 01433 /* 01434 * Initialize the various COM libraries and data structures. 01435 */ 01436 TRACE("() - Initializing the COM libraries\n"); 01437 01438 /* we may need to defer this until after apartment initialisation */ 01439 RunningObjectTableImpl_Initialize(); 01440 } 01441 01442 if (info->spy) 01443 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits); 01444 01445 if (!(apt = info->apt)) 01446 { 01447 apt = apartment_get_or_create(dwCoInit); 01448 if (!apt) return E_OUTOFMEMORY; 01449 } 01450 else if (!apartment_is_model(apt, dwCoInit)) 01451 { 01452 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine 01453 code then we are probably using the wrong threading model to implement that API. */ 01454 ERR("Attempt to change threading model of this apartment from %s to %s\n", 01455 apt->multi_threaded ? "multi-threaded" : "apartment threaded", 01456 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded"); 01457 return RPC_E_CHANGED_MODE; 01458 } 01459 else 01460 hr = S_FALSE; 01461 01462 info->inits++; 01463 01464 if (info->spy) 01465 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits); 01466 01467 return hr; 01468 } 01469 01470 /*********************************************************************** 01471 * CoUninitialize [OLE32.@] 01472 * 01473 * This method will decrement the refcount on the current apartment, freeing 01474 * the resources associated with it if it is the last thread in the apartment. 01475 * If the last apartment is freed, the function will additionally release 01476 * any COM resources associated with the process. 01477 * 01478 * PARAMS 01479 * 01480 * RETURNS 01481 * Nothing. 01482 * 01483 * SEE ALSO 01484 * CoInitializeEx 01485 */ 01486 void WINAPI CoUninitialize(void) 01487 { 01488 struct oletls * info = COM_CurrentInfo(); 01489 LONG lCOMRefCnt; 01490 01491 TRACE("()\n"); 01492 01493 /* will only happen on OOM */ 01494 if (!info) return; 01495 01496 if (info->spy) 01497 IInitializeSpy_PreUninitialize(info->spy, info->inits); 01498 01499 /* sanity check */ 01500 if (!info->inits) 01501 { 01502 ERR("Mismatched CoUninitialize\n"); 01503 01504 if (info->spy) 01505 IInitializeSpy_PostUninitialize(info->spy, info->inits); 01506 return; 01507 } 01508 01509 if (!--info->inits) 01510 { 01511 apartment_release(info->apt); 01512 info->apt = NULL; 01513 } 01514 01515 /* 01516 * Decrease the reference count. 01517 * If we are back to 0 locks on the COM library, make sure we free 01518 * all the associated data structures. 01519 */ 01520 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1); 01521 if (lCOMRefCnt==1) 01522 { 01523 TRACE("() - Releasing the COM libraries\n"); 01524 01525 RunningObjectTableImpl_UnInitialize(); 01526 } 01527 else if (lCOMRefCnt<1) { 01528 ERR( "CoUninitialize() - not CoInitialized.\n" ); 01529 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */ 01530 } 01531 if (info->spy) 01532 IInitializeSpy_PostUninitialize(info->spy, info->inits); 01533 } 01534 01535 /****************************************************************************** 01536 * CoDisconnectObject [OLE32.@] 01537 * 01538 * Disconnects all connections to this object from remote processes. Dispatches 01539 * pending RPCs while blocking new RPCs from occurring, and then calls 01540 * IMarshal::DisconnectObject on the given object. 01541 * 01542 * Typically called when the object server is forced to shut down, for instance by 01543 * the user. 01544 * 01545 * PARAMS 01546 * lpUnk [I] The object whose stub should be disconnected. 01547 * reserved [I] Reserved. Should be set to 0. 01548 * 01549 * RETURNS 01550 * Success: S_OK. 01551 * Failure: HRESULT code. 01552 * 01553 * SEE ALSO 01554 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal 01555 */ 01556 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) 01557 { 01558 HRESULT hr; 01559 IMarshal *marshal; 01560 APARTMENT *apt; 01561 01562 TRACE("(%p, 0x%08x)\n", lpUnk, reserved); 01563 01564 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal); 01565 if (hr == S_OK) 01566 { 01567 hr = IMarshal_DisconnectObject(marshal, reserved); 01568 IMarshal_Release(marshal); 01569 return hr; 01570 } 01571 01572 apt = COM_CurrentApt(); 01573 if (!apt) 01574 return CO_E_NOTINITIALIZED; 01575 01576 apartment_disconnectobject(apt, lpUnk); 01577 01578 /* Note: native is pretty broken here because it just silently 01579 * fails, without returning an appropriate error code if the object was 01580 * not found, making apps think that the object was disconnected, when 01581 * it actually wasn't */ 01582 01583 return S_OK; 01584 } 01585 01586 /****************************************************************************** 01587 * CoCreateGuid [OLE32.@] 01588 * 01589 * Simply forwards to UuidCreate in RPCRT4. 01590 * 01591 * PARAMS 01592 * pguid [O] Points to the GUID to initialize. 01593 * 01594 * RETURNS 01595 * Success: S_OK. 01596 * Failure: HRESULT code. 01597 * 01598 * SEE ALSO 01599 * UuidCreate 01600 */ 01601 HRESULT WINAPI CoCreateGuid(GUID *pguid) 01602 { 01603 DWORD status = UuidCreate(pguid); 01604 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK; 01605 return HRESULT_FROM_WIN32( status ); 01606 } 01607 01608 static inline BOOL is_valid_hex(WCHAR c) 01609 { 01610 if (!(((c >= '0') && (c <= '9')) || 01611 ((c >= 'a') && (c <= 'f')) || 01612 ((c >= 'A') && (c <= 'F')))) 01613 return FALSE; 01614 return TRUE; 01615 } 01616 01617 /****************************************************************************** 01618 * CLSIDFromString [OLE32.@] 01619 * IIDFromString [OLE32.@] 01620 * 01621 * Converts a unique identifier from its string representation into 01622 * the GUID struct. 01623 * 01624 * PARAMS 01625 * idstr [I] The string representation of the GUID. 01626 * id [O] GUID converted from the string. 01627 * 01628 * RETURNS 01629 * S_OK on success 01630 * CO_E_CLASSSTRING if idstr is not a valid CLSID 01631 * 01632 * SEE ALSO 01633 * StringFromCLSID 01634 */ 01635 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id) 01636 { 01637 int i; 01638 BYTE table[256]; 01639 01640 if (!s || s[0]!='{') { 01641 memset( id, 0, sizeof (CLSID) ); 01642 if(!s) return S_OK; 01643 return CO_E_CLASSSTRING; 01644 } 01645 01646 TRACE("%s -> %p\n", debugstr_w(s), id); 01647 01648 /* quick lookup table */ 01649 memset(table, 0, 256); 01650 01651 for (i = 0; i < 10; i++) { 01652 table['0' + i] = i; 01653 } 01654 for (i = 0; i < 6; i++) { 01655 table['A' + i] = i+10; 01656 table['a' + i] = i+10; 01657 } 01658 01659 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ 01660 01661 id->Data1 = 0; 01662 for (i = 1; i < 9; i++) { 01663 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING; 01664 id->Data1 = (id->Data1 << 4) | table[s[i]]; 01665 } 01666 if (s[9]!='-') return CO_E_CLASSSTRING; 01667 01668 id->Data2 = 0; 01669 for (i = 10; i < 14; i++) { 01670 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING; 01671 id->Data2 = (id->Data2 << 4) | table[s[i]]; 01672 } 01673 if (s[14]!='-') return CO_E_CLASSSTRING; 01674 01675 id->Data3 = 0; 01676 for (i = 15; i < 19; i++) { 01677 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING; 01678 id->Data3 = (id->Data3 << 4) | table[s[i]]; 01679 } 01680 if (s[19]!='-') return CO_E_CLASSSTRING; 01681 01682 for (i = 20; i < 37; i+=2) { 01683 if (i == 24) { 01684 if (s[i]!='-') return CO_E_CLASSSTRING; 01685 i++; 01686 } 01687 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING; 01688 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]]; 01689 } 01690 01691 if (s[37] == '}' && s[38] == '\0') 01692 return S_OK; 01693 01694 return CO_E_CLASSSTRING; 01695 } 01696 01697 /*****************************************************************************/ 01698 01699 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id ) 01700 { 01701 HRESULT ret; 01702 01703 if (!id) 01704 return E_INVALIDARG; 01705 01706 ret = __CLSIDFromString(idstr, id); 01707 if(ret != S_OK) { /* It appears a ProgID is also valid */ 01708 CLSID tmp_id; 01709 ret = CLSIDFromProgID(idstr, &tmp_id); 01710 if(SUCCEEDED(ret)) 01711 *id = tmp_id; 01712 } 01713 return ret; 01714 } 01715 01716 01717 /****************************************************************************** 01718 * StringFromCLSID [OLE32.@] 01719 * StringFromIID [OLE32.@] 01720 * 01721 * Converts a GUID into the respective string representation. 01722 * The target string is allocated using the OLE IMalloc. 01723 * 01724 * PARAMS 01725 * id [I] the GUID to be converted. 01726 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string. 01727 * 01728 * RETURNS 01729 * S_OK 01730 * E_FAIL 01731 * 01732 * SEE ALSO 01733 * StringFromGUID2, CLSIDFromString 01734 */ 01735 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr) 01736 { 01737 HRESULT ret; 01738 LPMALLOC mllc; 01739 01740 if ((ret = CoGetMalloc(0,&mllc))) return ret; 01741 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY; 01742 StringFromGUID2( id, *idstr, CHARS_IN_GUID ); 01743 return S_OK; 01744 } 01745 01746 /****************************************************************************** 01747 * StringFromGUID2 [OLE32.@] 01748 * 01749 * Modified version of StringFromCLSID that allows you to specify max 01750 * buffer size. 01751 * 01752 * PARAMS 01753 * id [I] GUID to convert to string. 01754 * str [O] Buffer where the result will be stored. 01755 * cmax [I] Size of the buffer in characters. 01756 * 01757 * RETURNS 01758 * Success: The length of the resulting string in characters. 01759 * Failure: 0. 01760 */ 01761 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax) 01762 { 01763 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-', 01764 '%','0','4','X','-','%','0','2','X','%','0','2','X','-', 01765 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X', 01766 '%','0','2','X','%','0','2','X','}',0 }; 01767 if (!id || cmax < CHARS_IN_GUID) return 0; 01768 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3, 01769 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], 01770 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); 01771 return CHARS_IN_GUID; 01772 } 01773 01774 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */ 01775 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey) 01776 { 01777 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0}; 01778 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1]; 01779 LONG res; 01780 HKEY key; 01781 01782 strcpyW(path, wszCLSIDSlash); 01783 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID); 01784 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key); 01785 if (res == ERROR_FILE_NOT_FOUND) 01786 return REGDB_E_CLASSNOTREG; 01787 else if (res != ERROR_SUCCESS) 01788 return REGDB_E_READREGDB; 01789 01790 if (!keyname) 01791 { 01792 *subkey = key; 01793 return S_OK; 01794 } 01795 01796 res = RegOpenKeyExW(key, keyname, 0, access, subkey); 01797 RegCloseKey(key); 01798 if (res == ERROR_FILE_NOT_FOUND) 01799 return REGDB_E_KEYMISSING; 01800 else if (res != ERROR_SUCCESS) 01801 return REGDB_E_READREGDB; 01802 01803 return S_OK; 01804 } 01805 01806 /* open HKCR\\AppId\\{string form of appid clsid} key */ 01807 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey) 01808 { 01809 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; 01810 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; 01811 DWORD res; 01812 WCHAR buf[CHARS_IN_GUID]; 01813 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID]; 01814 DWORD size; 01815 HKEY hkey; 01816 DWORD type; 01817 HRESULT hr; 01818 01819 /* read the AppID value under the class's key */ 01820 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey); 01821 if (FAILED(hr)) 01822 return hr; 01823 01824 size = sizeof(buf); 01825 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size); 01826 RegCloseKey(hkey); 01827 if (res == ERROR_FILE_NOT_FOUND) 01828 return REGDB_E_KEYMISSING; 01829 else if (res != ERROR_SUCCESS || type!=REG_SZ) 01830 return REGDB_E_READREGDB; 01831 01832 strcpyW(keyname, szAppIdKey); 01833 strcatW(keyname, buf); 01834 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey); 01835 if (res == ERROR_FILE_NOT_FOUND) 01836 return REGDB_E_KEYMISSING; 01837 else if (res != ERROR_SUCCESS) 01838 return REGDB_E_READREGDB; 01839 01840 return S_OK; 01841 } 01842 01843 /****************************************************************************** 01844 * ProgIDFromCLSID [OLE32.@] 01845 * 01846 * Converts a class id into the respective program ID. 01847 * 01848 * PARAMS 01849 * clsid [I] Class ID, as found in registry. 01850 * ppszProgID [O] Associated ProgID. 01851 * 01852 * RETURNS 01853 * S_OK 01854 * E_OUTOFMEMORY 01855 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID 01856 */ 01857 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID) 01858 { 01859 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0}; 01860 HKEY hkey; 01861 HRESULT ret; 01862 LONG progidlen = 0; 01863 01864 if (!ppszProgID) 01865 { 01866 ERR("ppszProgId isn't optional\n"); 01867 return E_INVALIDARG; 01868 } 01869 01870 *ppszProgID = NULL; 01871 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey); 01872 if (FAILED(ret)) 01873 return ret; 01874 01875 if (RegQueryValueW(hkey, NULL, NULL, &progidlen)) 01876 ret = REGDB_E_CLASSNOTREG; 01877 01878 if (ret == S_OK) 01879 { 01880 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR)); 01881 if (*ppszProgID) 01882 { 01883 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) 01884 ret = REGDB_E_CLASSNOTREG; 01885 } 01886 else 01887 ret = E_OUTOFMEMORY; 01888 } 01889 01890 RegCloseKey(hkey); 01891 return ret; 01892 } 01893 01894 /****************************************************************************** 01895 * CLSIDFromProgID [OLE32.@] 01896 * 01897 * Converts a program id into the respective GUID. 01898 * 01899 * PARAMS 01900 * progid [I] Unicode program ID, as found in registry. 01901 * clsid [O] Associated CLSID. 01902 * 01903 * RETURNS 01904 * Success: S_OK 01905 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found. 01906 */ 01907 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid) 01908 { 01909 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 }; 01910 WCHAR buf2[CHARS_IN_GUID]; 01911 LONG buf2len = sizeof(buf2); 01912 HKEY xhkey; 01913 WCHAR *buf; 01914 01915 if (!progid || !clsid) 01916 { 01917 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid); 01918 return E_INVALIDARG; 01919 } 01920 01921 /* initialise clsid in case of failure */ 01922 memset(clsid, 0, sizeof(*clsid)); 01923 01924 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) ); 01925 strcpyW( buf, progid ); 01926 strcatW( buf, clsidW ); 01927 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey)) 01928 { 01929 HeapFree(GetProcessHeap(),0,buf); 01930 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); 01931 return CO_E_CLASSSTRING; 01932 } 01933 HeapFree(GetProcessHeap(),0,buf); 01934 01935 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len)) 01936 { 01937 RegCloseKey(xhkey); 01938 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); 01939 return CO_E_CLASSSTRING; 01940 } 01941 RegCloseKey(xhkey); 01942 return __CLSIDFromString(buf2,clsid); 01943 } 01944 01945 01946 /***************************************************************************** 01947 * CoGetPSClsid [OLE32.@] 01948 * 01949 * Retrieves the CLSID of the proxy/stub factory that implements 01950 * IPSFactoryBuffer for the specified interface. 01951 * 01952 * PARAMS 01953 * riid [I] Interface whose proxy/stub CLSID is to be returned. 01954 * pclsid [O] Where to store returned proxy/stub CLSID. 01955 * 01956 * RETURNS 01957 * S_OK 01958 * E_OUTOFMEMORY 01959 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed 01960 * 01961 * NOTES 01962 * 01963 * The standard marshaller activates the object with the CLSID 01964 * returned and uses the CreateProxy and CreateStub methods on its 01965 * IPSFactoryBuffer interface to construct the proxies and stubs for a 01966 * given object. 01967 * 01968 * CoGetPSClsid determines this CLSID by searching the 01969 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 01970 * in the registry and any interface id registered by 01971 * CoRegisterPSClsid within the current process. 01972 * 01973 * BUGS 01974 * 01975 * Native returns S_OK for interfaces with a key in HKCR\Interface, but 01976 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be 01977 * considered a bug in native unless an application depends on this (unlikely). 01978 * 01979 * SEE ALSO 01980 * CoRegisterPSClsid. 01981 */ 01982 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) 01983 { 01984 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0}; 01985 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0}; 01986 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)]; 01987 WCHAR value[CHARS_IN_GUID]; 01988 LONG len; 01989 HKEY hkey; 01990 APARTMENT *apt = COM_CurrentApt(); 01991 struct registered_psclsid *registered_psclsid; 01992 01993 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid); 01994 01995 if (!apt) 01996 { 01997 ERR("apartment not initialised\n"); 01998 return CO_E_NOTINITIALIZED; 01999 } 02000 02001 if (!pclsid) 02002 { 02003 ERR("pclsid isn't optional\n"); 02004 return E_INVALIDARG; 02005 } 02006 02007 EnterCriticalSection(&apt->cs); 02008 02009 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry) 02010 if (IsEqualIID(®istered_psclsid->iid, riid)) 02011 { 02012 *pclsid = registered_psclsid->clsid; 02013 LeaveCriticalSection(&apt->cs); 02014 return S_OK; 02015 } 02016 02017 LeaveCriticalSection(&apt->cs); 02018 02019 /* Interface\\{string form of riid}\\ProxyStubClsid32 */ 02020 strcpyW(path, wszInterface); 02021 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID); 02022 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC); 02023 02024 /* Open the key.. */ 02025 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey)) 02026 { 02027 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid)); 02028 return REGDB_E_IIDNOTREG; 02029 } 02030 02031 /* ... Once we have the key, query the registry to get the 02032 value of CLSID as a string, and convert it into a 02033 proper CLSID structure to be passed back to the app */ 02034 len = sizeof(value); 02035 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len)) 02036 { 02037 RegCloseKey(hkey); 02038 return REGDB_E_IIDNOTREG; 02039 } 02040 RegCloseKey(hkey); 02041 02042 /* We have the CLSID we want back from the registry as a string, so 02043 let's convert it into a CLSID structure */ 02044 if (CLSIDFromString(value, pclsid) != NOERROR) 02045 return REGDB_E_IIDNOTREG; 02046 02047 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid)); 02048 return S_OK; 02049 } 02050 02051 /***************************************************************************** 02052 * CoRegisterPSClsid [OLE32.@] 02053 * 02054 * Register a proxy/stub CLSID for the given interface in the current process 02055 * only. 02056 * 02057 * PARAMS 02058 * riid [I] Interface whose proxy/stub CLSID is to be registered. 02059 * rclsid [I] CLSID of the proxy/stub. 02060 * 02061 * RETURNS 02062 * Success: S_OK 02063 * Failure: E_OUTOFMEMORY 02064 * 02065 * NOTES 02066 * 02067 * This function does not add anything to the registry and the effects are 02068 * limited to the lifetime of the current process. 02069 * 02070 * SEE ALSO 02071 * CoGetPSClsid. 02072 */ 02073 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) 02074 { 02075 APARTMENT *apt = COM_CurrentApt(); 02076 struct registered_psclsid *registered_psclsid; 02077 02078 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid)); 02079 02080 if (!apt) 02081 { 02082 ERR("apartment not initialised\n"); 02083 return CO_E_NOTINITIALIZED; 02084 } 02085 02086 EnterCriticalSection(&apt->cs); 02087 02088 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry) 02089 if (IsEqualIID(®istered_psclsid->iid, riid)) 02090 { 02091 registered_psclsid->clsid = *rclsid; 02092 LeaveCriticalSection(&apt->cs); 02093 return S_OK; 02094 } 02095 02096 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid)); 02097 if (!registered_psclsid) 02098 { 02099 LeaveCriticalSection(&apt->cs); 02100 return E_OUTOFMEMORY; 02101 } 02102 02103 registered_psclsid->iid = *riid; 02104 registered_psclsid->clsid = *rclsid; 02105 list_add_head(&apt->psclsids, ®istered_psclsid->entry); 02106 02107 LeaveCriticalSection(&apt->cs); 02108 02109 return S_OK; 02110 } 02111 02112 02113 /*** 02114 * COM_GetRegisteredClassObject 02115 * 02116 * This internal method is used to scan the registered class list to 02117 * find a class object. 02118 * 02119 * Params: 02120 * rclsid Class ID of the class to find. 02121 * dwClsContext Class context to match. 02122 * ppv [out] returns a pointer to the class object. Complying 02123 * to normal COM usage, this method will increase the 02124 * reference count on this object. 02125 */ 02126 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, 02127 DWORD dwClsContext, LPUNKNOWN* ppUnk) 02128 { 02129 HRESULT hr = S_FALSE; 02130 RegisteredClass *curClass; 02131 02132 EnterCriticalSection( &csRegisteredClassList ); 02133 02134 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) 02135 { 02136 /* 02137 * Check if we have a match on the class ID and context. 02138 */ 02139 if ((apt->oxid == curClass->apartment_id) && 02140 (dwClsContext & curClass->runContext) && 02141 IsEqualGUID(&(curClass->classIdentifier), rclsid)) 02142 { 02143 /* 02144 * We have a match, return the pointer to the class object. 02145 */ 02146 *ppUnk = curClass->classObject; 02147 02148 IUnknown_AddRef(curClass->classObject); 02149 02150 hr = S_OK; 02151 break; 02152 } 02153 } 02154 02155 LeaveCriticalSection( &csRegisteredClassList ); 02156 02157 return hr; 02158 } 02159 02160 /****************************************************************************** 02161 * CoRegisterClassObject [OLE32.@] 02162 * 02163 * Registers the class object for a given class ID. Servers housed in EXE 02164 * files use this method instead of exporting DllGetClassObject to allow 02165 * other code to connect to their objects. 02166 * 02167 * PARAMS 02168 * rclsid [I] CLSID of the object to register. 02169 * pUnk [I] IUnknown of the object. 02170 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable. 02171 * flags [I] REGCLS flags indicating how connections are made. 02172 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject. 02173 * 02174 * RETURNS 02175 * S_OK on success, 02176 * E_INVALIDARG if lpdwRegister or pUnk are NULL, 02177 * CO_E_OBJISREG if the object is already registered. We should not return this. 02178 * 02179 * SEE ALSO 02180 * CoRevokeClassObject, CoGetClassObject 02181 * 02182 * NOTES 02183 * In-process objects are only registered for the current apartment. 02184 * CoGetClassObject() and CoCreateInstance() will not return objects registered 02185 * in other apartments. 02186 * 02187 * BUGS 02188 * MSDN claims that multiple interface registrations are legal, but we 02189 * can't do that with our current implementation. 02190 */ 02191 HRESULT WINAPI CoRegisterClassObject( 02192 REFCLSID rclsid, 02193 LPUNKNOWN pUnk, 02194 DWORD dwClsContext, 02195 DWORD flags, 02196 LPDWORD lpdwRegister) 02197 { 02198 static LONG next_cookie; 02199 RegisteredClass* newClass; 02200 LPUNKNOWN foundObject; 02201 HRESULT hr; 02202 APARTMENT *apt; 02203 02204 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n", 02205 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); 02206 02207 if ( (lpdwRegister==0) || (pUnk==0) ) 02208 return E_INVALIDARG; 02209 02210 apt = COM_CurrentApt(); 02211 if (!apt) 02212 { 02213 ERR("COM was not initialized\n"); 02214 return CO_E_NOTINITIALIZED; 02215 } 02216 02217 *lpdwRegister = 0; 02218 02219 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what 02220 * differentiates the flag from REGCLS_MULTI_SEPARATE. */ 02221 if (flags & REGCLS_MULTIPLEUSE) 02222 dwClsContext |= CLSCTX_INPROC_SERVER; 02223 02224 /* 02225 * First, check if the class is already registered. 02226 * If it is, this should cause an error. 02227 */ 02228 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject); 02229 if (hr == S_OK) { 02230 if (flags & REGCLS_MULTIPLEUSE) { 02231 if (dwClsContext & CLSCTX_LOCAL_SERVER) 02232 hr = CoLockObjectExternal(foundObject, TRUE, FALSE); 02233 IUnknown_Release(foundObject); 02234 return hr; 02235 } 02236 IUnknown_Release(foundObject); 02237 ERR("object already registered for class %s\n", debugstr_guid(rclsid)); 02238 return CO_E_OBJISREG; 02239 } 02240 02241 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); 02242 if ( newClass == NULL ) 02243 return E_OUTOFMEMORY; 02244 02245 newClass->classIdentifier = *rclsid; 02246 newClass->apartment_id = apt->oxid; 02247 newClass->runContext = dwClsContext; 02248 newClass->connectFlags = flags; 02249 newClass->pMarshaledData = NULL; 02250 newClass->RpcRegistration = NULL; 02251 02252 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie ))) 02253 newClass->dwCookie = InterlockedIncrement( &next_cookie ); 02254 02255 /* 02256 * Since we're making a copy of the object pointer, we have to increase its 02257 * reference count. 02258 */ 02259 newClass->classObject = pUnk; 02260 IUnknown_AddRef(newClass->classObject); 02261 02262 EnterCriticalSection( &csRegisteredClassList ); 02263 list_add_tail(&RegisteredClassList, &newClass->entry); 02264 LeaveCriticalSection( &csRegisteredClassList ); 02265 02266 *lpdwRegister = newClass->dwCookie; 02267 02268 if (dwClsContext & CLSCTX_LOCAL_SERVER) { 02269 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData); 02270 if (hr) { 02271 FIXME("Failed to create stream on hglobal, %x\n", hr); 02272 return hr; 02273 } 02274 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown, 02275 newClass->classObject, MSHCTX_LOCAL, NULL, 02276 MSHLFLAGS_TABLESTRONG); 02277 if (hr) { 02278 FIXME("CoMarshalInterface failed, %x!\n",hr); 02279 return hr; 02280 } 02281 02282 hr = RPC_StartLocalServer(&newClass->classIdentifier, 02283 newClass->pMarshaledData, 02284 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE), 02285 &newClass->RpcRegistration); 02286 } 02287 return S_OK; 02288 } 02289 02290 static void get_threading_model(HKEY key, LPWSTR value, DWORD len) 02291 { 02292 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; 02293 DWORD keytype; 02294 DWORD ret; 02295 DWORD dwLength = len * sizeof(WCHAR); 02296 02297 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength); 02298 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ)) 02299 value[0] = '\0'; 02300 } 02301 02302 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, 02303 REFCLSID rclsid, REFIID riid, 02304 BOOL hostifnecessary, void **ppv) 02305 { 02306 WCHAR dllpath[MAX_PATH+1]; 02307 BOOL apartment_threaded; 02308 02309 if (hostifnecessary) 02310 { 02311 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0}; 02312 static const WCHAR wszFree[] = {'F','r','e','e',0}; 02313 static const WCHAR wszBoth[] = {'B','o','t','h',0}; 02314 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */]; 02315 02316 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model)); 02317 /* "Apartment" */ 02318 if (!strcmpiW(threading_model, wszApartment)) 02319 { 02320 apartment_threaded = TRUE; 02321 if (apt->multi_threaded) 02322 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv); 02323 } 02324 /* "Free" */ 02325 else if (!strcmpiW(threading_model, wszFree)) 02326 { 02327 apartment_threaded = FALSE; 02328 if (!apt->multi_threaded) 02329 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv); 02330 } 02331 /* everything except "Apartment", "Free" and "Both" */ 02332 else if (strcmpiW(threading_model, wszBoth)) 02333 { 02334 apartment_threaded = TRUE; 02335 /* everything else is main-threaded */ 02336 if (threading_model[0]) 02337 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n", 02338 debugstr_w(threading_model), debugstr_guid(rclsid)); 02339 02340 if (apt->multi_threaded || !apt->main) 02341 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv); 02342 } 02343 else 02344 apartment_threaded = FALSE; 02345 } 02346 else 02347 apartment_threaded = !apt->multi_threaded; 02348 02349 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS) 02350 { 02351 /* failure: CLSID is not found in registry */ 02352 WARN("class %s not registered inproc\n", debugstr_guid(rclsid)); 02353 return REGDB_E_CLASSNOTREG; 02354 } 02355 02356 return apartment_getclassobject(apt, dllpath, apartment_threaded, 02357 rclsid, riid, ppv); 02358 } 02359 02360 /*********************************************************************** 02361 * CoGetClassObject [OLE32.@] 02362 * 02363 * Creates an object of the specified class. 02364 * 02365 * PARAMS 02366 * rclsid [I] Class ID to create an instance of. 02367 * dwClsContext [I] Flags to restrict the location of the created instance. 02368 * pServerInfo [I] Optional. Details for connecting to a remote server. 02369 * iid [I] The ID of the interface of the instance to return. 02370 * ppv [O] On returns, contains a pointer to the specified interface of the object. 02371 * 02372 * RETURNS 02373 * Success: S_OK 02374 * Failure: HRESULT code. 02375 * 02376 * NOTES 02377 * The dwClsContext parameter can be one or more of the following: 02378 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. 02379 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. 02380 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. 02381 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. 02382 * 02383 * SEE ALSO 02384 * CoCreateInstance() 02385 */ 02386 HRESULT WINAPI CoGetClassObject( 02387 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo, 02388 REFIID iid, LPVOID *ppv) 02389 { 02390 LPUNKNOWN regClassObject; 02391 HRESULT hres = E_UNEXPECTED; 02392 APARTMENT *apt; 02393 BOOL release_apt = FALSE; 02394 02395 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid)); 02396 02397 if (!ppv) 02398 return E_INVALIDARG; 02399 02400 *ppv = NULL; 02401 02402 if (!(apt = COM_CurrentApt())) 02403 { 02404 if (!(apt = apartment_find_multi_threaded())) 02405 { 02406 ERR("apartment not initialised\n"); 02407 return CO_E_NOTINITIALIZED; 02408 } 02409 release_apt = TRUE; 02410 } 02411 02412 if (pServerInfo) { 02413 FIXME("pServerInfo->name=%s pAuthInfo=%p\n", 02414 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo); 02415 } 02416 02417 /* 02418 * First, try and see if we can't match the class ID with one of the 02419 * registered classes. 02420 */ 02421 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, 02422 ®ClassObject)) 02423 { 02424 /* Get the required interface from the retrieved pointer. */ 02425 hres = IUnknown_QueryInterface(regClassObject, iid, ppv); 02426 02427 /* 02428 * Since QI got another reference on the pointer, we want to release the 02429 * one we already have. If QI was unsuccessful, this will release the object. This 02430 * is good since we are not returning it in the "out" parameter. 02431 */ 02432 IUnknown_Release(regClassObject); 02433 if (release_apt) apartment_release(apt); 02434 return hres; 02435 } 02436 02437 /* First try in-process server */ 02438 if (CLSCTX_INPROC_SERVER & dwClsContext) 02439 { 02440 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; 02441 HKEY hkey; 02442 02443 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler)) 02444 { 02445 if (release_apt) apartment_release(apt); 02446 return FTMarshalCF_Create(iid, ppv); 02447 } 02448 02449 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey); 02450 if (FAILED(hres)) 02451 { 02452 if (hres == REGDB_E_CLASSNOTREG) 02453 ERR("class %s not registered\n", debugstr_guid(rclsid)); 02454 else if (hres == REGDB_E_KEYMISSING) 02455 { 02456 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid)); 02457 hres = REGDB_E_CLASSNOTREG; 02458 } 02459 } 02460 02461 if (SUCCEEDED(hres)) 02462 { 02463 hres = get_inproc_class_object(apt, hkey, rclsid, iid, 02464 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 02465 RegCloseKey(hkey); 02466 } 02467 02468 /* return if we got a class, otherwise fall through to one of the 02469 * other types */ 02470 if (SUCCEEDED(hres)) 02471 { 02472 if (release_apt) apartment_release(apt); 02473 return hres; 02474 } 02475 } 02476 02477 /* Next try in-process handler */ 02478 if (CLSCTX_INPROC_HANDLER & dwClsContext) 02479 { 02480 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; 02481 HKEY hkey; 02482 02483 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); 02484 if (FAILED(hres)) 02485 { 02486 if (hres == REGDB_E_CLASSNOTREG) 02487 ERR("class %s not registered\n", debugstr_guid(rclsid)); 02488 else if (hres == REGDB_E_KEYMISSING) 02489 { 02490 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid)); 02491 hres = REGDB_E_CLASSNOTREG; 02492 } 02493 } 02494 02495 if (SUCCEEDED(hres)) 02496 { 02497 hres = get_inproc_class_object(apt, hkey, rclsid, iid, 02498 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); 02499 RegCloseKey(hkey); 02500 } 02501 02502 /* return if we got a class, otherwise fall through to one of the 02503 * other types */ 02504 if (SUCCEEDED(hres)) 02505 { 02506 if (release_apt) apartment_release(apt); 02507 return hres; 02508 } 02509 } 02510 if (release_apt) apartment_release(apt); 02511 02512 /* Next try out of process */ 02513 if (CLSCTX_LOCAL_SERVER & dwClsContext) 02514 { 02515 hres = RPC_GetLocalClassObject(rclsid,iid,ppv); 02516 if (SUCCEEDED(hres)) 02517 return hres; 02518 } 02519 02520 /* Finally try remote: this requires networked DCOM (a lot of work) */ 02521 if (CLSCTX_REMOTE_SERVER & dwClsContext) 02522 { 02523 FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); 02524 hres = REGDB_E_CLASSNOTREG; 02525 } 02526 02527 if (FAILED(hres)) 02528 ERR("no class object %s could be created for context 0x%x\n", 02529 debugstr_guid(rclsid), dwClsContext); 02530 return hres; 02531 } 02532 02533 /*********************************************************************** 02534 * CoResumeClassObjects (OLE32.@) 02535 * 02536 * Resumes all class objects registered with REGCLS_SUSPENDED. 02537 * 02538 * RETURNS 02539 * Success: S_OK. 02540 * Failure: HRESULT code. 02541 */ 02542 HRESULT WINAPI CoResumeClassObjects(void) 02543 { 02544 FIXME("stub\n"); 02545 return S_OK; 02546 } 02547 02548 /*********************************************************************** 02549 * CoCreateInstance [OLE32.@] 02550 * 02551 * Creates an instance of the specified class. 02552 * 02553 * PARAMS 02554 * rclsid [I] Class ID to create an instance of. 02555 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object. 02556 * dwClsContext [I] Flags to restrict the location of the created instance. 02557 * iid [I] The ID of the interface of the instance to return. 02558 * ppv [O] On returns, contains a pointer to the specified interface of the instance. 02559 * 02560 * RETURNS 02561 * Success: S_OK 02562 * Failure: HRESULT code. 02563 * 02564 * NOTES 02565 * The dwClsContext parameter can be one or more of the following: 02566 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL. 02567 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process. 02568 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process. 02569 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine. 02570 * 02571 * Aggregation is the concept of deferring the IUnknown of an object to another 02572 * object. This allows a separate object to behave as though it was part of 02573 * the object and to allow this the pUnkOuter parameter can be set. Note that 02574 * not all objects support having an outer of unknown. 02575 * 02576 * SEE ALSO 02577 * CoGetClassObject() 02578 */ 02579 HRESULT WINAPI CoCreateInstance( 02580 REFCLSID rclsid, 02581 LPUNKNOWN pUnkOuter, 02582 DWORD dwClsContext, 02583 REFIID iid, 02584 LPVOID *ppv) 02585 { 02586 HRESULT hres; 02587 LPCLASSFACTORY lpclf = 0; 02588 APARTMENT *apt; 02589 02590 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid), 02591 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv); 02592 02593 /* 02594 * Sanity check 02595 */ 02596 if (ppv==0) 02597 return E_POINTER; 02598 02599 /* 02600 * Initialize the "out" parameter 02601 */ 02602 *ppv = 0; 02603 02604 if (!(apt = COM_CurrentApt())) 02605 { 02606 if (!(apt = apartment_find_multi_threaded())) 02607 { 02608 ERR("apartment not initialised\n"); 02609 return CO_E_NOTINITIALIZED; 02610 } 02611 apartment_release(apt); 02612 } 02613 02614 /* 02615 * The Standard Global Interface Table (GIT) object is a process-wide singleton. 02616 * Rather than create a class factory, we can just check for it here 02617 */ 02618 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) { 02619 if (StdGlobalInterfaceTableInstance == NULL) 02620 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct(); 02621 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv); 02622 if (hres) return hres; 02623 02624 TRACE("Retrieved GIT (%p)\n", *ppv); 02625 return S_OK; 02626 } 02627 02628 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent)) 02629 return ManualResetEvent_Construct(pUnkOuter, iid, ppv); 02630 02631 /* 02632 * Get a class factory to construct the object we want. 02633 */ 02634 hres = CoGetClassObject(rclsid, 02635 dwClsContext, 02636 NULL, 02637 &IID_IClassFactory, 02638 (LPVOID)&lpclf); 02639 02640 if (FAILED(hres)) 02641 return hres; 02642 02643 /* 02644 * Create the object and don't forget to release the factory 02645 */ 02646 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv); 02647 IClassFactory_Release(lpclf); 02648 if(FAILED(hres)) 02649 { 02650 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter) 02651 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid)); 02652 else 02653 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres); 02654 } 02655 02656 return hres; 02657 } 02658 02659 /*********************************************************************** 02660 * CoCreateInstanceEx [OLE32.@] 02661 */ 02662 HRESULT WINAPI CoCreateInstanceEx( 02663 REFCLSID rclsid, 02664 LPUNKNOWN pUnkOuter, 02665 DWORD dwClsContext, 02666 COSERVERINFO* pServerInfo, 02667 ULONG cmq, 02668 MULTI_QI* pResults) 02669 { 02670 IUnknown* pUnk = NULL; 02671 HRESULT hr; 02672 ULONG index; 02673 ULONG successCount = 0; 02674 02675 /* 02676 * Sanity check 02677 */ 02678 if ( (cmq==0) || (pResults==NULL)) 02679 return E_INVALIDARG; 02680 02681 if (pServerInfo!=NULL) 02682 FIXME("() non-NULL pServerInfo not supported!\n"); 02683 02684 /* 02685 * Initialize all the "out" parameters. 02686 */ 02687 for (index = 0; index < cmq; index++) 02688 { 02689 pResults[index].pItf = NULL; 02690 pResults[index].hr = E_NOINTERFACE; 02691 } 02692 02693 /* 02694 * Get the object and get its IUnknown pointer. 02695 */ 02696 hr = CoCreateInstance(rclsid, 02697 pUnkOuter, 02698 dwClsContext, 02699 &IID_IUnknown, 02700 (VOID**)&pUnk); 02701 02702 if (hr) 02703 return hr; 02704 02705 /* 02706 * Then, query for all the interfaces requested. 02707 */ 02708 for (index = 0; index < cmq; index++) 02709 { 02710 pResults[index].hr = IUnknown_QueryInterface(pUnk, 02711 pResults[index].pIID, 02712 (VOID**)&(pResults[index].pItf)); 02713 02714 if (pResults[index].hr == S_OK) 02715 successCount++; 02716 } 02717 02718 /* 02719 * Release our temporary unknown pointer. 02720 */ 02721 IUnknown_Release(pUnk); 02722 02723 if (successCount == 0) 02724 return E_NOINTERFACE; 02725 02726 if (successCount!=cmq) 02727 return CO_S_NOTALLINTERFACES; 02728 02729 return S_OK; 02730 } 02731 02732 /*********************************************************************** 02733 * CoLoadLibrary (OLE32.@) 02734 * 02735 * Loads a library. 02736 * 02737 * PARAMS 02738 * lpszLibName [I] Path to library. 02739 * bAutoFree [I] Whether the library should automatically be freed. 02740 * 02741 * RETURNS 02742 * Success: Handle to loaded library. 02743 * Failure: NULL. 02744 * 02745 * SEE ALSO 02746 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries 02747 */ 02748 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree) 02749 { 02750 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree); 02751 02752 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH); 02753 } 02754 02755 /*********************************************************************** 02756 * CoFreeLibrary [OLE32.@] 02757 * 02758 * Unloads a library from memory. 02759 * 02760 * PARAMS 02761 * hLibrary [I] Handle to library to unload. 02762 * 02763 * RETURNS 02764 * Nothing 02765 * 02766 * SEE ALSO 02767 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries 02768 */ 02769 void WINAPI CoFreeLibrary(HINSTANCE hLibrary) 02770 { 02771 FreeLibrary(hLibrary); 02772 } 02773 02774 02775 /*********************************************************************** 02776 * CoFreeAllLibraries [OLE32.@] 02777 * 02778 * Function for backwards compatibility only. Does nothing. 02779 * 02780 * RETURNS 02781 * Nothing. 02782 * 02783 * SEE ALSO 02784 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries 02785 */ 02786 void WINAPI CoFreeAllLibraries(void) 02787 { 02788 /* NOP */ 02789 } 02790 02791 /*********************************************************************** 02792 * CoFreeUnusedLibrariesEx [OLE32.@] 02793 * 02794 * Frees any previously unused libraries whose delay has expired and marks 02795 * currently unused libraries for unloading. Unused are identified as those that 02796 * return S_OK from their DllCanUnloadNow function. 02797 * 02798 * PARAMS 02799 * dwUnloadDelay [I] Unload delay in milliseconds. 02800 * dwReserved [I] Reserved. Set to 0. 02801 * 02802 * RETURNS 02803 * Nothing. 02804 * 02805 * SEE ALSO 02806 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary 02807 */ 02808 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved) 02809 { 02810 struct apartment *apt = COM_CurrentApt(); 02811 if (!apt) 02812 { 02813 ERR("apartment not initialised\n"); 02814 return; 02815 } 02816 02817 apartment_freeunusedlibraries(apt, dwUnloadDelay); 02818 } 02819 02820 /*********************************************************************** 02821 * CoFreeUnusedLibraries [OLE32.@] 02822 * 02823 * Frees any unused libraries. Unused are identified as those that return 02824 * S_OK from their DllCanUnloadNow function. 02825 * 02826 * RETURNS 02827 * Nothing. 02828 * 02829 * SEE ALSO 02830 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary 02831 */ 02832 void WINAPI CoFreeUnusedLibraries(void) 02833 { 02834 CoFreeUnusedLibrariesEx(INFINITE, 0); 02835 } 02836 02837 /*********************************************************************** 02838 * CoFileTimeNow [OLE32.@] 02839 * 02840 * Retrieves the current time in FILETIME format. 02841 * 02842 * PARAMS 02843 * lpFileTime [O] The current time. 02844 * 02845 * RETURNS 02846 * S_OK. 02847 */ 02848 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) 02849 { 02850 GetSystemTimeAsFileTime( lpFileTime ); 02851 return S_OK; 02852 } 02853 02854 /****************************************************************************** 02855 * CoLockObjectExternal [OLE32.@] 02856 * 02857 * Increments or decrements the external reference count of a stub object. 02858 * 02859 * PARAMS 02860 * pUnk [I] Stub object. 02861 * fLock [I] If TRUE then increments the external ref-count, 02862 * otherwise decrements. 02863 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of 02864 * calling CoDisconnectObject. 02865 * 02866 * RETURNS 02867 * Success: S_OK. 02868 * Failure: HRESULT code. 02869 * 02870 * NOTES 02871 * If fLock is TRUE and an object is passed in that doesn't have a stub 02872 * manager then a new stub manager is created for the object. 02873 */ 02874 HRESULT WINAPI CoLockObjectExternal( 02875 LPUNKNOWN pUnk, 02876 BOOL fLock, 02877 BOOL fLastUnlockReleases) 02878 { 02879 struct stub_manager *stubmgr; 02880 struct apartment *apt; 02881 02882 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", 02883 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); 02884 02885 apt = COM_CurrentApt(); 02886 if (!apt) return CO_E_NOTINITIALIZED; 02887 02888 stubmgr = get_stub_manager_from_object(apt, pUnk); 02889 02890 if (stubmgr) 02891 { 02892 if (fLock) 02893 stub_manager_ext_addref(stubmgr, 1, FALSE); 02894 else 02895 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases); 02896 02897 stub_manager_int_release(stubmgr); 02898 02899 return S_OK; 02900 } 02901 else if (fLock) 02902 { 02903 stubmgr = new_stub_manager(apt, pUnk); 02904 02905 if (stubmgr) 02906 { 02907 stub_manager_ext_addref(stubmgr, 1, FALSE); 02908 stub_manager_int_release(stubmgr); 02909 } 02910 02911 return S_OK; 02912 } 02913 else 02914 { 02915 WARN("stub object not found %p\n", pUnk); 02916 /* Note: native is pretty broken here because it just silently 02917 * fails, without returning an appropriate error code, making apps 02918 * think that the object was disconnected, when it actually wasn't */ 02919 return S_OK; 02920 } 02921 } 02922 02923 /*********************************************************************** 02924 * CoInitializeWOW (OLE32.@) 02925 * 02926 * WOW equivalent of CoInitialize? 02927 * 02928 * PARAMS 02929 * x [I] Unknown. 02930 * y [I] Unknown. 02931 * 02932 * RETURNS 02933 * Unknown. 02934 */ 02935 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) 02936 { 02937 FIXME("(0x%08x,0x%08x),stub!\n",x,y); 02938 return 0; 02939 } 02940 02941 /*********************************************************************** 02942 * CoGetState [OLE32.@] 02943 * 02944 * Retrieves the thread state object previously stored by CoSetState(). 02945 * 02946 * PARAMS 02947 * ppv [I] Address where pointer to object will be stored. 02948 * 02949 * RETURNS 02950 * Success: S_OK. 02951 * Failure: E_OUTOFMEMORY. 02952 * 02953 * NOTES 02954 * Crashes on all invalid ppv addresses, including NULL. 02955 * If the function returns a non-NULL object then the caller must release its 02956 * reference on the object when the object is no longer required. 02957 * 02958 * SEE ALSO 02959 * CoSetState(). 02960 */ 02961 HRESULT WINAPI CoGetState(IUnknown ** ppv) 02962 { 02963 struct oletls *info = COM_CurrentInfo(); 02964 if (!info) return E_OUTOFMEMORY; 02965 02966 *ppv = NULL; 02967 02968 if (info->state) 02969 { 02970 IUnknown_AddRef(info->state); 02971 *ppv = info->state; 02972 TRACE("apt->state=%p\n", info->state); 02973 } 02974 02975 return S_OK; 02976 } 02977 02978 /*********************************************************************** 02979 * CoSetState [OLE32.@] 02980 * 02981 * Sets the thread state object. 02982 * 02983 * PARAMS 02984 * pv [I] Pointer to state object to be stored. 02985 * 02986 * NOTES 02987 * The system keeps a reference on the object while the object stored. 02988 * 02989 * RETURNS 02990 * Success: S_OK. 02991 * Failure: E_OUTOFMEMORY. 02992 */ 02993 HRESULT WINAPI CoSetState(IUnknown * pv) 02994 { 02995 struct oletls *info = COM_CurrentInfo(); 02996 if (!info) return E_OUTOFMEMORY; 02997 02998 if (pv) IUnknown_AddRef(pv); 02999 03000 if (info->state) 03001 { 03002 TRACE("-- release %p now\n", info->state); 03003 IUnknown_Release(info->state); 03004 } 03005 03006 info->state = pv; 03007 03008 return S_OK; 03009 } 03010 03011 03012 /****************************************************************************** 03013 * CoTreatAsClass [OLE32.@] 03014 * 03015 * Sets the TreatAs value of a class. 03016 * 03017 * PARAMS 03018 * clsidOld [I] Class to set TreatAs value on. 03019 * clsidNew [I] The class the clsidOld should be treated as. 03020 * 03021 * RETURNS 03022 * Success: S_OK. 03023 * Failure: HRESULT code. 03024 * 03025 * SEE ALSO 03026 * CoGetTreatAsClass 03027 */ 03028 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew) 03029 { 03030 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0}; 03031 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0}; 03032 HKEY hkey = NULL; 03033 WCHAR szClsidNew[CHARS_IN_GUID]; 03034 HRESULT res = S_OK; 03035 WCHAR auto_treat_as[CHARS_IN_GUID]; 03036 LONG auto_treat_as_size = sizeof(auto_treat_as); 03037 CLSID id; 03038 03039 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey); 03040 if (FAILED(res)) 03041 goto done; 03042 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) )) 03043 { 03044 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) && 03045 CLSIDFromString(auto_treat_as, &id) == S_OK) 03046 { 03047 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as))) 03048 { 03049 res = REGDB_E_WRITEREGDB; 03050 goto done; 03051 } 03052 } 03053 else 03054 { 03055 RegDeleteKeyW(hkey, wszTreatAs); 03056 goto done; 03057 } 03058 } 03059 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) && 03060 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew))) 03061 { 03062 res = REGDB_E_WRITEREGDB; 03063 goto done; 03064 } 03065 03066 done: 03067 if (hkey) RegCloseKey(hkey); 03068 return res; 03069 } 03070 03071 /****************************************************************************** 03072 * CoGetTreatAsClass [OLE32.@] 03073 * 03074 * Gets the TreatAs value of a class. 03075 * 03076 * PARAMS 03077 * clsidOld [I] Class to get the TreatAs value of. 03078 * clsidNew [I] The class the clsidOld should be treated as. 03079 * 03080 * RETURNS 03081 * Success: S_OK. 03082 * Failure: HRESULT code. 03083 * 03084 * SEE ALSO 03085 * CoSetTreatAsClass 03086 */ 03087 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) 03088 { 03089 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0}; 03090 HKEY hkey = NULL; 03091 WCHAR szClsidNew[CHARS_IN_GUID]; 03092 HRESULT res = S_OK; 03093 LONG len = sizeof(szClsidNew); 03094 03095 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew); 03096 *clsidNew = *clsidOld; /* copy over old value */ 03097 03098 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey); 03099 if (FAILED(res)) 03100 { 03101 res = S_FALSE; 03102 goto done; 03103 } 03104 if (RegQueryValueW(hkey, NULL, szClsidNew, &len)) 03105 { 03106 res = S_FALSE; 03107 goto done; 03108 } 03109 res = CLSIDFromString(szClsidNew,clsidNew); 03110 if (FAILED(res)) 03111 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res); 03112 done: 03113 if (hkey) RegCloseKey(hkey); 03114 return res; 03115 } 03116 03117 /****************************************************************************** 03118 * CoGetCurrentProcess [OLE32.@] 03119 * 03120 * Gets the current process ID. 03121 * 03122 * RETURNS 03123 * The current process ID. 03124 * 03125 * NOTES 03126 * Is DWORD really the correct return type for this function? 03127 */ 03128 DWORD WINAPI CoGetCurrentProcess(void) 03129 { 03130 return GetCurrentProcessId(); 03131 } 03132 03133 /****************************************************************************** 03134 * CoRegisterMessageFilter [OLE32.@] 03135 * 03136 * Registers a message filter. 03137 * 03138 * PARAMS 03139 * lpMessageFilter [I] Pointer to interface. 03140 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL. 03141 * 03142 * RETURNS 03143 * Success: S_OK. 03144 * Failure: HRESULT code. 03145 * 03146 * NOTES 03147 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL 03148 * lpMessageFilter removes the message filter. 03149 * 03150 * If lplpMessageFilter is not NULL the previous message filter will be 03151 * returned in the memory pointer to this parameter and the caller is 03152 * responsible for releasing the object. 03153 * 03154 * The current thread be in an apartment otherwise the function will crash. 03155 */ 03156 HRESULT WINAPI CoRegisterMessageFilter( 03157 LPMESSAGEFILTER lpMessageFilter, 03158 LPMESSAGEFILTER *lplpMessageFilter) 03159 { 03160 struct apartment *apt; 03161 IMessageFilter *lpOldMessageFilter; 03162 03163 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter); 03164 03165 apt = COM_CurrentApt(); 03166 03167 /* can't set a message filter in a multi-threaded apartment */ 03168 if (!apt || apt->multi_threaded) 03169 { 03170 WARN("can't set message filter in MTA or uninitialized apt\n"); 03171 return CO_E_NOT_SUPPORTED; 03172 } 03173 03174 if (lpMessageFilter) 03175 IMessageFilter_AddRef(lpMessageFilter); 03176 03177 EnterCriticalSection(&apt->cs); 03178 03179 lpOldMessageFilter = apt->filter; 03180 apt->filter = lpMessageFilter; 03181 03182 LeaveCriticalSection(&apt->cs); 03183 03184 if (lplpMessageFilter) 03185 *lplpMessageFilter = lpOldMessageFilter; 03186 else if (lpOldMessageFilter) 03187 IMessageFilter_Release(lpOldMessageFilter); 03188 03189 return S_OK; 03190 } 03191 03192 /*********************************************************************** 03193 * CoIsOle1Class [OLE32.@] 03194 * 03195 * Determines whether the specified class an OLE v1 class. 03196 * 03197 * PARAMS 03198 * clsid [I] Class to test. 03199 * 03200 * RETURNS 03201 * TRUE if the class is an OLE v1 class, or FALSE otherwise. 03202 */ 03203 BOOL WINAPI CoIsOle1Class(REFCLSID clsid) 03204 { 03205 FIXME("%s\n", debugstr_guid(clsid)); 03206 return FALSE; 03207 } 03208 03209 /*********************************************************************** 03210 * IsEqualGUID [OLE32.@] 03211 * 03212 * Compares two Unique Identifiers. 03213 * 03214 * PARAMS 03215 * rguid1 [I] The first GUID to compare. 03216 * rguid2 [I] The other GUID to compare. 03217 * 03218 * RETURNS 03219 * TRUE if equal 03220 */ 03221 #undef IsEqualGUID 03222 BOOL WINAPI IsEqualGUID( 03223 REFGUID rguid1, 03224 REFGUID rguid2) 03225 { 03226 return !memcmp(rguid1,rguid2,sizeof(GUID)); 03227 } 03228 03229 /*********************************************************************** 03230 * CoInitializeSecurity [OLE32.@] 03231 */ 03232 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, 03233 SOLE_AUTHENTICATION_SERVICE* asAuthSvc, 03234 void* pReserved1, DWORD dwAuthnLevel, 03235 DWORD dwImpLevel, void* pReserved2, 03236 DWORD dwCapabilities, void* pReserved3) 03237 { 03238 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc, 03239 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2, 03240 dwCapabilities, pReserved3); 03241 return S_OK; 03242 } 03243 03244 /*********************************************************************** 03245 * CoSuspendClassObjects [OLE32.@] 03246 * 03247 * Suspends all registered class objects to prevent further requests coming in 03248 * for those objects. 03249 * 03250 * RETURNS 03251 * Success: S_OK. 03252 * Failure: HRESULT code. 03253 */ 03254 HRESULT WINAPI CoSuspendClassObjects(void) 03255 { 03256 FIXME("\n"); 03257 return S_OK; 03258 } 03259 03260 /*********************************************************************** 03261 * CoAddRefServerProcess [OLE32.@] 03262 * 03263 * Helper function for incrementing the reference count of a local-server 03264 * process. 03265 * 03266 * RETURNS 03267 * New reference count. 03268 * 03269 * SEE ALSO 03270 * CoReleaseServerProcess(). 03271 */ 03272 ULONG WINAPI CoAddRefServerProcess(void) 03273 { 03274 ULONG refs; 03275 03276 TRACE("\n"); 03277 03278 EnterCriticalSection(&csRegisteredClassList); 03279 refs = ++s_COMServerProcessReferences; 03280 LeaveCriticalSection(&csRegisteredClassList); 03281 03282 TRACE("refs before: %d\n", refs - 1); 03283 03284 return refs; 03285 } 03286 03287 /*********************************************************************** 03288 * CoReleaseServerProcess [OLE32.@] 03289 * 03290 * Helper function for decrementing the reference count of a local-server 03291 * process. 03292 * 03293 * RETURNS 03294 * New reference count. 03295 * 03296 * NOTES 03297 * When reference count reaches 0, this function suspends all registered 03298 * classes so no new connections are accepted. 03299 * 03300 * SEE ALSO 03301 * CoAddRefServerProcess(), CoSuspendClassObjects(). 03302 */ 03303 ULONG WINAPI CoReleaseServerProcess(void) 03304 { 03305 ULONG refs; 03306 03307 TRACE("\n"); 03308 03309 EnterCriticalSection(&csRegisteredClassList); 03310 03311 refs = --s_COMServerProcessReferences; 03312 /* FIXME: if (!refs) COM_SuspendClassObjects(); */ 03313 03314 LeaveCriticalSection(&csRegisteredClassList); 03315 03316 TRACE("refs after: %d\n", refs); 03317 03318 return refs; 03319 } 03320 03321 /*********************************************************************** 03322 * CoIsHandlerConnected [OLE32.@] 03323 * 03324 * Determines whether a proxy is connected to a remote stub. 03325 * 03326 * PARAMS 03327 * pUnk [I] Pointer to object that may or may not be connected. 03328 * 03329 * RETURNS 03330 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or 03331 * FALSE otherwise. 03332 */ 03333 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk) 03334 { 03335 FIXME("%p\n", pUnk); 03336 03337 return TRUE; 03338 } 03339 03340 /*********************************************************************** 03341 * CoAllowSetForegroundWindow [OLE32.@] 03342 * 03343 */ 03344 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved) 03345 { 03346 FIXME("(%p, %p): stub\n", pUnk, pvReserved); 03347 return S_OK; 03348 } 03349 03350 /*********************************************************************** 03351 * CoQueryProxyBlanket [OLE32.@] 03352 * 03353 * Retrieves the security settings being used by a proxy. 03354 * 03355 * PARAMS 03356 * pProxy [I] Pointer to the proxy object. 03357 * pAuthnSvc [O] The type of authentication service. 03358 * pAuthzSvc [O] The type of authorization service. 03359 * ppServerPrincName [O] Optional. The server prinicple name. 03360 * pAuthnLevel [O] The authentication level. 03361 * pImpLevel [O] The impersonation level. 03362 * ppAuthInfo [O] Information specific to the authorization/authentication service. 03363 * pCapabilities [O] Flags affecting the security behaviour. 03364 * 03365 * RETURNS 03366 * Success: S_OK. 03367 * Failure: HRESULT code. 03368 * 03369 * SEE ALSO 03370 * CoCopyProxy, CoSetProxyBlanket. 03371 */ 03372 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc, 03373 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel, 03374 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities) 03375 { 03376 IClientSecurity *pCliSec; 03377 HRESULT hr; 03378 03379 TRACE("%p\n", pProxy); 03380 03381 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 03382 if (SUCCEEDED(hr)) 03383 { 03384 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc, 03385 pAuthzSvc, ppServerPrincName, 03386 pAuthnLevel, pImpLevel, ppAuthInfo, 03387 pCapabilities); 03388 IClientSecurity_Release(pCliSec); 03389 } 03390 03391 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 03392 return hr; 03393 } 03394 03395 /*********************************************************************** 03396 * CoSetProxyBlanket [OLE32.@] 03397 * 03398 * Sets the security settings for a proxy. 03399 * 03400 * PARAMS 03401 * pProxy [I] Pointer to the proxy object. 03402 * AuthnSvc [I] The type of authentication service. 03403 * AuthzSvc [I] The type of authorization service. 03404 * pServerPrincName [I] The server prinicple name. 03405 * AuthnLevel [I] The authentication level. 03406 * ImpLevel [I] The impersonation level. 03407 * pAuthInfo [I] Information specific to the authorization/authentication service. 03408 * Capabilities [I] Flags affecting the security behaviour. 03409 * 03410 * RETURNS 03411 * Success: S_OK. 03412 * Failure: HRESULT code. 03413 * 03414 * SEE ALSO 03415 * CoQueryProxyBlanket, CoCopyProxy. 03416 */ 03417 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc, 03418 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel, 03419 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities) 03420 { 03421 IClientSecurity *pCliSec; 03422 HRESULT hr; 03423 03424 TRACE("%p\n", pProxy); 03425 03426 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 03427 if (SUCCEEDED(hr)) 03428 { 03429 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc, 03430 AuthzSvc, pServerPrincName, 03431 AuthnLevel, ImpLevel, pAuthInfo, 03432 Capabilities); 03433 IClientSecurity_Release(pCliSec); 03434 } 03435 03436 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 03437 return hr; 03438 } 03439 03440 /*********************************************************************** 03441 * CoCopyProxy [OLE32.@] 03442 * 03443 * Copies a proxy. 03444 * 03445 * PARAMS 03446 * pProxy [I] Pointer to the proxy object. 03447 * ppCopy [O] Copy of the proxy. 03448 * 03449 * RETURNS 03450 * Success: S_OK. 03451 * Failure: HRESULT code. 03452 * 03453 * SEE ALSO 03454 * CoQueryProxyBlanket, CoSetProxyBlanket. 03455 */ 03456 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) 03457 { 03458 IClientSecurity *pCliSec; 03459 HRESULT hr; 03460 03461 TRACE("%p\n", pProxy); 03462 03463 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); 03464 if (SUCCEEDED(hr)) 03465 { 03466 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy); 03467 IClientSecurity_Release(pCliSec); 03468 } 03469 03470 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr); 03471 return hr; 03472 } 03473 03474 03475 /*********************************************************************** 03476 * CoGetCallContext [OLE32.@] 03477 * 03478 * Gets the context of the currently executing server call in the current 03479 * thread. 03480 * 03481 * PARAMS 03482 * riid [I] Context interface to return. 03483 * ppv [O] Pointer to memory that will receive the context on return. 03484 * 03485 * RETURNS 03486 * Success: S_OK. 03487 * Failure: HRESULT code. 03488 */ 03489 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv) 03490 { 03491 struct oletls *info = COM_CurrentInfo(); 03492 03493 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 03494 03495 if (!info) 03496 return E_OUTOFMEMORY; 03497 03498 if (!info->call_state) 03499 return RPC_E_CALL_COMPLETE; 03500 03501 return IUnknown_QueryInterface(info->call_state, riid, ppv); 03502 } 03503 03504 /*********************************************************************** 03505 * CoSwitchCallContext [OLE32.@] 03506 * 03507 * Switches the context of the currently executing server call in the current 03508 * thread. 03509 * 03510 * PARAMS 03511 * pObject [I] Pointer to new context object 03512 * ppOldObject [O] Pointer to memory that will receive old context object pointer 03513 * 03514 * RETURNS 03515 * Success: S_OK. 03516 * Failure: HRESULT code. 03517 */ 03518 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject) 03519 { 03520 struct oletls *info = COM_CurrentInfo(); 03521 03522 TRACE("(%p, %p)\n", pObject, ppOldObject); 03523 03524 if (!info) 03525 return E_OUTOFMEMORY; 03526 03527 *ppOldObject = info->call_state; 03528 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */ 03529 03530 return S_OK; 03531 } 03532 03533 /*********************************************************************** 03534 * CoQueryClientBlanket [OLE32.@] 03535 * 03536 * Retrieves the authentication information about the client of the currently 03537 * executing server call in the current thread. 03538 * 03539 * PARAMS 03540 * pAuthnSvc [O] Optional. The type of authentication service. 03541 * pAuthzSvc [O] Optional. The type of authorization service. 03542 * pServerPrincName [O] Optional. The server prinicple name. 03543 * pAuthnLevel [O] Optional. The authentication level. 03544 * pImpLevel [O] Optional. The impersonation level. 03545 * pPrivs [O] Optional. Information about the privileges of the client. 03546 * pCapabilities [IO] Optional. Flags affecting the security behaviour. 03547 * 03548 * RETURNS 03549 * Success: S_OK. 03550 * Failure: HRESULT code. 03551 * 03552 * SEE ALSO 03553 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext. 03554 */ 03555 HRESULT WINAPI CoQueryClientBlanket( 03556 DWORD *pAuthnSvc, 03557 DWORD *pAuthzSvc, 03558 OLECHAR **pServerPrincName, 03559 DWORD *pAuthnLevel, 03560 DWORD *pImpLevel, 03561 RPC_AUTHZ_HANDLE *pPrivs, 03562 DWORD *pCapabilities) 03563 { 03564 IServerSecurity *pSrvSec; 03565 HRESULT hr; 03566 03567 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n", 03568 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel, 03569 pPrivs, pCapabilities); 03570 03571 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 03572 if (SUCCEEDED(hr)) 03573 { 03574 hr = IServerSecurity_QueryBlanket( 03575 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, 03576 pImpLevel, pPrivs, pCapabilities); 03577 IServerSecurity_Release(pSrvSec); 03578 } 03579 03580 return hr; 03581 } 03582 03583 /*********************************************************************** 03584 * CoImpersonateClient [OLE32.@] 03585 * 03586 * Impersonates the client of the currently executing server call in the 03587 * current thread. 03588 * 03589 * PARAMS 03590 * None. 03591 * 03592 * RETURNS 03593 * Success: S_OK. 03594 * Failure: HRESULT code. 03595 * 03596 * NOTES 03597 * If this function fails then the current thread will not be impersonating 03598 * the client and all actions will take place on behalf of the server. 03599 * Therefore, it is important to check the return value from this function. 03600 * 03601 * SEE ALSO 03602 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext. 03603 */ 03604 HRESULT WINAPI CoImpersonateClient(void) 03605 { 03606 IServerSecurity *pSrvSec; 03607 HRESULT hr; 03608 03609 TRACE("\n"); 03610 03611 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 03612 if (SUCCEEDED(hr)) 03613 { 03614 hr = IServerSecurity_ImpersonateClient(pSrvSec); 03615 IServerSecurity_Release(pSrvSec); 03616 } 03617 03618 return hr; 03619 } 03620 03621 /*********************************************************************** 03622 * CoRevertToSelf [OLE32.@] 03623 * 03624 * Ends the impersonation of the client of the currently executing server 03625 * call in the current thread. 03626 * 03627 * PARAMS 03628 * None. 03629 * 03630 * RETURNS 03631 * Success: S_OK. 03632 * Failure: HRESULT code. 03633 * 03634 * SEE ALSO 03635 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext. 03636 */ 03637 HRESULT WINAPI CoRevertToSelf(void) 03638 { 03639 IServerSecurity *pSrvSec; 03640 HRESULT hr; 03641 03642 TRACE("\n"); 03643 03644 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec); 03645 if (SUCCEEDED(hr)) 03646 { 03647 hr = IServerSecurity_RevertToSelf(pSrvSec); 03648 IServerSecurity_Release(pSrvSec); 03649 } 03650 03651 return hr; 03652 } 03653 03654 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg) 03655 { 03656 /* first try to retrieve messages for incoming COM calls to the apartment window */ 03657 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) || 03658 /* next retrieve other messages necessary for the app to remain responsive */ 03659 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) || 03660 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD); 03661 } 03662 03663 /*********************************************************************** 03664 * CoWaitForMultipleHandles [OLE32.@] 03665 * 03666 * Waits for one or more handles to become signaled. 03667 * 03668 * PARAMS 03669 * dwFlags [I] Flags. See notes. 03670 * dwTimeout [I] Timeout in milliseconds. 03671 * cHandles [I] Number of handles pointed to by pHandles. 03672 * pHandles [I] Handles to wait for. 03673 * lpdwindex [O] Index of handle that was signaled. 03674 * 03675 * RETURNS 03676 * Success: S_OK. 03677 * Failure: RPC_S_CALLPENDING on timeout. 03678 * 03679 * NOTES 03680 * 03681 * The dwFlags parameter can be zero or more of the following: 03682 *| COWAIT_WAITALL - Wait for all of the handles to become signaled. 03683 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait. 03684 * 03685 * SEE ALSO 03686 * MsgWaitForMultipleObjects, WaitForMultipleObjects. 03687 */ 03688 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, 03689 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex) 03690 { 03691 HRESULT hr = S_OK; 03692 DWORD start_time = GetTickCount(); 03693 APARTMENT *apt = COM_CurrentApt(); 03694 BOOL message_loop = apt && !apt->multi_threaded; 03695 03696 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles, 03697 pHandles, lpdwindex); 03698 03699 while (TRUE) 03700 { 03701 DWORD now = GetTickCount(); 03702 DWORD res; 03703 03704 if (now - start_time > dwTimeout) 03705 { 03706 hr = RPC_S_CALLPENDING; 03707 break; 03708 } 03709 03710 if (message_loop) 03711 { 03712 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) | 03713 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0); 03714 03715 TRACE("waiting for rpc completion or window message\n"); 03716 03717 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles, 03718 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, 03719 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags); 03720 03721 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */ 03722 { 03723 MSG msg; 03724 03725 /* call message filter */ 03726 03727 if (COM_CurrentApt()->filter) 03728 { 03729 PENDINGTYPE pendingtype = 03730 COM_CurrentInfo()->pending_call_count_server ? 03731 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL; 03732 DWORD be_handled = IMessageFilter_MessagePending( 03733 COM_CurrentApt()->filter, 0 /* FIXME */, 03734 now - start_time, pendingtype); 03735 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled); 03736 switch (be_handled) 03737 { 03738 case PENDINGMSG_CANCELCALL: 03739 WARN("call canceled\n"); 03740 hr = RPC_E_CALL_CANCELED; 03741 break; 03742 case PENDINGMSG_WAITNOPROCESS: 03743 case PENDINGMSG_WAITDEFPROCESS: 03744 default: 03745 /* FIXME: MSDN is very vague about the difference 03746 * between WAITNOPROCESS and WAITDEFPROCESS - there 03747 * appears to be none, so it is possibly a left-over 03748 * from the 16-bit world. */ 03749 break; 03750 } 03751 } 03752 03753 while (COM_PeekMessage(apt, &msg)) 03754 { 03755 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message); 03756 TranslateMessage(&msg); 03757 DispatchMessageW(&msg); 03758 if (msg.message == WM_QUIT) 03759 { 03760 TRACE("resending WM_QUIT to outer message loop\n"); 03761 PostQuitMessage(msg.wParam); 03762 /* no longer need to process messages */ 03763 message_loop = FALSE; 03764 break; 03765 } 03766 } 03767 continue; 03768 } 03769 } 03770 else 03771 { 03772 TRACE("waiting for rpc completion\n"); 03773 03774 res = WaitForMultipleObjectsEx(cHandles, pHandles, 03775 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE, 03776 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, 03777 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE); 03778 } 03779 03780 switch (res) 03781 { 03782 case WAIT_TIMEOUT: 03783 hr = RPC_S_CALLPENDING; 03784 break; 03785 case WAIT_FAILED: 03786 hr = HRESULT_FROM_WIN32( GetLastError() ); 03787 break; 03788 default: 03789 *lpdwindex = res; 03790 break; 03791 } 03792 break; 03793 } 03794 TRACE("-- 0x%08x\n", hr); 03795 return hr; 03796 } 03797 03798 03799 /*********************************************************************** 03800 * CoGetObject [OLE32.@] 03801 * 03802 * Gets the object named by converting the name to a moniker and binding to it. 03803 * 03804 * PARAMS 03805 * pszName [I] String representing the object. 03806 * pBindOptions [I] Parameters affecting the binding to the named object. 03807 * riid [I] Interface to bind to on the objecct. 03808 * ppv [O] On output, the interface riid of the object represented 03809 * by pszName. 03810 * 03811 * RETURNS 03812 * Success: S_OK. 03813 * Failure: HRESULT code. 03814 * 03815 * SEE ALSO 03816 * MkParseDisplayName. 03817 */ 03818 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions, 03819 REFIID riid, void **ppv) 03820 { 03821 IBindCtx *pbc; 03822 HRESULT hr; 03823 03824 *ppv = NULL; 03825 03826 hr = CreateBindCtx(0, &pbc); 03827 if (SUCCEEDED(hr)) 03828 { 03829 if (pBindOptions) 03830 hr = IBindCtx_SetBindOptions(pbc, pBindOptions); 03831 03832 if (SUCCEEDED(hr)) 03833 { 03834 ULONG chEaten; 03835 IMoniker *pmk; 03836 03837 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk); 03838 if (SUCCEEDED(hr)) 03839 { 03840 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv); 03841 IMoniker_Release(pmk); 03842 } 03843 } 03844 03845 IBindCtx_Release(pbc); 03846 } 03847 return hr; 03848 } 03849 03850 /*********************************************************************** 03851 * CoRegisterChannelHook [OLE32.@] 03852 * 03853 * Registers a process-wide hook that is called during ORPC calls. 03854 * 03855 * PARAMS 03856 * guidExtension [I] GUID of the channel hook to register. 03857 * pChannelHook [I] Channel hook object to register. 03858 * 03859 * RETURNS 03860 * Success: S_OK. 03861 * Failure: HRESULT code. 03862 */ 03863 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook) 03864 { 03865 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook); 03866 03867 return RPC_RegisterChannelHook(guidExtension, pChannelHook); 03868 } 03869 03870 typedef struct Context 03871 { 03872 IComThreadingInfo IComThreadingInfo_iface; 03873 IContextCallback IContextCallback_iface; 03874 IObjContext IObjContext_iface; 03875 LONG refs; 03876 APTTYPE apttype; 03877 } Context; 03878 03879 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface ) 03880 { 03881 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface); 03882 } 03883 03884 static inline Context *impl_from_IContextCallback( IContextCallback *iface ) 03885 { 03886 return CONTAINING_RECORD(iface, Context, IContextCallback_iface); 03887 } 03888 03889 static inline Context *impl_from_IObjContext( IObjContext *iface ) 03890 { 03891 return CONTAINING_RECORD(iface, Context, IObjContext_iface); 03892 } 03893 03894 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv) 03895 { 03896 *ppv = NULL; 03897 03898 if (IsEqualIID(riid, &IID_IComThreadingInfo) || 03899 IsEqualIID(riid, &IID_IUnknown)) 03900 { 03901 *ppv = &iface->IComThreadingInfo_iface; 03902 } 03903 else if (IsEqualIID(riid, &IID_IContextCallback)) 03904 { 03905 *ppv = &iface->IContextCallback_iface; 03906 } 03907 else if (IsEqualIID(riid, &IID_IObjContext)) 03908 { 03909 *ppv = &iface->IObjContext_iface; 03910 } 03911 03912 if (*ppv) 03913 { 03914 IUnknown_AddRef((IUnknown*)*ppv); 03915 return S_OK; 03916 } 03917 03918 FIXME("interface not implemented %s\n", debugstr_guid(riid)); 03919 return E_NOINTERFACE; 03920 } 03921 03922 static ULONG Context_AddRef(Context *This) 03923 { 03924 return InterlockedIncrement(&This->refs); 03925 } 03926 03927 static ULONG Context_Release(Context *This) 03928 { 03929 ULONG refs = InterlockedDecrement(&This->refs); 03930 if (!refs) 03931 HeapFree(GetProcessHeap(), 0, This); 03932 return refs; 03933 } 03934 03935 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv) 03936 { 03937 Context *This = impl_from_IComThreadingInfo(iface); 03938 return Context_QueryInterface(This, riid, ppv); 03939 } 03940 03941 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface) 03942 { 03943 Context *This = impl_from_IComThreadingInfo(iface); 03944 return Context_AddRef(This); 03945 } 03946 03947 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface) 03948 { 03949 Context *This = impl_from_IComThreadingInfo(iface); 03950 return Context_Release(This); 03951 } 03952 03953 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype) 03954 { 03955 Context *This = impl_from_IComThreadingInfo(iface); 03956 03957 TRACE("(%p)\n", apttype); 03958 03959 *apttype = This->apttype; 03960 return S_OK; 03961 } 03962 03963 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype) 03964 { 03965 Context *This = impl_from_IComThreadingInfo(iface); 03966 03967 TRACE("(%p)\n", thdtype); 03968 03969 switch (This->apttype) 03970 { 03971 case APTTYPE_STA: 03972 case APTTYPE_MAINSTA: 03973 *thdtype = THDTYPE_PROCESSMESSAGES; 03974 break; 03975 default: 03976 *thdtype = THDTYPE_BLOCKMESSAGES; 03977 break; 03978 } 03979 return S_OK; 03980 } 03981 03982 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id) 03983 { 03984 FIXME("(%p): stub\n", logical_thread_id); 03985 return E_NOTIMPL; 03986 } 03987 03988 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id) 03989 { 03990 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id)); 03991 return E_NOTIMPL; 03992 } 03993 03994 static const IComThreadingInfoVtbl Context_Threading_Vtbl = 03995 { 03996 Context_CTI_QueryInterface, 03997 Context_CTI_AddRef, 03998 Context_CTI_Release, 03999 Context_CTI_GetCurrentApartmentType, 04000 Context_CTI_GetCurrentThreadType, 04001 Context_CTI_GetCurrentLogicalThreadId, 04002 Context_CTI_SetCurrentLogicalThreadId 04003 }; 04004 04005 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv) 04006 { 04007 Context *This = impl_from_IContextCallback(iface); 04008 return Context_QueryInterface(This, riid, ppv); 04009 } 04010 04011 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface) 04012 { 04013 Context *This = impl_from_IContextCallback(iface); 04014 return Context_AddRef(This); 04015 } 04016 04017 static ULONG WINAPI Context_CC_Release(IContextCallback *iface) 04018 { 04019 Context *This = impl_from_IContextCallback(iface); 04020 return Context_Release(This); 04021 } 04022 04023 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback, 04024 ComCallData *param, REFIID riid, int method, IUnknown *punk) 04025 { 04026 Context *This = impl_from_IContextCallback(iface); 04027 04028 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk); 04029 return E_NOTIMPL; 04030 } 04031 04032 static const IContextCallbackVtbl Context_Callback_Vtbl = 04033 { 04034 Context_CC_QueryInterface, 04035 Context_CC_AddRef, 04036 Context_CC_Release, 04037 Context_CC_ContextCallback 04038 }; 04039 04040 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv) 04041 { 04042 Context *This = impl_from_IObjContext(iface); 04043 return Context_QueryInterface(This, riid, ppv); 04044 } 04045 04046 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface) 04047 { 04048 Context *This = impl_from_IObjContext(iface); 04049 return Context_AddRef(This); 04050 } 04051 04052 static ULONG WINAPI Context_OC_Release(IObjContext *iface) 04053 { 04054 Context *This = impl_from_IObjContext(iface); 04055 return Context_Release(This); 04056 } 04057 04058 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk) 04059 { 04060 Context *This = impl_from_IObjContext(iface); 04061 04062 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk); 04063 return E_NOTIMPL; 04064 } 04065 04066 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid) 04067 { 04068 Context *This = impl_from_IObjContext(iface); 04069 04070 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid)); 04071 return E_NOTIMPL; 04072 } 04073 04074 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk) 04075 { 04076 Context *This = impl_from_IObjContext(iface); 04077 04078 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk); 04079 return E_NOTIMPL; 04080 } 04081 04082 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props) 04083 { 04084 Context *This = impl_from_IObjContext(iface); 04085 04086 FIXME("(%p/%p)->(%p)\n", This, iface, props); 04087 return E_NOTIMPL; 04088 } 04089 04090 static void WINAPI Context_OC_Reserved1(IObjContext *iface) 04091 { 04092 Context *This = impl_from_IObjContext(iface); 04093 FIXME("(%p/%p)\n", This, iface); 04094 } 04095 04096 static void WINAPI Context_OC_Reserved2(IObjContext *iface) 04097 { 04098 Context *This = impl_from_IObjContext(iface); 04099 FIXME("(%p/%p)\n", This, iface); 04100 } 04101 04102 static void WINAPI Context_OC_Reserved3(IObjContext *iface) 04103 { 04104 Context *This = impl_from_IObjContext(iface); 04105 FIXME("(%p/%p)\n", This, iface); 04106 } 04107 04108 static void WINAPI Context_OC_Reserved4(IObjContext *iface) 04109 { 04110 Context *This = impl_from_IObjContext(iface); 04111 FIXME("(%p/%p)\n", This, iface); 04112 } 04113 04114 static void WINAPI Context_OC_Reserved5(IObjContext *iface) 04115 { 04116 Context *This = impl_from_IObjContext(iface); 04117 FIXME("(%p/%p)\n", This, iface); 04118 } 04119 04120 static void WINAPI Context_OC_Reserved6(IObjContext *iface) 04121 { 04122 Context *This = impl_from_IObjContext(iface); 04123 FIXME("(%p/%p)\n", This, iface); 04124 } 04125 04126 static void WINAPI Context_OC_Reserved7(IObjContext *iface) 04127 { 04128 Context *This = impl_from_IObjContext(iface); 04129 FIXME("(%p/%p)\n", This, iface); 04130 } 04131 04132 static const IObjContextVtbl Context_Object_Vtbl = 04133 { 04134 Context_OC_QueryInterface, 04135 Context_OC_AddRef, 04136 Context_OC_Release, 04137 Context_OC_SetProperty, 04138 Context_OC_RemoveProperty, 04139 Context_OC_GetProperty, 04140 Context_OC_EnumContextProps, 04141 Context_OC_Reserved1, 04142 Context_OC_Reserved2, 04143 Context_OC_Reserved3, 04144 Context_OC_Reserved4, 04145 Context_OC_Reserved5, 04146 Context_OC_Reserved6, 04147 Context_OC_Reserved7 04148 }; 04149 04150 /*********************************************************************** 04151 * CoGetObjectContext [OLE32.@] 04152 * 04153 * Retrieves an object associated with the current context (i.e. apartment). 04154 * 04155 * PARAMS 04156 * riid [I] ID of the interface of the object to retrieve. 04157 * ppv [O] Address where object will be stored on return. 04158 * 04159 * RETURNS 04160 * Success: S_OK. 04161 * Failure: HRESULT code. 04162 */ 04163 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) 04164 { 04165 APARTMENT *apt = COM_CurrentApt(); 04166 Context *context; 04167 HRESULT hr; 04168 04169 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 04170 04171 *ppv = NULL; 04172 if (!apt) 04173 { 04174 if (!(apt = apartment_find_multi_threaded())) 04175 { 04176 ERR("apartment not initialised\n"); 04177 return CO_E_NOTINITIALIZED; 04178 } 04179 apartment_release(apt); 04180 } 04181 04182 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context)); 04183 if (!context) 04184 return E_OUTOFMEMORY; 04185 04186 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl; 04187 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl; 04188 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl; 04189 context->refs = 1; 04190 if (apt->multi_threaded) 04191 context->apttype = APTTYPE_MTA; 04192 else if (apt->main) 04193 context->apttype = APTTYPE_MAINSTA; 04194 else 04195 context->apttype = APTTYPE_STA; 04196 04197 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv); 04198 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface); 04199 04200 return hr; 04201 } 04202 04203 04204 /*********************************************************************** 04205 * CoGetContextToken [OLE32.@] 04206 */ 04207 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) 04208 { 04209 struct oletls *info = COM_CurrentInfo(); 04210 04211 TRACE("(%p)\n", token); 04212 04213 if (!info) 04214 return E_OUTOFMEMORY; 04215 04216 if (!info->apt) 04217 { 04218 APARTMENT *apt; 04219 if (!(apt = apartment_find_multi_threaded())) 04220 { 04221 ERR("apartment not initialised\n"); 04222 return CO_E_NOTINITIALIZED; 04223 } 04224 apartment_release(apt); 04225 } 04226 04227 if (!token) 04228 return E_POINTER; 04229 04230 if (!info->context_token) 04231 { 04232 HRESULT hr; 04233 IObjContext *ctx; 04234 04235 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx); 04236 if (FAILED(hr)) return hr; 04237 info->context_token = ctx; 04238 } 04239 04240 *token = (ULONG_PTR)info->context_token; 04241 TRACE("apt->context_token=%p\n", info->context_token); 04242 04243 return S_OK; 04244 } 04245 04246 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 04247 { 04248 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; 04249 HKEY hkey; 04250 HRESULT hres; 04251 04252 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey); 04253 if (SUCCEEDED(hres)) 04254 { 04255 WCHAR dllpath[MAX_PATH+1]; 04256 04257 if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS) 04258 { 04259 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; 04260 if (!strcmpiW(dllpath, wszOle32)) 04261 { 04262 RegCloseKey(hkey); 04263 return HandlerCF_Create(rclsid, riid, ppv); 04264 } 04265 } 04266 else 04267 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath)); 04268 RegCloseKey(hkey); 04269 } 04270 04271 return CLASS_E_CLASSNOTAVAILABLE; 04272 } 04273 04274 /*********************************************************************** 04275 * DllMain (OLE32.@) 04276 */ 04277 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) 04278 { 04279 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad); 04280 04281 switch(fdwReason) { 04282 case DLL_PROCESS_ATTACH: 04283 hProxyDll = hinstDLL; 04284 COMPOBJ_InitProcess(); 04285 break; 04286 04287 case DLL_PROCESS_DETACH: 04288 COMPOBJ_UninitProcess(); 04289 RPC_UnregisterAllChannelHooks(); 04290 COMPOBJ_DllList_Free(); 04291 DeleteCriticalSection(&csRegisteredClassList); 04292 DeleteCriticalSection(&csApartment); 04293 break; 04294 04295 case DLL_THREAD_DETACH: 04296 COM_TlsDestroy(); 04297 break; 04298 } 04299 return TRUE; 04300 } 04301 04302 /*********************************************************************** 04303 * DllRegisterServer (OLE32.@) 04304 */ 04305 HRESULT WINAPI DllRegisterServer(void) 04306 { 04307 return OLE32_DllRegisterServer(); 04308 } 04309 04310 /*********************************************************************** 04311 * DllUnregisterServer (OLE32.@) 04312 */ 04313 HRESULT WINAPI DllUnregisterServer(void) 04314 { 04315 return OLE32_DllUnregisterServer(); 04316 } Generated on Sat May 26 2012 04:24:06 for ReactOS by
1.7.6.1
|