4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
37 * - Make all ole interface marshaling use NDR to be wire compatible with
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
62 #include "compobj_private.h"
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
69 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
71 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
73 /****************************************************************************
74 * This section defines variables internal to the COM module.
76 * TODO: Most of these things will have to be made thread-safe.
79 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
80 DWORD dwClsContext, LPUNKNOWN* ppUnk);
81 static void COM_RevokeAllClasses(const struct apartment *apt);
82 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv);
84 static APARTMENT *MTA; /* protected by csApartment */
85 static APARTMENT *MainApartment; /* the first STA apartment */
86 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
88 static CRITICAL_SECTION csApartment;
89 static CRITICAL_SECTION_DEBUG critsect_debug =
92 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
93 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
95 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
97 struct registered_psclsid
105 * This lock count counts the number of times CoInitialize is called. It is
106 * decreased every time CoUninitialize is called. When it hits 0, the COM
107 * libraries are freed
109 static LONG s_COMLockCount = 0;
110 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
111 static LONG s_COMServerProcessReferences = 0;
114 * This linked list contains the list of registered class objects. These
115 * are mostly used to register the factories for out-of-proc servers of OLE
118 * TODO: Make this data structure aware of inter-process communication. This
119 * means that parts of this will be exported to the Wine Server.
121 typedef struct tagRegisteredClass
124 CLSID classIdentifier;
126 LPUNKNOWN classObject;
130 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
131 void *RpcRegistration;
134 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
136 static CRITICAL_SECTION csRegisteredClassList;
137 static CRITICAL_SECTION_DEBUG class_cs_debug =
139 0, 0, &csRegisteredClassList,
140 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
141 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
143 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
145 /*****************************************************************************
146 * This section contains OpenDllList definitions
148 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
149 * other functions that do LoadLibrary _without_ giving back a HMODULE.
150 * Without this list these handles would never be freed.
152 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
153 * next unload-call but not before 600 sec.
156 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
157 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
159 typedef struct tagOpenDll
164 DllGetClassObjectFunc DllGetClassObject;
165 DllCanUnloadNowFunc DllCanUnloadNow;
169 static struct list openDllList = LIST_INIT(openDllList);
171 static CRITICAL_SECTION csOpenDllList;
172 static CRITICAL_SECTION_DEBUG dll_cs_debug =
174 0, 0, &csOpenDllList,
175 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
176 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
178 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
180 struct apartment_loaded_dll
186 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',' ',
187 '0','x','#','#','#','#','#','#','#','#',' ',0};
188 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
189 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
190 REFCLSID rclsid, REFIID riid, void **ppv);
191 static void apartment_freeunusedlibraries(struct apartment *apt);
193 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
194 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
195 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
197 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
199 static void COMPOBJ_InitProcess( void )
203 /* Dispatching to the correct thread in an apartment is done through
204 * window messages rather than RPC transports. When an interface is
205 * marshalled into another apartment in the same process, a window of the
206 * following class is created. The *caller* of CoMarshalInterface (ie the
207 * application) is responsible for pumping the message loop in that thread.
208 * The WM_USER messages which point to the RPCs are then dispatched to
209 * COM_AptWndProc by the user's code from the apartment in which the interface
212 memset(&wclass, 0, sizeof(wclass));
213 wclass.lpfnWndProc = apartment_wndproc;
214 wclass.hInstance = OLE32_hInstance;
215 wclass.lpszClassName = wszAptWinClass;
216 RegisterClassW(&wclass);
219 static void COMPOBJ_UninitProcess( void )
221 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
224 static void COM_TlsDestroy(void)
226 struct oletls *info = NtCurrentTeb()->ReservedForOle;
229 if (info->apt) apartment_release(info->apt);
230 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
231 if (info->state) IUnknown_Release(info->state);
232 HeapFree(GetProcessHeap(), 0, info);
233 NtCurrentTeb()->ReservedForOle = NULL;
237 /******************************************************************************
241 /* allocates memory and fills in the necessary fields for a new apartment
242 * object. must be called inside apartment cs */
243 static APARTMENT *apartment_construct(DWORD model)
247 TRACE("creating new apartment, model=%d\n", model);
249 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
250 apt->tid = GetCurrentThreadId();
252 list_init(&apt->proxies);
253 list_init(&apt->stubmgrs);
254 list_init(&apt->psclsids);
255 list_init(&apt->loaded_dlls);
258 apt->remunk_exported = FALSE;
260 InitializeCriticalSection(&apt->cs);
261 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
263 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
265 if (apt->multi_threaded)
267 /* FIXME: should be randomly generated by in an RPC call to rpcss */
268 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
272 /* FIXME: should be randomly generated by in an RPC call to rpcss */
273 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
276 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
278 list_add_head(&apts, &apt->entry);
283 /* gets and existing apartment if one exists or otherwise creates an apartment
284 * structure which stores OLE apartment-local information and stores a pointer
285 * to it in the thread-local storage */
286 static APARTMENT *apartment_get_or_create(DWORD model)
288 APARTMENT *apt = COM_CurrentApt();
292 if (model & COINIT_APARTMENTTHREADED)
294 EnterCriticalSection(&csApartment);
296 apt = apartment_construct(model);
301 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
304 LeaveCriticalSection(&csApartment);
308 EnterCriticalSection(&csApartment);
310 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
311 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
315 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
316 apartment_addref(MTA);
319 MTA = apartment_construct(model);
323 LeaveCriticalSection(&csApartment);
325 COM_CurrentInfo()->apt = apt;
331 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
333 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
336 DWORD apartment_addref(struct apartment *apt)
338 DWORD refs = InterlockedIncrement(&apt->refs);
339 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
343 DWORD apartment_release(struct apartment *apt)
347 EnterCriticalSection(&csApartment);
349 ret = InterlockedDecrement(&apt->refs);
350 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
351 /* destruction stuff that needs to happen under csApartment CS */
354 if (apt == MTA) MTA = NULL;
355 else if (apt == MainApartment) MainApartment = NULL;
356 list_remove(&apt->entry);
359 LeaveCriticalSection(&csApartment);
363 struct list *cursor, *cursor2;
365 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
367 /* Release the references to the registered class objects */
368 COM_RevokeAllClasses(apt);
370 /* no locking is needed for this apartment, because no other thread
371 * can access it at this point */
373 apartment_disconnectproxies(apt);
375 if (apt->win) DestroyWindow(apt->win);
376 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
378 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
380 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
381 /* release the implicit reference given by the fact that the
382 * stub has external references (it must do since it is in the
383 * stub manager list in the apartment and all non-apartment users
384 * must have a ref on the apartment and so it cannot be destroyed).
386 stub_manager_int_release(stubmgr);
389 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
391 struct registered_psclsid *registered_psclsid =
392 LIST_ENTRY(cursor, struct registered_psclsid, entry);
394 list_remove(®istered_psclsid->entry);
395 HeapFree(GetProcessHeap(), 0, registered_psclsid);
398 /* if this assert fires, then another thread took a reference to a
399 * stub manager without taking a reference to the containing
400 * apartment, which it must do. */
401 assert(list_empty(&apt->stubmgrs));
403 if (apt->filter) IUnknown_Release(apt->filter);
405 /* free as many unused libraries as possible... */
406 apartment_freeunusedlibraries(apt);
408 /* ... and free the memory for the apartment loaded dll entry and
409 * release the dll list reference without freeing the library for the
411 while ((cursor = list_head(&apt->loaded_dlls)))
413 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
414 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
416 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
419 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
420 DeleteCriticalSection(&apt->cs);
422 HeapFree(GetProcessHeap(), 0, apt);
428 /* The given OXID must be local to this process:
430 * The ref parameter is here mostly to ensure people remember that
431 * they get one, you should normally take a ref for thread safety.
433 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
435 APARTMENT *result = NULL;
438 EnterCriticalSection(&csApartment);
439 LIST_FOR_EACH( cursor, &apts )
441 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
442 if (apt->oxid == oxid)
445 if (ref) apartment_addref(result);
449 LeaveCriticalSection(&csApartment);
454 /* gets the apartment which has a given creator thread ID. The caller must
455 * release the reference from the apartment as soon as the apartment pointer
456 * is no longer required. */
457 APARTMENT *apartment_findfromtid(DWORD tid)
459 APARTMENT *result = NULL;
462 EnterCriticalSection(&csApartment);
463 LIST_FOR_EACH( cursor, &apts )
465 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
469 apartment_addref(result);
473 LeaveCriticalSection(&csApartment);
478 /* gets the main apartment if it exists. The caller must
479 * release the reference from the apartment as soon as the apartment pointer
480 * is no longer required. */
481 static APARTMENT *apartment_findmain(void)
485 EnterCriticalSection(&csApartment);
487 result = MainApartment;
488 if (result) apartment_addref(result);
490 LeaveCriticalSection(&csApartment);
495 struct host_object_params
498 CLSID clsid; /* clsid of object to marshal */
499 IID iid; /* interface to marshal */
500 HANDLE event; /* event signalling when ready for multi-threaded case */
501 HRESULT hr; /* result for multi-threaded case */
502 IStream *stream; /* stream that the object will be marshaled into */
505 static HRESULT apartment_hostobject(struct apartment *apt,
506 const struct host_object_params *params)
510 static const LARGE_INTEGER llZero;
511 WCHAR dllpath[MAX_PATH+1];
513 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid));
515 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
517 /* failure: CLSID is not found in registry */
518 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
519 return REGDB_E_CLASSNOTREG;
522 hr = apartment_getclassobject(apt, dllpath, ¶ms->clsid, ¶ms->iid, (void **)&object);
526 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
528 IUnknown_Release(object);
529 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
534 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
539 RPC_ExecuteCall((struct dispatch_params *)lParam);
542 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
544 return DefWindowProcW(hWnd, msg, wParam, lParam);
548 struct host_thread_params
550 COINIT threading_model;
555 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
557 struct host_thread_params *params = p;
560 struct apartment *apt;
564 hr = CoInitializeEx(NULL, params->threading_model);
565 if (FAILED(hr)) return hr;
567 apt = COM_CurrentApt();
568 if (params->threading_model == COINIT_APARTMENTTHREADED)
570 apartment_createwindowifneeded(apt);
571 params->apartment_hwnd = apartment_getwindow(apt);
574 params->apartment_hwnd = NULL;
576 /* force the message queue to be created before signaling parent thread */
577 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
579 SetEvent(params->ready_event);
580 params = NULL; /* can't touch params after here as it may be invalid */
582 while (GetMessageW(&msg, NULL, 0, 0))
584 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
586 struct host_object_params *params = (struct host_object_params *)msg.lParam;
587 params->hr = apartment_hostobject(apt, params);
588 SetEvent(params->event);
592 TranslateMessage(&msg);
593 DispatchMessageW(&msg);
604 static HRESULT apartment_hostobject_in_hostapt(struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
606 struct host_object_params params;
607 HWND apartment_hwnd = NULL;
608 DWORD apartment_tid = 0;
611 if (!multi_threaded && main_apartment)
613 APARTMENT *host_apt = apartment_findmain();
616 apartment_hwnd = apartment_getwindow(host_apt);
617 apartment_release(host_apt);
623 EnterCriticalSection(&apt->cs);
625 if (!apt->host_apt_tid)
627 struct host_thread_params thread_params;
631 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
632 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
633 thread_params.apartment_hwnd = NULL;
634 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
637 CloseHandle(handles[0]);
638 LeaveCriticalSection(&apt->cs);
639 return E_OUTOFMEMORY;
641 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
642 CloseHandle(handles[0]);
643 CloseHandle(handles[1]);
644 if (wait_value == WAIT_OBJECT_0)
645 apt->host_apt_hwnd = thread_params.apartment_hwnd;
648 LeaveCriticalSection(&apt->cs);
649 return E_OUTOFMEMORY;
653 if (multi_threaded || !main_apartment)
655 apartment_hwnd = apt->host_apt_hwnd;
656 apartment_tid = apt->host_apt_tid;
659 LeaveCriticalSection(&apt->cs);
662 /* another thread may have become the main apartment in the time it took
663 * us to create the thread for the host apartment */
664 if (!apartment_hwnd && !multi_threaded && main_apartment)
666 APARTMENT *host_apt = apartment_findmain();
669 apartment_hwnd = apartment_getwindow(host_apt);
670 apartment_release(host_apt);
674 params.hkeydll = hkeydll;
675 params.clsid = *rclsid;
677 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
683 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
684 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms))
688 WaitForSingleObject(params.event, INFINITE);
691 CloseHandle(params.event);
697 ERR("host apartment didn't create window\n");
701 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
704 hr = CoUnmarshalInterface(params.stream, riid, ppv);
705 IStream_Release(params.stream);
709 HRESULT apartment_createwindowifneeded(struct apartment *apt)
711 if (apt->multi_threaded)
716 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
718 0, 0, OLE32_hInstance, NULL);
721 ERR("CreateWindow failed with error %d\n", GetLastError());
722 return HRESULT_FROM_WIN32(GetLastError());
724 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
725 /* someone beat us to it */
732 HWND apartment_getwindow(const struct apartment *apt)
734 assert(!apt->multi_threaded);
738 void apartment_joinmta(void)
740 apartment_addref(MTA);
741 COM_CurrentInfo()->apt = MTA;
744 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
745 REFCLSID rclsid, REFIID riid, void **ppv)
747 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
750 struct apartment_loaded_dll *apartment_loaded_dll;
752 if (!strcmpiW(dllpath, wszOle32))
754 /* we don't need to control the lifetime of this dll, so use the local
755 * implementation of DllGetClassObject directly */
756 TRACE("calling ole32!DllGetClassObject\n");
757 hr = DllGetClassObject(rclsid, riid, ppv);
760 ERR("DllGetClassObject returned error 0x%08x\n", hr);
765 EnterCriticalSection(&apt->cs);
767 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
768 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
770 TRACE("found %s already loaded\n", debugstr_w(dllpath));
777 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
778 if (!apartment_loaded_dll)
782 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
784 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
788 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
789 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
793 LeaveCriticalSection(&apt->cs);
797 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
798 /* OK: get the ClassObject */
799 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
802 ERR("DllGetClassObject returned error 0x%08x\n", hr);
808 static void apartment_freeunusedlibraries(struct apartment *apt)
810 struct apartment_loaded_dll *entry, *next;
811 EnterCriticalSection(&apt->cs);
812 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
814 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
816 list_remove(&entry->entry);
817 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
818 HeapFree(GetProcessHeap(), 0, entry);
821 LeaveCriticalSection(&apt->cs);
824 /*****************************************************************************
825 * This section contains OpenDllList implementation
828 /* caller must ensure that library_name is not already in the open dll list */
829 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
835 DllCanUnloadNowFunc DllCanUnloadNow;
836 DllGetClassObjectFunc DllGetClassObject;
840 *ret = COMPOBJ_DllList_Get(library_name);
841 if (*ret) return S_OK;
843 /* do this outside the csOpenDllList to avoid creating a lock dependency on
845 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
848 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
849 /* failure: DLL could not be loaded */
850 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
853 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
854 /* Note: failing to find DllCanUnloadNow is not a failure */
855 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
856 if (!DllGetClassObject)
858 /* failure: the dll did not export DllGetClassObject */
859 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
860 FreeLibrary(hLibrary);
861 return CO_E_DLLNOTFOUND;
864 EnterCriticalSection( &csOpenDllList );
866 *ret = COMPOBJ_DllList_Get(library_name);
869 /* another caller to this function already added the dll while we
870 * weren't in the critical section */
871 FreeLibrary(hLibrary);
875 len = strlenW(library_name);
876 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
878 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
879 if (entry && entry->library_name)
881 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
882 entry->library = hLibrary;
884 entry->DllCanUnloadNow = DllCanUnloadNow;
885 entry->DllGetClassObject = DllGetClassObject;
886 list_add_tail(&openDllList, &entry->entry);
891 FreeLibrary(hLibrary);
896 LeaveCriticalSection( &csOpenDllList );
901 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
905 EnterCriticalSection(&csOpenDllList);
906 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
908 if (!strcmpiW(library_name, ptr->library_name) &&
909 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
915 LeaveCriticalSection(&csOpenDllList);
919 /* pass FALSE for free_entry to release a reference without destroying the
920 * entry if it reaches zero or TRUE otherwise */
921 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
923 if (!InterlockedDecrement(&entry->refs) && free_entry)
925 EnterCriticalSection(&csOpenDllList);
926 list_remove(&entry->entry);
927 LeaveCriticalSection(&csOpenDllList);
929 TRACE("freeing %p\n", entry->library);
930 FreeLibrary(entry->library);
932 HeapFree(GetProcessHeap(), 0, entry->library_name);
933 HeapFree(GetProcessHeap(), 0, entry);
937 /******************************************************************************
938 * CoBuildVersion [OLE32.@]
939 * CoBuildVersion [COMPOBJ.1]
941 * Gets the build version of the DLL.
946 * Current build version, hiword is majornumber, loword is minornumber
948 DWORD WINAPI CoBuildVersion(void)
950 TRACE("Returning version %d, build %d.\n", rmm, rup);
951 return (rmm<<16)+rup;
954 /******************************************************************************
955 * CoInitialize [OLE32.@]
957 * Initializes the COM libraries by calling CoInitializeEx with
958 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
961 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
964 * Success: S_OK if not already initialized, S_FALSE otherwise.
965 * Failure: HRESULT code.
970 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
973 * Just delegate to the newer method.
975 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
978 /******************************************************************************
979 * CoInitializeEx [OLE32.@]
981 * Initializes the COM libraries.
984 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
985 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
988 * S_OK if successful,
989 * S_FALSE if this function was called already.
990 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
995 * The behavior used to set the IMalloc used for memory management is
997 * The dwCoInit parameter must specify one of the following apartment
999 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1000 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1001 * The parameter may also specify zero or more of the following flags:
1002 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1003 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1008 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1013 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1015 if (lpReserved!=NULL)
1017 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1021 * Check the lock count. If this is the first time going through the initialize
1022 * process, we have to initialize the libraries.
1024 * And crank-up that lock count.
1026 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1029 * Initialize the various COM libraries and data structures.
1031 TRACE("() - Initializing the COM libraries\n");
1033 /* we may need to defer this until after apartment initialisation */
1034 RunningObjectTableImpl_Initialize();
1037 if (!(apt = COM_CurrentInfo()->apt))
1039 apt = apartment_get_or_create(dwCoInit);
1040 if (!apt) return E_OUTOFMEMORY;
1042 else if (!apartment_is_model(apt, dwCoInit))
1044 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1045 code then we are probably using the wrong threading model to implement that API. */
1046 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1047 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1048 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1049 return RPC_E_CHANGED_MODE;
1054 COM_CurrentInfo()->inits++;
1059 /***********************************************************************
1060 * CoUninitialize [OLE32.@]
1062 * This method will decrement the refcount on the current apartment, freeing
1063 * the resources associated with it if it is the last thread in the apartment.
1064 * If the last apartment is freed, the function will additionally release
1065 * any COM resources associated with the process.
1075 void WINAPI CoUninitialize(void)
1077 struct oletls * info = COM_CurrentInfo();
1082 /* will only happen on OOM */
1088 ERR("Mismatched CoUninitialize\n");
1094 apartment_release(info->apt);
1099 * Decrease the reference count.
1100 * If we are back to 0 locks on the COM library, make sure we free
1101 * all the associated data structures.
1103 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1106 TRACE("() - Releasing the COM libraries\n");
1108 RunningObjectTableImpl_UnInitialize();
1110 else if (lCOMRefCnt<1) {
1111 ERR( "CoUninitialize() - not CoInitialized.\n" );
1112 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1116 /******************************************************************************
1117 * CoDisconnectObject [OLE32.@]
1119 * Disconnects all connections to this object from remote processes. Dispatches
1120 * pending RPCs while blocking new RPCs from occurring, and then calls
1121 * IMarshal::DisconnectObject on the given object.
1123 * Typically called when the object server is forced to shut down, for instance by
1127 * lpUnk [I] The object whose stub should be disconnected.
1128 * reserved [I] Reserved. Should be set to 0.
1132 * Failure: HRESULT code.
1135 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1137 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1143 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1145 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1148 hr = IMarshal_DisconnectObject(marshal, reserved);
1149 IMarshal_Release(marshal);
1153 apt = COM_CurrentApt();
1155 return CO_E_NOTINITIALIZED;
1157 apartment_disconnectobject(apt, lpUnk);
1159 /* Note: native is pretty broken here because it just silently
1160 * fails, without returning an appropriate error code if the object was
1161 * not found, making apps think that the object was disconnected, when
1162 * it actually wasn't */
1167 /******************************************************************************
1168 * CoCreateGuid [OLE32.@]
1170 * Simply forwards to UuidCreate in RPCRT4.
1173 * pguid [O] Points to the GUID to initialize.
1177 * Failure: HRESULT code.
1182 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1184 return UuidCreate(pguid);
1187 /******************************************************************************
1188 * CLSIDFromString [OLE32.@]
1189 * IIDFromString [OLE32.@]
1191 * Converts a unique identifier from its string representation into
1195 * idstr [I] The string representation of the GUID.
1196 * id [O] GUID converted from the string.
1200 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1205 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
1211 memset( id, 0, sizeof (CLSID) );
1215 /* validate the CLSID string */
1216 if (strlenW(s) != 38)
1217 return CO_E_CLASSSTRING;
1219 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1220 return CO_E_CLASSSTRING;
1222 for (i=1; i<37; i++) {
1223 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1224 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1225 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1226 ((s[i] >= 'A') && (s[i] <= 'F'))))
1227 return CO_E_CLASSSTRING;
1230 TRACE("%s -> %p\n", debugstr_w(s), id);
1232 /* quick lookup table */
1233 memset(table, 0, 256);
1235 for (i = 0; i < 10; i++) {
1238 for (i = 0; i < 6; i++) {
1239 table['A' + i] = i+10;
1240 table['a' + i] = i+10;
1243 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1245 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1246 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1247 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1248 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1250 /* these are just sequential bytes */
1251 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1252 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1253 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1254 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1255 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1256 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1257 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1258 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1263 /*****************************************************************************/
1265 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1270 return E_INVALIDARG;
1272 ret = __CLSIDFromString(idstr, id);
1273 if(ret != S_OK) { /* It appears a ProgID is also valid */
1274 ret = CLSIDFromProgID(idstr, id);
1279 /* Converts a GUID into the respective string representation. */
1280 HRESULT WINE_StringFromCLSID(
1281 const CLSID *id, /* [in] GUID to be converted */
1282 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1284 static const char hex[] = "0123456789ABCDEF";
1289 { ERR("called with id=Null\n");
1294 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1295 id->Data1, id->Data2, id->Data3,
1296 id->Data4[0], id->Data4[1]);
1300 for (i = 2; i < 8; i++) {
1301 *s++ = hex[id->Data4[i]>>4];
1302 *s++ = hex[id->Data4[i] & 0xf];
1308 TRACE("%p->%s\n", id, idstr);
1314 /******************************************************************************
1315 * StringFromCLSID [OLE32.@]
1316 * StringFromIID [OLE32.@]
1318 * Converts a GUID into the respective string representation.
1319 * The target string is allocated using the OLE IMalloc.
1322 * id [I] the GUID to be converted.
1323 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1330 * StringFromGUID2, CLSIDFromString
1332 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1338 if ((ret = CoGetMalloc(0,&mllc)))
1341 ret=WINE_StringFromCLSID(id,buf);
1343 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1344 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1345 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1350 /******************************************************************************
1351 * StringFromGUID2 [OLE32.@]
1352 * StringFromGUID2 [COMPOBJ.76]
1354 * Modified version of StringFromCLSID that allows you to specify max
1358 * id [I] GUID to convert to string.
1359 * str [O] Buffer where the result will be stored.
1360 * cmax [I] Size of the buffer in characters.
1363 * Success: The length of the resulting string in characters.
1366 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1370 if (WINE_StringFromCLSID(id,xguid))
1372 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1375 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1376 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1378 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1379 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1383 strcpyW(path, wszCLSIDSlash);
1384 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1385 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1386 if (res == ERROR_FILE_NOT_FOUND)
1387 return REGDB_E_CLASSNOTREG;
1388 else if (res != ERROR_SUCCESS)
1389 return REGDB_E_READREGDB;
1397 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1399 if (res == ERROR_FILE_NOT_FOUND)
1400 return REGDB_E_KEYMISSING;
1401 else if (res != ERROR_SUCCESS)
1402 return REGDB_E_READREGDB;
1407 /* open HKCR\\AppId\\{string form of appid clsid} key */
1408 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1410 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1411 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1413 WCHAR buf[CHARS_IN_GUID];
1414 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1420 /* read the AppID value under the class's key */
1421 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1426 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1428 if (res == ERROR_FILE_NOT_FOUND)
1429 return REGDB_E_KEYMISSING;
1430 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1431 return REGDB_E_READREGDB;
1433 strcpyW(keyname, szAppIdKey);
1434 strcatW(keyname, buf);
1435 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1436 if (res == ERROR_FILE_NOT_FOUND)
1437 return REGDB_E_KEYMISSING;
1438 else if (res != ERROR_SUCCESS)
1439 return REGDB_E_READREGDB;
1444 /******************************************************************************
1445 * ProgIDFromCLSID [OLE32.@]
1447 * Converts a class id into the respective program ID.
1450 * clsid [I] Class ID, as found in registry.
1451 * ppszProgID [O] Associated ProgID.
1456 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1458 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1460 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1467 ERR("ppszProgId isn't optional\n");
1468 return E_INVALIDARG;
1472 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1476 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1477 ret = REGDB_E_CLASSNOTREG;
1481 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1484 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1485 ret = REGDB_E_CLASSNOTREG;
1488 ret = E_OUTOFMEMORY;
1495 /******************************************************************************
1496 * CLSIDFromProgID [OLE32.@]
1498 * Converts a program id into the respective GUID.
1501 * progid [I] Unicode program ID, as found in registry.
1502 * clsid [O] Associated CLSID.
1506 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1508 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1510 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1511 WCHAR buf2[CHARS_IN_GUID];
1512 LONG buf2len = sizeof(buf2);
1516 if (!progid || !clsid)
1518 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1519 return E_INVALIDARG;
1522 /* initialise clsid in case of failure */
1523 memset(clsid, 0, sizeof(*clsid));
1525 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1526 strcpyW( buf, progid );
1527 strcatW( buf, clsidW );
1528 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1530 HeapFree(GetProcessHeap(),0,buf);
1531 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1532 return CO_E_CLASSSTRING;
1534 HeapFree(GetProcessHeap(),0,buf);
1536 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1539 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1540 return CO_E_CLASSSTRING;
1543 return CLSIDFromString(buf2,clsid);
1547 /*****************************************************************************
1548 * CoGetPSClsid [OLE32.@]
1550 * Retrieves the CLSID of the proxy/stub factory that implements
1551 * IPSFactoryBuffer for the specified interface.
1554 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1555 * pclsid [O] Where to store returned proxy/stub CLSID.
1560 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1564 * The standard marshaller activates the object with the CLSID
1565 * returned and uses the CreateProxy and CreateStub methods on its
1566 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1569 * CoGetPSClsid determines this CLSID by searching the
1570 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1571 * in the registry and any interface id registered by
1572 * CoRegisterPSClsid within the current process.
1576 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1577 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1578 * considered a bug in native unless an application depends on this (unlikely).
1581 * CoRegisterPSClsid.
1583 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1585 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1586 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1587 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1588 WCHAR value[CHARS_IN_GUID];
1591 APARTMENT *apt = COM_CurrentApt();
1592 struct registered_psclsid *registered_psclsid;
1594 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1598 ERR("apartment not initialised\n");
1599 return CO_E_NOTINITIALIZED;
1604 ERR("pclsid isn't optional\n");
1605 return E_INVALIDARG;
1608 EnterCriticalSection(&apt->cs);
1610 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1611 if (IsEqualIID(®istered_psclsid->iid, riid))
1613 *pclsid = registered_psclsid->clsid;
1614 LeaveCriticalSection(&apt->cs);
1618 LeaveCriticalSection(&apt->cs);
1620 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1621 strcpyW(path, wszInterface);
1622 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1623 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1625 /* Open the key.. */
1626 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1628 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1629 return REGDB_E_IIDNOTREG;
1632 /* ... Once we have the key, query the registry to get the
1633 value of CLSID as a string, and convert it into a
1634 proper CLSID structure to be passed back to the app */
1635 len = sizeof(value);
1636 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1639 return REGDB_E_IIDNOTREG;
1643 /* We have the CLSid we want back from the registry as a string, so
1644 lets convert it into a CLSID structure */
1645 if (CLSIDFromString(value, pclsid) != NOERROR)
1646 return REGDB_E_IIDNOTREG;
1648 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1652 /*****************************************************************************
1653 * CoRegisterPSClsid [OLE32.@]
1655 * Register a proxy/stub CLSID for the given interface in the current process
1659 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1660 * rclsid [I] CLSID of the proxy/stub.
1664 * Failure: E_OUTOFMEMORY
1668 * This function does not add anything to the registry and the effects are
1669 * limited to the lifetime of the current process.
1674 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1676 APARTMENT *apt = COM_CurrentApt();
1677 struct registered_psclsid *registered_psclsid;
1679 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1683 ERR("apartment not initialised\n");
1684 return CO_E_NOTINITIALIZED;
1687 EnterCriticalSection(&apt->cs);
1689 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1690 if (IsEqualIID(®istered_psclsid->iid, riid))
1692 registered_psclsid->clsid = *rclsid;
1693 LeaveCriticalSection(&apt->cs);
1697 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1698 if (!registered_psclsid)
1700 LeaveCriticalSection(&apt->cs);
1701 return E_OUTOFMEMORY;
1704 registered_psclsid->iid = *riid;
1705 registered_psclsid->clsid = *rclsid;
1706 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1708 LeaveCriticalSection(&apt->cs);
1715 * COM_GetRegisteredClassObject
1717 * This internal method is used to scan the registered class list to
1718 * find a class object.
1721 * rclsid Class ID of the class to find.
1722 * dwClsContext Class context to match.
1723 * ppv [out] returns a pointer to the class object. Complying
1724 * to normal COM usage, this method will increase the
1725 * reference count on this object.
1727 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1728 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1730 HRESULT hr = S_FALSE;
1731 RegisteredClass *curClass;
1738 EnterCriticalSection( &csRegisteredClassList );
1740 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1743 * Check if we have a match on the class ID and context.
1745 if ((apt->oxid == curClass->apartment_id) &&
1746 (dwClsContext & curClass->runContext) &&
1747 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1750 * We have a match, return the pointer to the class object.
1752 *ppUnk = curClass->classObject;
1754 IUnknown_AddRef(curClass->classObject);
1761 LeaveCriticalSection( &csRegisteredClassList );
1766 /******************************************************************************
1767 * CoRegisterClassObject [OLE32.@]
1769 * Registers the class object for a given class ID. Servers housed in EXE
1770 * files use this method instead of exporting DllGetClassObject to allow
1771 * other code to connect to their objects.
1774 * rclsid [I] CLSID of the object to register.
1775 * pUnk [I] IUnknown of the object.
1776 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1777 * flags [I] REGCLS flags indicating how connections are made.
1778 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1782 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1783 * CO_E_OBJISREG if the object is already registered. We should not return this.
1786 * CoRevokeClassObject, CoGetClassObject
1789 * In-process objects are only registered for the current apartment.
1790 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1791 * in other apartments.
1794 * MSDN claims that multiple interface registrations are legal, but we
1795 * can't do that with our current implementation.
1797 HRESULT WINAPI CoRegisterClassObject(
1802 LPDWORD lpdwRegister)
1804 RegisteredClass* newClass;
1805 LPUNKNOWN foundObject;
1809 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1810 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1812 if ( (lpdwRegister==0) || (pUnk==0) )
1813 return E_INVALIDARG;
1815 apt = COM_CurrentApt();
1818 ERR("COM was not initialized\n");
1819 return CO_E_NOTINITIALIZED;
1824 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1825 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1826 if (flags & REGCLS_MULTIPLEUSE)
1827 dwClsContext |= CLSCTX_INPROC_SERVER;
1830 * First, check if the class is already registered.
1831 * If it is, this should cause an error.
1833 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1835 if (flags & REGCLS_MULTIPLEUSE) {
1836 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1837 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1838 IUnknown_Release(foundObject);
1841 IUnknown_Release(foundObject);
1842 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1843 return CO_E_OBJISREG;
1846 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1847 if ( newClass == NULL )
1848 return E_OUTOFMEMORY;
1850 newClass->classIdentifier = *rclsid;
1851 newClass->apartment_id = apt->oxid;
1852 newClass->runContext = dwClsContext;
1853 newClass->connectFlags = flags;
1854 newClass->pMarshaledData = NULL;
1855 newClass->RpcRegistration = NULL;
1858 * Use the address of the chain node as the cookie since we are sure it's
1859 * unique. FIXME: not on 64-bit platforms.
1861 newClass->dwCookie = (DWORD)newClass;
1864 * Since we're making a copy of the object pointer, we have to increase its
1867 newClass->classObject = pUnk;
1868 IUnknown_AddRef(newClass->classObject);
1870 EnterCriticalSection( &csRegisteredClassList );
1871 list_add_tail(&RegisteredClassList, &newClass->entry);
1872 LeaveCriticalSection( &csRegisteredClassList );
1874 *lpdwRegister = newClass->dwCookie;
1876 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1877 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1879 FIXME("Failed to create stream on hglobal, %x\n", hr);
1882 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1883 newClass->classObject, MSHCTX_LOCAL, NULL,
1884 MSHLFLAGS_TABLESTRONG);
1886 FIXME("CoMarshalInterface failed, %x!\n",hr);
1890 hr = RPC_StartLocalServer(&newClass->classIdentifier,
1891 newClass->pMarshaledData,
1892 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
1893 &newClass->RpcRegistration);
1898 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
1900 list_remove(&curClass->entry);
1902 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
1903 RPC_StopLocalServer(curClass->RpcRegistration);
1906 * Release the reference to the class object.
1908 IUnknown_Release(curClass->classObject);
1910 if (curClass->pMarshaledData)
1913 memset(&zero, 0, sizeof(zero));
1914 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
1915 CoReleaseMarshalData(curClass->pMarshaledData);
1918 HeapFree(GetProcessHeap(), 0, curClass);
1921 static void COM_RevokeAllClasses(const struct apartment *apt)
1923 RegisteredClass *curClass, *cursor;
1925 EnterCriticalSection( &csRegisteredClassList );
1927 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
1929 if (curClass->apartment_id == apt->oxid)
1930 COM_RevokeRegisteredClassObject(curClass);
1933 LeaveCriticalSection( &csRegisteredClassList );
1936 /***********************************************************************
1937 * CoRevokeClassObject [OLE32.@]
1939 * Removes a class object from the class registry.
1942 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1946 * Failure: HRESULT code.
1949 * Must be called from the same apartment that called CoRegisterClassObject(),
1950 * otherwise it will fail with RPC_E_WRONG_THREAD.
1953 * CoRegisterClassObject
1955 HRESULT WINAPI CoRevokeClassObject(
1958 HRESULT hr = E_INVALIDARG;
1959 RegisteredClass *curClass;
1962 TRACE("(%08x)\n",dwRegister);
1964 apt = COM_CurrentApt();
1967 ERR("COM was not initialized\n");
1968 return CO_E_NOTINITIALIZED;
1971 EnterCriticalSection( &csRegisteredClassList );
1973 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1976 * Check if we have a match on the cookie.
1978 if (curClass->dwCookie == dwRegister)
1980 if (curClass->apartment_id == apt->oxid)
1982 COM_RevokeRegisteredClassObject(curClass);
1987 ERR("called from wrong apartment, should be called from %s\n",
1988 wine_dbgstr_longlong(curClass->apartment_id));
1989 hr = RPC_E_WRONG_THREAD;
1995 LeaveCriticalSection( &csRegisteredClassList );
2000 /***********************************************************************
2001 * COM_RegReadPath [internal]
2003 * Reads a registry value and expands it when necessary
2005 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2010 WCHAR src[MAX_PATH];
2011 DWORD dwLength = dstlen * sizeof(WCHAR);
2013 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
2014 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2015 if (keytype == REG_EXPAND_SZ) {
2016 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2018 lstrcpynW(dst, src, dstlen);
2026 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2028 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2031 DWORD dwLength = len * sizeof(WCHAR);
2033 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2034 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2038 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2039 REFCLSID rclsid, REFIID riid, void **ppv)
2041 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2042 static const WCHAR wszFree[] = {'F','r','e','e',0};
2043 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2044 WCHAR dllpath[MAX_PATH+1];
2045 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2047 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2049 if (!strcmpiW(threading_model, wszApartment))
2051 if (apt->multi_threaded)
2052 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2055 else if (!strcmpiW(threading_model, wszFree))
2057 if (!apt->multi_threaded)
2058 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2060 /* everything except "Apartment", "Free" and "Both" */
2061 else if (strcmpiW(threading_model, wszBoth))
2063 /* everything else is main-threaded */
2064 if (threading_model[0])
2065 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2066 debugstr_w(threading_model), debugstr_guid(rclsid));
2068 if (apt->multi_threaded || !apt->main)
2069 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2072 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2074 /* failure: CLSID is not found in registry */
2075 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2076 return REGDB_E_CLASSNOTREG;
2079 return apartment_getclassobject(apt, dllpath, rclsid, riid, ppv);
2082 /***********************************************************************
2083 * CoGetClassObject [OLE32.@]
2085 * Creates an object of the specified class.
2088 * rclsid [I] Class ID to create an instance of.
2089 * dwClsContext [I] Flags to restrict the location of the created instance.
2090 * pServerInfo [I] Optional. Details for connecting to a remote server.
2091 * iid [I] The ID of the interface of the instance to return.
2092 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2096 * Failure: HRESULT code.
2099 * The dwClsContext parameter can be one or more of the following:
2100 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2101 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2102 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2103 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2106 * CoCreateInstance()
2108 HRESULT WINAPI CoGetClassObject(
2109 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2110 REFIID iid, LPVOID *ppv)
2112 LPUNKNOWN regClassObject;
2113 HRESULT hres = E_UNEXPECTED;
2116 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2119 return E_INVALIDARG;
2123 apt = COM_CurrentApt();
2126 ERR("apartment not initialised\n");
2127 return CO_E_NOTINITIALIZED;
2131 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2132 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2136 * First, try and see if we can't match the class ID with one of the
2137 * registered classes.
2139 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2142 /* Get the required interface from the retrieved pointer. */
2143 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2146 * Since QI got another reference on the pointer, we want to release the
2147 * one we already have. If QI was unsuccessful, this will release the object. This
2148 * is good since we are not returning it in the "out" parameter.
2150 IUnknown_Release(regClassObject);
2155 /* First try in-process server */
2156 if (CLSCTX_INPROC_SERVER & dwClsContext)
2158 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2161 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2162 return FTMarshalCF_Create(iid, ppv);
2164 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2167 if (hres == REGDB_E_CLASSNOTREG)
2168 ERR("class %s not registered\n", debugstr_guid(rclsid));
2169 else if (hres == REGDB_E_KEYMISSING)
2171 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2172 hres = REGDB_E_CLASSNOTREG;
2176 if (SUCCEEDED(hres))
2178 hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
2182 /* return if we got a class, otherwise fall through to one of the
2184 if (SUCCEEDED(hres))
2188 /* Next try in-process handler */
2189 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2191 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2194 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2197 if (hres == REGDB_E_CLASSNOTREG)
2198 ERR("class %s not registered\n", debugstr_guid(rclsid));
2199 else if (hres == REGDB_E_KEYMISSING)
2201 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2202 hres = REGDB_E_CLASSNOTREG;
2206 if (SUCCEEDED(hres))
2208 hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
2212 /* return if we got a class, otherwise fall through to one of the
2214 if (SUCCEEDED(hres))
2218 /* Next try out of process */
2219 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2221 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2222 if (SUCCEEDED(hres))
2226 /* Finally try remote: this requires networked DCOM (a lot of work) */
2227 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2229 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2230 hres = E_NOINTERFACE;
2234 ERR("no class object %s could be created for context 0x%x\n",
2235 debugstr_guid(rclsid), dwClsContext);
2239 /***********************************************************************
2240 * CoResumeClassObjects (OLE32.@)
2242 * Resumes all class objects registered with REGCLS_SUSPENDED.
2246 * Failure: HRESULT code.
2248 HRESULT WINAPI CoResumeClassObjects(void)
2254 /***********************************************************************
2255 * CoCreateInstance [OLE32.@]
2257 * Creates an instance of the specified class.
2260 * rclsid [I] Class ID to create an instance of.
2261 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2262 * dwClsContext [I] Flags to restrict the location of the created instance.
2263 * iid [I] The ID of the interface of the instance to return.
2264 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2268 * Failure: HRESULT code.
2271 * The dwClsContext parameter can be one or more of the following:
2272 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2273 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2274 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2275 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2277 * Aggregation is the concept of deferring the IUnknown of an object to another
2278 * object. This allows a separate object to behave as though it was part of
2279 * the object and to allow this the pUnkOuter parameter can be set. Note that
2280 * not all objects support having an outer of unknown.
2283 * CoGetClassObject()
2285 HRESULT WINAPI CoCreateInstance(
2287 LPUNKNOWN pUnkOuter,
2293 LPCLASSFACTORY lpclf = 0;
2295 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2296 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2305 * Initialize the "out" parameter
2309 if (!COM_CurrentApt())
2311 ERR("apartment not initialised\n");
2312 return CO_E_NOTINITIALIZED;
2316 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2317 * Rather than create a class factory, we can just check for it here
2319 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2320 if (StdGlobalInterfaceTableInstance == NULL)
2321 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2322 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2323 if (hres) return hres;
2325 TRACE("Retrieved GIT (%p)\n", *ppv);
2330 * Get a class factory to construct the object we want.
2332 hres = CoGetClassObject(rclsid,
2342 * Create the object and don't forget to release the factory
2344 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2345 IClassFactory_Release(lpclf);
2347 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2348 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2353 /***********************************************************************
2354 * CoCreateInstanceEx [OLE32.@]
2356 HRESULT WINAPI CoCreateInstanceEx(
2358 LPUNKNOWN pUnkOuter,
2360 COSERVERINFO* pServerInfo,
2364 IUnknown* pUnk = NULL;
2367 ULONG successCount = 0;
2372 if ( (cmq==0) || (pResults==NULL))
2373 return E_INVALIDARG;
2375 if (pServerInfo!=NULL)
2376 FIXME("() non-NULL pServerInfo not supported!\n");
2379 * Initialize all the "out" parameters.
2381 for (index = 0; index < cmq; index++)
2383 pResults[index].pItf = NULL;
2384 pResults[index].hr = E_NOINTERFACE;
2388 * Get the object and get its IUnknown pointer.
2390 hr = CoCreateInstance(rclsid,
2400 * Then, query for all the interfaces requested.
2402 for (index = 0; index < cmq; index++)
2404 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2405 pResults[index].pIID,
2406 (VOID**)&(pResults[index].pItf));
2408 if (pResults[index].hr == S_OK)
2413 * Release our temporary unknown pointer.
2415 IUnknown_Release(pUnk);
2417 if (successCount == 0)
2418 return E_NOINTERFACE;
2420 if (successCount!=cmq)
2421 return CO_S_NOTALLINTERFACES;
2426 /***********************************************************************
2427 * CoLoadLibrary (OLE32.@)
2432 * lpszLibName [I] Path to library.
2433 * bAutoFree [I] Whether the library should automatically be freed.
2436 * Success: Handle to loaded library.
2440 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2442 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2444 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2446 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2449 /***********************************************************************
2450 * CoFreeLibrary [OLE32.@]
2452 * Unloads a library from memory.
2455 * hLibrary [I] Handle to library to unload.
2461 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2463 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2465 FreeLibrary(hLibrary);
2469 /***********************************************************************
2470 * CoFreeAllLibraries [OLE32.@]
2472 * Function for backwards compatibility only. Does nothing.
2478 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2480 void WINAPI CoFreeAllLibraries(void)
2486 /***********************************************************************
2487 * CoFreeUnusedLibraries [OLE32.@]
2488 * CoFreeUnusedLibraries [COMPOBJ.17]
2490 * Frees any unused libraries. Unused are identified as those that return
2491 * S_OK from their DllCanUnloadNow function.
2497 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2499 void WINAPI CoFreeUnusedLibraries(void)
2501 struct apartment *apt = COM_CurrentApt();
2504 ERR("apartment not initialised\n");
2508 apartment_freeunusedlibraries(apt);
2511 /***********************************************************************
2512 * CoFileTimeNow [OLE32.@]
2513 * CoFileTimeNow [COMPOBJ.82]
2515 * Retrieves the current time in FILETIME format.
2518 * lpFileTime [O] The current time.
2523 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2525 GetSystemTimeAsFileTime( lpFileTime );
2529 /******************************************************************************
2530 * CoLockObjectExternal [OLE32.@]
2532 * Increments or decrements the external reference count of a stub object.
2535 * pUnk [I] Stub object.
2536 * fLock [I] If TRUE then increments the external ref-count,
2537 * otherwise decrements.
2538 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2539 * calling CoDisconnectObject.
2543 * Failure: HRESULT code.
2546 * If fLock is TRUE and an object is passed in that doesn't have a stub
2547 * manager then a new stub manager is created for the object.
2549 HRESULT WINAPI CoLockObjectExternal(
2552 BOOL fLastUnlockReleases)
2554 struct stub_manager *stubmgr;
2555 struct apartment *apt;
2557 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2558 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2560 apt = COM_CurrentApt();
2561 if (!apt) return CO_E_NOTINITIALIZED;
2563 stubmgr = get_stub_manager_from_object(apt, pUnk);
2568 stub_manager_ext_addref(stubmgr, 1);
2570 stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
2572 stub_manager_int_release(stubmgr);
2578 stubmgr = new_stub_manager(apt, pUnk);
2582 stub_manager_ext_addref(stubmgr, 1);
2583 stub_manager_int_release(stubmgr);
2590 WARN("stub object not found %p\n", pUnk);
2591 /* Note: native is pretty broken here because it just silently
2592 * fails, without returning an appropriate error code, making apps
2593 * think that the object was disconnected, when it actually wasn't */
2598 /***********************************************************************
2599 * CoInitializeWOW (OLE32.@)
2601 * WOW equivalent of CoInitialize?
2610 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2612 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2616 /***********************************************************************
2617 * CoGetState [OLE32.@]
2619 * Retrieves the thread state object previously stored by CoSetState().
2622 * ppv [I] Address where pointer to object will be stored.
2626 * Failure: E_OUTOFMEMORY.
2629 * Crashes on all invalid ppv addresses, including NULL.
2630 * If the function returns a non-NULL object then the caller must release its
2631 * reference on the object when the object is no longer required.
2636 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2638 struct oletls *info = COM_CurrentInfo();
2639 if (!info) return E_OUTOFMEMORY;
2645 IUnknown_AddRef(info->state);
2647 TRACE("apt->state=%p\n", info->state);
2653 /***********************************************************************
2654 * CoSetState [OLE32.@]
2656 * Sets the thread state object.
2659 * pv [I] Pointer to state object to be stored.
2662 * The system keeps a reference on the object while the object stored.
2666 * Failure: E_OUTOFMEMORY.
2668 HRESULT WINAPI CoSetState(IUnknown * pv)
2670 struct oletls *info = COM_CurrentInfo();
2671 if (!info) return E_OUTOFMEMORY;
2673 if (pv) IUnknown_AddRef(pv);
2677 TRACE("-- release %p now\n", info->state);
2678 IUnknown_Release(info->state);
2687 /******************************************************************************
2688 * CoTreatAsClass [OLE32.@]
2690 * Sets the TreatAs value of a class.
2693 * clsidOld [I] Class to set TreatAs value on.
2694 * clsidNew [I] The class the clsidOld should be treated as.
2698 * Failure: HRESULT code.
2703 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2705 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2706 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2708 WCHAR szClsidNew[CHARS_IN_GUID];
2710 WCHAR auto_treat_as[CHARS_IN_GUID];
2711 LONG auto_treat_as_size = sizeof(auto_treat_as);
2714 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2717 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2719 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2720 !CLSIDFromString(auto_treat_as, &id))
2722 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2724 res = REGDB_E_WRITEREGDB;
2730 RegDeleteKeyW(hkey, wszTreatAs);
2734 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2735 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2737 res = REGDB_E_WRITEREGDB;
2742 if (hkey) RegCloseKey(hkey);
2746 /******************************************************************************
2747 * CoGetTreatAsClass [OLE32.@]
2749 * Gets the TreatAs value of a class.
2752 * clsidOld [I] Class to get the TreatAs value of.
2753 * clsidNew [I] The class the clsidOld should be treated as.
2757 * Failure: HRESULT code.
2762 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2764 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2766 WCHAR szClsidNew[CHARS_IN_GUID];
2768 LONG len = sizeof(szClsidNew);
2770 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2771 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2773 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2776 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2781 res = CLSIDFromString(szClsidNew,clsidNew);
2783 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2785 if (hkey) RegCloseKey(hkey);
2789 /******************************************************************************
2790 * CoGetCurrentProcess [OLE32.@]
2791 * CoGetCurrentProcess [COMPOBJ.34]
2793 * Gets the current process ID.
2796 * The current process ID.
2799 * Is DWORD really the correct return type for this function?
2801 DWORD WINAPI CoGetCurrentProcess(void)
2803 return GetCurrentProcessId();
2806 /******************************************************************************
2807 * CoRegisterMessageFilter [OLE32.@]
2809 * Registers a message filter.
2812 * lpMessageFilter [I] Pointer to interface.
2813 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2817 * Failure: HRESULT code.
2820 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2821 * lpMessageFilter removes the message filter.
2823 * If lplpMessageFilter is not NULL the previous message filter will be
2824 * returned in the memory pointer to this parameter and the caller is
2825 * responsible for releasing the object.
2827 * The current thread be in an apartment otherwise the function will crash.
2829 HRESULT WINAPI CoRegisterMessageFilter(
2830 LPMESSAGEFILTER lpMessageFilter,
2831 LPMESSAGEFILTER *lplpMessageFilter)
2833 struct apartment *apt;
2834 IMessageFilter *lpOldMessageFilter;
2836 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2838 apt = COM_CurrentApt();
2840 /* can't set a message filter in a multi-threaded apartment */
2841 if (!apt || apt->multi_threaded)
2843 WARN("can't set message filter in MTA or uninitialized apt\n");
2844 return CO_E_NOT_SUPPORTED;
2847 if (lpMessageFilter)
2848 IMessageFilter_AddRef(lpMessageFilter);
2850 EnterCriticalSection(&apt->cs);
2852 lpOldMessageFilter = apt->filter;
2853 apt->filter = lpMessageFilter;
2855 LeaveCriticalSection(&apt->cs);
2857 if (lplpMessageFilter)
2858 *lplpMessageFilter = lpOldMessageFilter;
2859 else if (lpOldMessageFilter)
2860 IMessageFilter_Release(lpOldMessageFilter);
2865 /***********************************************************************
2866 * CoIsOle1Class [OLE32.@]
2868 * Determines whether the specified class an OLE v1 class.
2871 * clsid [I] Class to test.
2874 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2876 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2878 FIXME("%s\n", debugstr_guid(clsid));
2882 /***********************************************************************
2883 * IsEqualGUID [OLE32.@]
2885 * Compares two Unique Identifiers.
2888 * rguid1 [I] The first GUID to compare.
2889 * rguid2 [I] The other GUID to compare.
2895 BOOL WINAPI IsEqualGUID(
2899 return !memcmp(rguid1,rguid2,sizeof(GUID));
2902 /***********************************************************************
2903 * CoInitializeSecurity [OLE32.@]
2905 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2906 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2907 void* pReserved1, DWORD dwAuthnLevel,
2908 DWORD dwImpLevel, void* pReserved2,
2909 DWORD dwCapabilities, void* pReserved3)
2911 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
2912 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2913 dwCapabilities, pReserved3);
2917 /***********************************************************************
2918 * CoSuspendClassObjects [OLE32.@]
2920 * Suspends all registered class objects to prevent further requests coming in
2921 * for those objects.
2925 * Failure: HRESULT code.
2927 HRESULT WINAPI CoSuspendClassObjects(void)
2933 /***********************************************************************
2934 * CoAddRefServerProcess [OLE32.@]
2936 * Helper function for incrementing the reference count of a local-server
2940 * New reference count.
2943 * CoReleaseServerProcess().
2945 ULONG WINAPI CoAddRefServerProcess(void)
2951 EnterCriticalSection(&csRegisteredClassList);
2952 refs = ++s_COMServerProcessReferences;
2953 LeaveCriticalSection(&csRegisteredClassList);
2955 TRACE("refs before: %d\n", refs - 1);
2960 /***********************************************************************
2961 * CoReleaseServerProcess [OLE32.@]
2963 * Helper function for decrementing the reference count of a local-server
2967 * New reference count.
2970 * When reference count reaches 0, this function suspends all registered
2971 * classes so no new connections are accepted.
2974 * CoAddRefServerProcess(), CoSuspendClassObjects().
2976 ULONG WINAPI CoReleaseServerProcess(void)
2982 EnterCriticalSection(&csRegisteredClassList);
2984 refs = --s_COMServerProcessReferences;
2985 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
2987 LeaveCriticalSection(&csRegisteredClassList);
2989 TRACE("refs after: %d\n", refs);
2994 /***********************************************************************
2995 * CoIsHandlerConnected [OLE32.@]
2997 * Determines whether a proxy is connected to a remote stub.
3000 * pUnk [I] Pointer to object that may or may not be connected.
3003 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3006 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3008 FIXME("%p\n", pUnk);
3013 /***********************************************************************
3014 * CoAllowSetForegroundWindow [OLE32.@]
3017 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3019 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3023 /***********************************************************************
3024 * CoQueryProxyBlanket [OLE32.@]
3026 * Retrieves the security settings being used by a proxy.
3029 * pProxy [I] Pointer to the proxy object.
3030 * pAuthnSvc [O] The type of authentication service.
3031 * pAuthzSvc [O] The type of authorization service.
3032 * ppServerPrincName [O] Optional. The server prinicple name.
3033 * pAuthnLevel [O] The authentication level.
3034 * pImpLevel [O] The impersonation level.
3035 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3036 * pCapabilities [O] Flags affecting the security behaviour.
3040 * Failure: HRESULT code.
3043 * CoCopyProxy, CoSetProxyBlanket.
3045 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3046 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3047 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3049 IClientSecurity *pCliSec;
3052 TRACE("%p\n", pProxy);
3054 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3057 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3058 pAuthzSvc, ppServerPrincName,
3059 pAuthnLevel, pImpLevel, ppAuthInfo,
3061 IClientSecurity_Release(pCliSec);
3064 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3068 /***********************************************************************
3069 * CoSetProxyBlanket [OLE32.@]
3071 * Sets the security settings for a proxy.
3074 * pProxy [I] Pointer to the proxy object.
3075 * AuthnSvc [I] The type of authentication service.
3076 * AuthzSvc [I] The type of authorization service.
3077 * pServerPrincName [I] The server prinicple name.
3078 * AuthnLevel [I] The authentication level.
3079 * ImpLevel [I] The impersonation level.
3080 * pAuthInfo [I] Information specific to the authorization/authentication service.
3081 * Capabilities [I] Flags affecting the security behaviour.
3085 * Failure: HRESULT code.
3088 * CoQueryProxyBlanket, CoCopyProxy.
3090 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3091 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3092 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3094 IClientSecurity *pCliSec;
3097 TRACE("%p\n", pProxy);
3099 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3102 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3103 AuthzSvc, pServerPrincName,
3104 AuthnLevel, ImpLevel, pAuthInfo,
3106 IClientSecurity_Release(pCliSec);
3109 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3113 /***********************************************************************
3114 * CoCopyProxy [OLE32.@]
3119 * pProxy [I] Pointer to the proxy object.
3120 * ppCopy [O] Copy of the proxy.
3124 * Failure: HRESULT code.
3127 * CoQueryProxyBlanket, CoSetProxyBlanket.
3129 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3131 IClientSecurity *pCliSec;
3134 TRACE("%p\n", pProxy);
3136 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3139 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3140 IClientSecurity_Release(pCliSec);
3143 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3148 /***********************************************************************
3149 * CoGetCallContext [OLE32.@]
3151 * Gets the context of the currently executing server call in the current
3155 * riid [I] Context interface to return.
3156 * ppv [O] Pointer to memory that will receive the context on return.
3160 * Failure: HRESULT code.
3162 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3164 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
3167 return E_NOINTERFACE;
3170 /***********************************************************************
3171 * CoQueryClientBlanket [OLE32.@]
3173 * Retrieves the authentication information about the client of the currently
3174 * executing server call in the current thread.
3177 * pAuthnSvc [O] Optional. The type of authentication service.
3178 * pAuthzSvc [O] Optional. The type of authorization service.
3179 * pServerPrincName [O] Optional. The server prinicple name.
3180 * pAuthnLevel [O] Optional. The authentication level.
3181 * pImpLevel [O] Optional. The impersonation level.
3182 * pPrivs [O] Optional. Information about the privileges of the client.
3183 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3187 * Failure: HRESULT code.
3190 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3192 HRESULT WINAPI CoQueryClientBlanket(
3195 OLECHAR **pServerPrincName,
3198 RPC_AUTHZ_HANDLE *pPrivs,
3199 DWORD *pCapabilities)
3201 IServerSecurity *pSrvSec;
3204 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3205 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3206 pPrivs, pCapabilities);
3208 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3211 hr = IServerSecurity_QueryBlanket(
3212 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3213 pImpLevel, pPrivs, pCapabilities);
3214 IServerSecurity_Release(pSrvSec);
3220 /***********************************************************************
3221 * CoImpersonateClient [OLE32.@]
3223 * Impersonates the client of the currently executing server call in the
3231 * Failure: HRESULT code.
3234 * If this function fails then the current thread will not be impersonating
3235 * the client and all actions will take place on behalf of the server.
3236 * Therefore, it is important to check the return value from this function.
3239 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3241 HRESULT WINAPI CoImpersonateClient(void)
3243 IServerSecurity *pSrvSec;
3248 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3251 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3252 IServerSecurity_Release(pSrvSec);
3258 /***********************************************************************
3259 * CoRevertToSelf [OLE32.@]
3261 * Ends the impersonation of the client of the currently executing server
3262 * call in the current thread.
3269 * Failure: HRESULT code.
3272 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3274 HRESULT WINAPI CoRevertToSelf(void)
3276 IServerSecurity *pSrvSec;
3281 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3284 hr = IServerSecurity_RevertToSelf(pSrvSec);
3285 IServerSecurity_Release(pSrvSec);
3291 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3293 /* first try to retrieve messages for incoming COM calls to the apartment window */
3294 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3295 /* next retrieve other messages necessary for the app to remain responsive */
3296 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3299 /***********************************************************************
3300 * CoWaitForMultipleHandles [OLE32.@]
3302 * Waits for one or more handles to become signaled.
3305 * dwFlags [I] Flags. See notes.
3306 * dwTimeout [I] Timeout in milliseconds.
3307 * cHandles [I] Number of handles pointed to by pHandles.
3308 * pHandles [I] Handles to wait for.
3309 * lpdwindex [O] Index of handle that was signaled.
3313 * Failure: RPC_S_CALLPENDING on timeout.
3317 * The dwFlags parameter can be zero or more of the following:
3318 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3319 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3322 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3324 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3325 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3328 DWORD start_time = GetTickCount();
3329 APARTMENT *apt = COM_CurrentApt();
3330 BOOL message_loop = apt && !apt->multi_threaded;
3332 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3333 pHandles, lpdwindex);
3337 DWORD now = GetTickCount();
3340 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3342 hr = RPC_S_CALLPENDING;
3348 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3349 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3351 TRACE("waiting for rpc completion or window message\n");
3353 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3354 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3355 QS_ALLINPUT, wait_flags);
3357 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3361 /* call message filter */
3363 if (COM_CurrentApt()->filter)
3365 PENDINGTYPE pendingtype =
3366 COM_CurrentInfo()->pending_call_count_server ?
3367 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3368 DWORD be_handled = IMessageFilter_MessagePending(
3369 COM_CurrentApt()->filter, 0 /* FIXME */,
3370 now - start_time, pendingtype);
3371 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3374 case PENDINGMSG_CANCELCALL:
3375 WARN("call canceled\n");
3376 hr = RPC_E_CALL_CANCELED;
3378 case PENDINGMSG_WAITNOPROCESS:
3379 case PENDINGMSG_WAITDEFPROCESS:
3381 /* FIXME: MSDN is very vague about the difference
3382 * between WAITNOPROCESS and WAITDEFPROCESS - there
3383 * appears to be none, so it is possibly a left-over
3384 * from the 16-bit world. */
3389 /* note: using "if" here instead of "while" might seem less
3390 * efficient, but only if we are optimising for quick delivery
3391 * of pending messages, rather than quick completion of the
3393 if (COM_PeekMessage(apt, &msg))
3395 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3396 TranslateMessage(&msg);
3397 DispatchMessageW(&msg);
3398 if (msg.message == WM_QUIT)
3400 TRACE("resending WM_QUIT to outer message loop\n");
3401 PostQuitMessage(msg.wParam);
3402 /* no longer need to process messages */
3403 message_loop = FALSE;
3411 TRACE("waiting for rpc completion\n");
3413 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3414 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3415 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3416 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3419 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3421 /* handle signaled, store index */
3422 *lpdwindex = (res - WAIT_OBJECT_0);
3425 else if (res == WAIT_TIMEOUT)
3427 hr = RPC_S_CALLPENDING;
3432 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3437 TRACE("-- 0x%08x\n", hr);
3442 /***********************************************************************
3443 * CoGetObject [OLE32.@]
3445 * Gets the object named by coverting the name to a moniker and binding to it.
3448 * pszName [I] String representing the object.
3449 * pBindOptions [I] Parameters affecting the binding to the named object.
3450 * riid [I] Interface to bind to on the objecct.
3451 * ppv [O] On output, the interface riid of the object represented
3456 * Failure: HRESULT code.
3459 * MkParseDisplayName.
3461 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3462 REFIID riid, void **ppv)
3469 hr = CreateBindCtx(0, &pbc);
3473 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3480 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3483 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3484 IMoniker_Release(pmk);
3488 IBindCtx_Release(pbc);
3493 /***********************************************************************
3494 * CoRegisterChannelHook [OLE32.@]
3496 * Registers a process-wide hook that is called during ORPC calls.
3499 * guidExtension [I] GUID of the channel hook to register.
3500 * pChannelHook [I] Channel hook object to register.
3504 * Failure: HRESULT code.
3506 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3508 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3510 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3513 /***********************************************************************
3516 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3518 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3521 case DLL_PROCESS_ATTACH:
3522 OLE32_hInstance = hinstDLL;
3523 COMPOBJ_InitProcess();
3524 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3527 case DLL_PROCESS_DETACH:
3528 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3529 OLEDD_UnInitialize();
3530 COMPOBJ_UninitProcess();
3531 RPC_UnregisterAllChannelHooks();
3532 OLE32_hInstance = 0;
3535 case DLL_THREAD_DETACH:
3542 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */