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
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
55 #define USE_COM_CONTEXT_DEF
63 #include "compobj_private.h"
66 #include "wine/unicode.h"
67 #include "wine/debug.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(ole);
71 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
73 /****************************************************************************
74 * This section defines variables internal to the COM module.
77 static APARTMENT *MTA; /* protected by csApartment */
78 static APARTMENT *MainApartment; /* the first STA apartment */
79 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
81 static CRITICAL_SECTION csApartment;
82 static CRITICAL_SECTION_DEBUG critsect_debug =
85 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
88 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
90 struct registered_psclsid
98 * This lock count counts the number of times CoInitialize is called. It is
99 * decreased every time CoUninitialize is called. When it hits 0, the COM
100 * libraries are freed
102 static LONG s_COMLockCount = 0;
103 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
104 static LONG s_COMServerProcessReferences = 0;
107 * This linked list contains the list of registered class objects. These
108 * are mostly used to register the factories for out-of-proc servers of OLE
111 * TODO: Make this data structure aware of inter-process communication. This
112 * means that parts of this will be exported to rpcss.
114 typedef struct tagRegisteredClass
117 CLSID classIdentifier;
119 LPUNKNOWN classObject;
123 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
124 void *RpcRegistration;
127 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
129 static CRITICAL_SECTION csRegisteredClassList;
130 static CRITICAL_SECTION_DEBUG class_cs_debug =
132 0, 0, &csRegisteredClassList,
133 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
134 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
136 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
138 /*****************************************************************************
139 * This section contains OpenDllList definitions
141 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
142 * other functions that do LoadLibrary _without_ giving back a HMODULE.
143 * Without this list these handles would never be freed.
145 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
146 * next unload-call but not before 600 sec.
149 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
150 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
152 typedef struct tagOpenDll
157 DllGetClassObjectFunc DllGetClassObject;
158 DllCanUnloadNowFunc DllCanUnloadNow;
162 static struct list openDllList = LIST_INIT(openDllList);
164 static CRITICAL_SECTION csOpenDllList;
165 static CRITICAL_SECTION_DEBUG dll_cs_debug =
167 0, 0, &csOpenDllList,
168 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
169 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
171 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
173 struct apartment_loaded_dll
181 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',' ',
182 '0','x','#','#','#','#','#','#','#','#',' ',0};
184 /*****************************************************************************
185 * This section contains OpenDllList implementation
188 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
192 EnterCriticalSection(&csOpenDllList);
193 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
195 if (!strcmpiW(library_name, ptr->library_name) &&
196 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
202 LeaveCriticalSection(&csOpenDllList);
206 /* caller must ensure that library_name is not already in the open dll list */
207 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
213 DllCanUnloadNowFunc DllCanUnloadNow;
214 DllGetClassObjectFunc DllGetClassObject;
218 *ret = COMPOBJ_DllList_Get(library_name);
219 if (*ret) return S_OK;
221 /* do this outside the csOpenDllList to avoid creating a lock dependency on
223 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
226 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
227 /* failure: DLL could not be loaded */
228 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
231 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
232 /* Note: failing to find DllCanUnloadNow is not a failure */
233 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
234 if (!DllGetClassObject)
236 /* failure: the dll did not export DllGetClassObject */
237 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
238 FreeLibrary(hLibrary);
239 return CO_E_DLLNOTFOUND;
242 EnterCriticalSection( &csOpenDllList );
244 *ret = COMPOBJ_DllList_Get(library_name);
247 /* another caller to this function already added the dll while we
248 * weren't in the critical section */
249 FreeLibrary(hLibrary);
253 len = strlenW(library_name);
254 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
256 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
257 if (entry && entry->library_name)
259 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
260 entry->library = hLibrary;
262 entry->DllCanUnloadNow = DllCanUnloadNow;
263 entry->DllGetClassObject = DllGetClassObject;
264 list_add_tail(&openDllList, &entry->entry);
268 HeapFree(GetProcessHeap(), 0, entry);
270 FreeLibrary(hLibrary);
275 LeaveCriticalSection( &csOpenDllList );
280 /* pass FALSE for free_entry to release a reference without destroying the
281 * entry if it reaches zero or TRUE otherwise */
282 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
284 if (!InterlockedDecrement(&entry->refs) && free_entry)
286 EnterCriticalSection(&csOpenDllList);
287 list_remove(&entry->entry);
288 LeaveCriticalSection(&csOpenDllList);
290 TRACE("freeing %p\n", entry->library);
291 FreeLibrary(entry->library);
293 HeapFree(GetProcessHeap(), 0, entry->library_name);
294 HeapFree(GetProcessHeap(), 0, entry);
298 /* frees memory associated with active dll list */
299 static void COMPOBJ_DllList_Free(void)
301 OpenDll *entry, *cursor2;
302 EnterCriticalSection(&csOpenDllList);
303 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
305 list_remove(&entry->entry);
307 HeapFree(GetProcessHeap(), 0, entry->library_name);
308 HeapFree(GetProcessHeap(), 0, entry);
310 LeaveCriticalSection(&csOpenDllList);
313 /******************************************************************************
317 static DWORD apartment_addref(struct apartment *apt)
319 DWORD refs = InterlockedIncrement(&apt->refs);
320 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
324 /* allocates memory and fills in the necessary fields for a new apartment
325 * object. must be called inside apartment cs */
326 static APARTMENT *apartment_construct(DWORD model)
330 TRACE("creating new apartment, model=%d\n", model);
332 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
333 apt->tid = GetCurrentThreadId();
335 list_init(&apt->proxies);
336 list_init(&apt->stubmgrs);
337 list_init(&apt->psclsids);
338 list_init(&apt->loaded_dlls);
341 apt->remunk_exported = FALSE;
343 InitializeCriticalSection(&apt->cs);
344 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
346 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
348 if (apt->multi_threaded)
350 /* FIXME: should be randomly generated by in an RPC call to rpcss */
351 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
355 /* FIXME: should be randomly generated by in an RPC call to rpcss */
356 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
359 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
361 list_add_head(&apts, &apt->entry);
366 /* gets and existing apartment if one exists or otherwise creates an apartment
367 * structure which stores OLE apartment-local information and stores a pointer
368 * to it in the thread-local storage */
369 static APARTMENT *apartment_get_or_create(DWORD model)
371 APARTMENT *apt = COM_CurrentApt();
375 if (model & COINIT_APARTMENTTHREADED)
377 EnterCriticalSection(&csApartment);
379 apt = apartment_construct(model);
384 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
387 LeaveCriticalSection(&csApartment);
390 apartment_createwindowifneeded(apt);
394 EnterCriticalSection(&csApartment);
396 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
397 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
401 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
402 apartment_addref(MTA);
405 MTA = apartment_construct(model);
409 LeaveCriticalSection(&csApartment);
411 COM_CurrentInfo()->apt = apt;
417 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
419 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
422 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
424 list_remove(&curClass->entry);
426 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
427 RPC_StopLocalServer(curClass->RpcRegistration);
430 * Release the reference to the class object.
432 IUnknown_Release(curClass->classObject);
434 if (curClass->pMarshaledData)
437 memset(&zero, 0, sizeof(zero));
438 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
439 CoReleaseMarshalData(curClass->pMarshaledData);
440 IStream_Release(curClass->pMarshaledData);
443 HeapFree(GetProcessHeap(), 0, curClass);
446 static void COM_RevokeAllClasses(const struct apartment *apt)
448 RegisteredClass *curClass, *cursor;
450 EnterCriticalSection( &csRegisteredClassList );
452 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
454 if (curClass->apartment_id == apt->oxid)
455 COM_RevokeRegisteredClassObject(curClass);
458 LeaveCriticalSection( &csRegisteredClassList );
461 /******************************************************************************
462 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
465 typedef struct ManualResetEvent {
466 ISynchronize ISynchronize_iface;
471 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
473 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
476 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
478 MREImpl *This = impl_from_ISynchronize(iface);
479 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
482 if(IsEqualGUID(riid, &IID_IUnknown) ||
483 IsEqualGUID(riid, &IID_ISynchronize))
486 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
490 IUnknown_AddRef((IUnknown*)*ppv);
494 return E_NOINTERFACE;
497 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
499 MREImpl *This = impl_from_ISynchronize(iface);
500 LONG ref = InterlockedIncrement(&This->ref);
501 TRACE("%p - ref %d\n", This, ref);
506 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
508 MREImpl *This = impl_from_ISynchronize(iface);
509 LONG ref = InterlockedDecrement(&This->ref);
510 TRACE("%p - ref %d\n", This, ref);
514 CloseHandle(This->event);
515 HeapFree(GetProcessHeap(), 0, This);
521 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
523 MREImpl *This = impl_from_ISynchronize(iface);
525 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
526 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
529 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
531 MREImpl *This = impl_from_ISynchronize(iface);
533 SetEvent(This->event);
537 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
539 MREImpl *This = impl_from_ISynchronize(iface);
541 ResetEvent(This->event);
545 static ISynchronizeVtbl vt_ISynchronize = {
546 ISynchronize_fnQueryInterface,
547 ISynchronize_fnAddRef,
548 ISynchronize_fnRelease,
550 ISynchronize_fnSignal,
554 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
556 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
560 FIXME("Aggregation not implemented.\n");
563 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
564 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
566 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
567 ISynchronize_Release(&This->ISynchronize_iface);
571 /***********************************************************************
572 * CoRevokeClassObject [OLE32.@]
574 * Removes a class object from the class registry.
577 * dwRegister [I] Cookie returned from CoRegisterClassObject().
581 * Failure: HRESULT code.
584 * Must be called from the same apartment that called CoRegisterClassObject(),
585 * otherwise it will fail with RPC_E_WRONG_THREAD.
588 * CoRegisterClassObject
590 HRESULT WINAPI CoRevokeClassObject(
593 HRESULT hr = E_INVALIDARG;
594 RegisteredClass *curClass;
597 TRACE("(%08x)\n",dwRegister);
599 apt = COM_CurrentApt();
602 ERR("COM was not initialized\n");
603 return CO_E_NOTINITIALIZED;
606 EnterCriticalSection( &csRegisteredClassList );
608 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
611 * Check if we have a match on the cookie.
613 if (curClass->dwCookie == dwRegister)
615 if (curClass->apartment_id == apt->oxid)
617 COM_RevokeRegisteredClassObject(curClass);
622 ERR("called from wrong apartment, should be called from %s\n",
623 wine_dbgstr_longlong(curClass->apartment_id));
624 hr = RPC_E_WRONG_THREAD;
630 LeaveCriticalSection( &csRegisteredClassList );
635 /* frees unused libraries loaded by apartment_getclassobject by calling the
636 * DLL's DllCanUnloadNow entry point */
637 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
639 struct apartment_loaded_dll *entry, *next;
640 EnterCriticalSection(&apt->cs);
641 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
643 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
645 DWORD real_delay = delay;
647 if (real_delay == INFINITE)
649 /* DLLs that return multi-threaded objects aren't unloaded
650 * straight away to cope for programs that have races between
651 * last object destruction and threads in the DLLs that haven't
652 * finished, despite DllCanUnloadNow returning S_OK */
653 if (entry->multi_threaded)
654 real_delay = 10 * 60 * 1000; /* 10 minutes */
659 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
661 list_remove(&entry->entry);
662 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
663 HeapFree(GetProcessHeap(), 0, entry);
666 entry->unload_time = GetTickCount() + real_delay;
668 else if (entry->unload_time)
669 entry->unload_time = 0;
671 LeaveCriticalSection(&apt->cs);
674 DWORD apartment_release(struct apartment *apt)
678 EnterCriticalSection(&csApartment);
680 ret = InterlockedDecrement(&apt->refs);
681 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
682 /* destruction stuff that needs to happen under csApartment CS */
685 if (apt == MTA) MTA = NULL;
686 else if (apt == MainApartment) MainApartment = NULL;
687 list_remove(&apt->entry);
690 LeaveCriticalSection(&csApartment);
694 struct list *cursor, *cursor2;
696 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
698 /* Release the references to the registered class objects */
699 COM_RevokeAllClasses(apt);
701 /* no locking is needed for this apartment, because no other thread
702 * can access it at this point */
704 apartment_disconnectproxies(apt);
706 if (apt->win) DestroyWindow(apt->win);
707 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
709 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
711 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
712 /* release the implicit reference given by the fact that the
713 * stub has external references (it must do since it is in the
714 * stub manager list in the apartment and all non-apartment users
715 * must have a ref on the apartment and so it cannot be destroyed).
717 stub_manager_int_release(stubmgr);
720 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
722 struct registered_psclsid *registered_psclsid =
723 LIST_ENTRY(cursor, struct registered_psclsid, entry);
725 list_remove(®istered_psclsid->entry);
726 HeapFree(GetProcessHeap(), 0, registered_psclsid);
729 /* if this assert fires, then another thread took a reference to a
730 * stub manager without taking a reference to the containing
731 * apartment, which it must do. */
732 assert(list_empty(&apt->stubmgrs));
734 if (apt->filter) IUnknown_Release(apt->filter);
736 /* free as many unused libraries as possible... */
737 apartment_freeunusedlibraries(apt, 0);
739 /* ... and free the memory for the apartment loaded dll entry and
740 * release the dll list reference without freeing the library for the
742 while ((cursor = list_head(&apt->loaded_dlls)))
744 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
745 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
747 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
750 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
751 DeleteCriticalSection(&apt->cs);
753 HeapFree(GetProcessHeap(), 0, apt);
759 /* The given OXID must be local to this process:
761 * The ref parameter is here mostly to ensure people remember that
762 * they get one, you should normally take a ref for thread safety.
764 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
766 APARTMENT *result = NULL;
769 EnterCriticalSection(&csApartment);
770 LIST_FOR_EACH( cursor, &apts )
772 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
773 if (apt->oxid == oxid)
776 if (ref) apartment_addref(result);
780 LeaveCriticalSection(&csApartment);
785 /* gets the apartment which has a given creator thread ID. The caller must
786 * release the reference from the apartment as soon as the apartment pointer
787 * is no longer required. */
788 APARTMENT *apartment_findfromtid(DWORD tid)
790 APARTMENT *result = NULL;
793 EnterCriticalSection(&csApartment);
794 LIST_FOR_EACH( cursor, &apts )
796 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
800 apartment_addref(result);
804 LeaveCriticalSection(&csApartment);
809 /* gets the main apartment if it exists. The caller must
810 * release the reference from the apartment as soon as the apartment pointer
811 * is no longer required. */
812 static APARTMENT *apartment_findmain(void)
816 EnterCriticalSection(&csApartment);
818 result = MainApartment;
819 if (result) apartment_addref(result);
821 LeaveCriticalSection(&csApartment);
826 /* gets the multi-threaded apartment if it exists. The caller must
827 * release the reference from the apartment as soon as the apartment pointer
828 * is no longer required. */
829 static APARTMENT *apartment_find_multi_threaded(void)
831 APARTMENT *result = NULL;
834 EnterCriticalSection(&csApartment);
836 LIST_FOR_EACH( cursor, &apts )
838 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
839 if (apt->multi_threaded)
842 apartment_addref(result);
847 LeaveCriticalSection(&csApartment);
851 /* gets the specified class object by loading the appropriate DLL, if
852 * necessary and calls the DllGetClassObject function for the DLL */
853 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
854 BOOL apartment_threaded,
855 REFCLSID rclsid, REFIID riid, void **ppv)
857 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
860 struct apartment_loaded_dll *apartment_loaded_dll;
862 if (!strcmpiW(dllpath, wszOle32))
864 /* we don't need to control the lifetime of this dll, so use the local
865 * implementation of DllGetClassObject directly */
866 TRACE("calling ole32!DllGetClassObject\n");
867 hr = DllGetClassObject(rclsid, riid, ppv);
870 ERR("DllGetClassObject returned error 0x%08x\n", hr);
875 EnterCriticalSection(&apt->cs);
877 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
878 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
880 TRACE("found %s already loaded\n", debugstr_w(dllpath));
887 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
888 if (!apartment_loaded_dll)
892 apartment_loaded_dll->unload_time = 0;
893 apartment_loaded_dll->multi_threaded = FALSE;
894 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
896 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
900 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
901 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
905 LeaveCriticalSection(&apt->cs);
909 /* one component being multi-threaded overrides any number of
910 * apartment-threaded components */
911 if (!apartment_threaded)
912 apartment_loaded_dll->multi_threaded = TRUE;
914 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
915 /* OK: get the ClassObject */
916 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
919 ERR("DllGetClassObject returned error 0x%08x\n", hr);
925 /***********************************************************************
926 * COM_RegReadPath [internal]
928 * Reads a registry value and expands it when necessary
930 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
936 DWORD dwLength = dstlen * sizeof(WCHAR);
938 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
939 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
940 if (keytype == REG_EXPAND_SZ) {
941 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
943 const WCHAR *quote_start;
944 quote_start = strchrW(src, '\"');
946 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
948 memmove(src, quote_start + 1,
949 (quote_end - quote_start - 1) * sizeof(WCHAR));
950 src[quote_end - quote_start - 1] = '\0';
953 lstrcpynW(dst, src, dstlen);
961 struct host_object_params
964 CLSID clsid; /* clsid of object to marshal */
965 IID iid; /* interface to marshal */
966 HANDLE event; /* event signalling when ready for multi-threaded case */
967 HRESULT hr; /* result for multi-threaded case */
968 IStream *stream; /* stream that the object will be marshaled into */
969 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
972 static HRESULT apartment_hostobject(struct apartment *apt,
973 const struct host_object_params *params)
977 static const LARGE_INTEGER llZero;
978 WCHAR dllpath[MAX_PATH+1];
980 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid));
982 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
984 /* failure: CLSID is not found in registry */
985 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
986 return REGDB_E_CLASSNOTREG;
989 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
990 ¶ms->clsid, ¶ms->iid, (void **)&object);
994 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
996 IUnknown_Release(object);
997 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1002 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1007 RPC_ExecuteCall((struct dispatch_params *)lParam);
1010 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1012 return DefWindowProcW(hWnd, msg, wParam, lParam);
1016 struct host_thread_params
1018 COINIT threading_model;
1020 HWND apartment_hwnd;
1023 /* thread for hosting an object to allow an object to appear to be created in
1024 * an apartment with an incompatible threading model */
1025 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1027 struct host_thread_params *params = p;
1030 struct apartment *apt;
1034 hr = CoInitializeEx(NULL, params->threading_model);
1035 if (FAILED(hr)) return hr;
1037 apt = COM_CurrentApt();
1038 if (params->threading_model == COINIT_APARTMENTTHREADED)
1040 apartment_createwindowifneeded(apt);
1041 params->apartment_hwnd = apartment_getwindow(apt);
1044 params->apartment_hwnd = NULL;
1046 /* force the message queue to be created before signaling parent thread */
1047 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1049 SetEvent(params->ready_event);
1050 params = NULL; /* can't touch params after here as it may be invalid */
1052 while (GetMessageW(&msg, NULL, 0, 0))
1054 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1056 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1057 obj_params->hr = apartment_hostobject(apt, obj_params);
1058 SetEvent(obj_params->event);
1062 TranslateMessage(&msg);
1063 DispatchMessageW(&msg);
1074 /* finds or creates a host apartment, creates the object inside it and returns
1075 * a proxy to it so that the object can be used in the apartment of the
1076 * caller of this function */
1077 static HRESULT apartment_hostobject_in_hostapt(
1078 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1079 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
1081 struct host_object_params params;
1082 HWND apartment_hwnd = NULL;
1083 DWORD apartment_tid = 0;
1086 if (!multi_threaded && main_apartment)
1088 APARTMENT *host_apt = apartment_findmain();
1091 apartment_hwnd = apartment_getwindow(host_apt);
1092 apartment_release(host_apt);
1096 if (!apartment_hwnd)
1098 EnterCriticalSection(&apt->cs);
1100 if (!apt->host_apt_tid)
1102 struct host_thread_params thread_params;
1106 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1107 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1108 thread_params.apartment_hwnd = NULL;
1109 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1112 CloseHandle(handles[0]);
1113 LeaveCriticalSection(&apt->cs);
1114 return E_OUTOFMEMORY;
1116 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1117 CloseHandle(handles[0]);
1118 CloseHandle(handles[1]);
1119 if (wait_value == WAIT_OBJECT_0)
1120 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1123 LeaveCriticalSection(&apt->cs);
1124 return E_OUTOFMEMORY;
1128 if (multi_threaded || !main_apartment)
1130 apartment_hwnd = apt->host_apt_hwnd;
1131 apartment_tid = apt->host_apt_tid;
1134 LeaveCriticalSection(&apt->cs);
1137 /* another thread may have become the main apartment in the time it took
1138 * us to create the thread for the host apartment */
1139 if (!apartment_hwnd && !multi_threaded && main_apartment)
1141 APARTMENT *host_apt = apartment_findmain();
1144 apartment_hwnd = apartment_getwindow(host_apt);
1145 apartment_release(host_apt);
1149 params.hkeydll = hkeydll;
1150 params.clsid = *rclsid;
1152 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
1155 params.apartment_threaded = !multi_threaded;
1159 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1160 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms))
1164 WaitForSingleObject(params.event, INFINITE);
1167 CloseHandle(params.event);
1171 if (!apartment_hwnd)
1173 ERR("host apartment didn't create window\n");
1177 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
1180 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1181 IStream_Release(params.stream);
1185 /* create a window for the apartment or return the current one if one has
1186 * already been created */
1187 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1189 if (apt->multi_threaded)
1194 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1196 HWND_MESSAGE, 0, hProxyDll, NULL);
1199 ERR("CreateWindow failed with error %d\n", GetLastError());
1200 return HRESULT_FROM_WIN32(GetLastError());
1202 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1203 /* someone beat us to it */
1204 DestroyWindow(hwnd);
1210 /* retrieves the window for the main- or apartment-threaded apartment */
1211 HWND apartment_getwindow(const struct apartment *apt)
1213 assert(!apt->multi_threaded);
1217 void apartment_joinmta(void)
1219 apartment_addref(MTA);
1220 COM_CurrentInfo()->apt = MTA;
1223 static void COMPOBJ_InitProcess( void )
1227 /* Dispatching to the correct thread in an apartment is done through
1228 * window messages rather than RPC transports. When an interface is
1229 * marshalled into another apartment in the same process, a window of the
1230 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1231 * application) is responsible for pumping the message loop in that thread.
1232 * The WM_USER messages which point to the RPCs are then dispatched to
1233 * apartment_wndproc by the user's code from the apartment in which the
1234 * interface was unmarshalled.
1236 memset(&wclass, 0, sizeof(wclass));
1237 wclass.lpfnWndProc = apartment_wndproc;
1238 wclass.hInstance = hProxyDll;
1239 wclass.lpszClassName = wszAptWinClass;
1240 RegisterClassW(&wclass);
1243 static void COMPOBJ_UninitProcess( void )
1245 UnregisterClassW(wszAptWinClass, hProxyDll);
1248 static void COM_TlsDestroy(void)
1250 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1253 if (info->apt) apartment_release(info->apt);
1254 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1255 if (info->state) IUnknown_Release(info->state);
1256 if (info->spy) IUnknown_Release(info->spy);
1257 if (info->context_token) IObjContext_Release(info->context_token);
1258 HeapFree(GetProcessHeap(), 0, info);
1259 NtCurrentTeb()->ReservedForOle = NULL;
1263 /******************************************************************************
1264 * CoBuildVersion [OLE32.@]
1266 * Gets the build version of the DLL.
1271 * Current build version, hiword is majornumber, loword is minornumber
1273 DWORD WINAPI CoBuildVersion(void)
1275 TRACE("Returning version %d, build %d.\n", rmm, rup);
1276 return (rmm<<16)+rup;
1279 /******************************************************************************
1280 * CoRegisterInitializeSpy [OLE32.@]
1282 * Add a Spy that watches CoInitializeEx calls
1285 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1286 * cookie [II] cookie receiver
1289 * Success: S_OK if not already initialized, S_FALSE otherwise.
1290 * Failure: HRESULT code.
1295 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1297 struct oletls *info = COM_CurrentInfo();
1300 TRACE("(%p, %p)\n", spy, cookie);
1302 if (!spy || !cookie || !info)
1305 WARN("Could not allocate tls\n");
1306 return E_INVALIDARG;
1311 FIXME("Already registered?\n");
1312 return E_UNEXPECTED;
1315 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1318 cookie->QuadPart = (DWORD_PTR)spy;
1324 /******************************************************************************
1325 * CoRevokeInitializeSpy [OLE32.@]
1327 * Remove a spy that previously watched CoInitializeEx calls
1330 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1333 * Success: S_OK if a spy is removed
1334 * Failure: E_INVALIDARG
1339 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1341 struct oletls *info = COM_CurrentInfo();
1342 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1344 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1345 return E_INVALIDARG;
1347 IUnknown_Release(info->spy);
1353 /******************************************************************************
1354 * CoInitialize [OLE32.@]
1356 * Initializes the COM libraries by calling CoInitializeEx with
1357 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1360 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1363 * Success: S_OK if not already initialized, S_FALSE otherwise.
1364 * Failure: HRESULT code.
1369 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1372 * Just delegate to the newer method.
1374 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1377 /******************************************************************************
1378 * CoInitializeEx [OLE32.@]
1380 * Initializes the COM libraries.
1383 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1384 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1387 * S_OK if successful,
1388 * S_FALSE if this function was called already.
1389 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1394 * The behavior used to set the IMalloc used for memory management is
1396 * The dwCoInit parameter must specify one of the following apartment
1398 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1399 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1400 * The parameter may also specify zero or more of the following flags:
1401 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1402 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1407 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1409 struct oletls *info = COM_CurrentInfo();
1413 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1415 if (lpReserved!=NULL)
1417 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1421 * Check the lock count. If this is the first time going through the initialize
1422 * process, we have to initialize the libraries.
1424 * And crank-up that lock count.
1426 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1429 * Initialize the various COM libraries and data structures.
1431 TRACE("() - Initializing the COM libraries\n");
1433 /* we may need to defer this until after apartment initialisation */
1434 RunningObjectTableImpl_Initialize();
1438 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1440 if (!(apt = info->apt))
1442 apt = apartment_get_or_create(dwCoInit);
1443 if (!apt) return E_OUTOFMEMORY;
1445 else if (!apartment_is_model(apt, dwCoInit))
1447 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1448 code then we are probably using the wrong threading model to implement that API. */
1449 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1450 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1451 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1452 return RPC_E_CHANGED_MODE;
1460 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1465 /***********************************************************************
1466 * CoUninitialize [OLE32.@]
1468 * This method will decrement the refcount on the current apartment, freeing
1469 * the resources associated with it if it is the last thread in the apartment.
1470 * If the last apartment is freed, the function will additionally release
1471 * any COM resources associated with the process.
1481 void WINAPI CoUninitialize(void)
1483 struct oletls * info = COM_CurrentInfo();
1488 /* will only happen on OOM */
1492 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1497 ERR("Mismatched CoUninitialize\n");
1500 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1506 apartment_release(info->apt);
1511 * Decrease the reference count.
1512 * If we are back to 0 locks on the COM library, make sure we free
1513 * all the associated data structures.
1515 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1518 TRACE("() - Releasing the COM libraries\n");
1520 RunningObjectTableImpl_UnInitialize();
1522 else if (lCOMRefCnt<1) {
1523 ERR( "CoUninitialize() - not CoInitialized.\n" );
1524 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1527 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1530 /******************************************************************************
1531 * CoDisconnectObject [OLE32.@]
1533 * Disconnects all connections to this object from remote processes. Dispatches
1534 * pending RPCs while blocking new RPCs from occurring, and then calls
1535 * IMarshal::DisconnectObject on the given object.
1537 * Typically called when the object server is forced to shut down, for instance by
1541 * lpUnk [I] The object whose stub should be disconnected.
1542 * reserved [I] Reserved. Should be set to 0.
1546 * Failure: HRESULT code.
1549 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1551 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1557 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1559 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1562 hr = IMarshal_DisconnectObject(marshal, reserved);
1563 IMarshal_Release(marshal);
1567 apt = COM_CurrentApt();
1569 return CO_E_NOTINITIALIZED;
1571 apartment_disconnectobject(apt, lpUnk);
1573 /* Note: native is pretty broken here because it just silently
1574 * fails, without returning an appropriate error code if the object was
1575 * not found, making apps think that the object was disconnected, when
1576 * it actually wasn't */
1581 /******************************************************************************
1582 * CoCreateGuid [OLE32.@]
1584 * Simply forwards to UuidCreate in RPCRT4.
1587 * pguid [O] Points to the GUID to initialize.
1591 * Failure: HRESULT code.
1596 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1598 DWORD status = UuidCreate(pguid);
1599 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1600 return HRESULT_FROM_WIN32( status );
1603 static inline BOOL is_valid_hex(WCHAR c)
1605 if (!(((c >= '0') && (c <= '9')) ||
1606 ((c >= 'a') && (c <= 'f')) ||
1607 ((c >= 'A') && (c <= 'F'))))
1612 /******************************************************************************
1613 * CLSIDFromString [OLE32.@]
1614 * IIDFromString [OLE32.@]
1616 * Converts a unique identifier from its string representation into
1620 * idstr [I] The string representation of the GUID.
1621 * id [O] GUID converted from the string.
1625 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1630 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1635 if (!s || s[0]!='{') {
1636 memset( id, 0, sizeof (CLSID) );
1638 return CO_E_CLASSSTRING;
1641 TRACE("%s -> %p\n", debugstr_w(s), id);
1643 /* quick lookup table */
1644 memset(table, 0, 256);
1646 for (i = 0; i < 10; i++) {
1649 for (i = 0; i < 6; i++) {
1650 table['A' + i] = i+10;
1651 table['a' + i] = i+10;
1654 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1657 for (i = 1; i < 9; i++) {
1658 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1659 id->Data1 = (id->Data1 << 4) | table[s[i]];
1661 if (s[9]!='-') return CO_E_CLASSSTRING;
1664 for (i = 10; i < 14; i++) {
1665 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1666 id->Data2 = (id->Data2 << 4) | table[s[i]];
1668 if (s[14]!='-') return CO_E_CLASSSTRING;
1671 for (i = 15; i < 19; i++) {
1672 if (!is_valid_hex(s[i])) return CO_E_CLASSSTRING;
1673 id->Data3 = (id->Data3 << 4) | table[s[i]];
1675 if (s[19]!='-') return CO_E_CLASSSTRING;
1677 for (i = 20; i < 37; i+=2) {
1679 if (s[i]!='-') return CO_E_CLASSSTRING;
1682 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return CO_E_CLASSSTRING;
1683 id->Data4[(i-20)/2] = table[s[i]] << 4 | table[s[i+1]];
1686 if (s[37] == '}' && s[38] == '\0')
1689 return CO_E_CLASSSTRING;
1692 /*****************************************************************************/
1694 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1699 return E_INVALIDARG;
1701 ret = __CLSIDFromString(idstr, id);
1702 if(ret != S_OK) { /* It appears a ProgID is also valid */
1704 ret = CLSIDFromProgID(idstr, &tmp_id);
1712 /******************************************************************************
1713 * StringFromCLSID [OLE32.@]
1714 * StringFromIID [OLE32.@]
1716 * Converts a GUID into the respective string representation.
1717 * The target string is allocated using the OLE IMalloc.
1720 * id [I] the GUID to be converted.
1721 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1728 * StringFromGUID2, CLSIDFromString
1730 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1735 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1736 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1737 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1741 /******************************************************************************
1742 * StringFromGUID2 [OLE32.@]
1744 * Modified version of StringFromCLSID that allows you to specify max
1748 * id [I] GUID to convert to string.
1749 * str [O] Buffer where the result will be stored.
1750 * cmax [I] Size of the buffer in characters.
1753 * Success: The length of the resulting string in characters.
1756 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1758 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1759 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1760 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1761 '%','0','2','X','%','0','2','X','}',0 };
1762 if (!id || cmax < CHARS_IN_GUID) return 0;
1763 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1764 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1765 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1766 return CHARS_IN_GUID;
1769 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1770 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1772 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1773 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1777 strcpyW(path, wszCLSIDSlash);
1778 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1779 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1780 if (res == ERROR_FILE_NOT_FOUND)
1781 return REGDB_E_CLASSNOTREG;
1782 else if (res != ERROR_SUCCESS)
1783 return REGDB_E_READREGDB;
1791 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1793 if (res == ERROR_FILE_NOT_FOUND)
1794 return REGDB_E_KEYMISSING;
1795 else if (res != ERROR_SUCCESS)
1796 return REGDB_E_READREGDB;
1801 /* open HKCR\\AppId\\{string form of appid clsid} key */
1802 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1804 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1805 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1807 WCHAR buf[CHARS_IN_GUID];
1808 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1814 /* read the AppID value under the class's key */
1815 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1820 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1822 if (res == ERROR_FILE_NOT_FOUND)
1823 return REGDB_E_KEYMISSING;
1824 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1825 return REGDB_E_READREGDB;
1827 strcpyW(keyname, szAppIdKey);
1828 strcatW(keyname, buf);
1829 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1830 if (res == ERROR_FILE_NOT_FOUND)
1831 return REGDB_E_KEYMISSING;
1832 else if (res != ERROR_SUCCESS)
1833 return REGDB_E_READREGDB;
1838 /******************************************************************************
1839 * ProgIDFromCLSID [OLE32.@]
1841 * Converts a class id into the respective program ID.
1844 * clsid [I] Class ID, as found in registry.
1845 * ppszProgID [O] Associated ProgID.
1850 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1852 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1854 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1861 ERR("ppszProgId isn't optional\n");
1862 return E_INVALIDARG;
1866 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1870 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1871 ret = REGDB_E_CLASSNOTREG;
1875 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1878 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1879 ret = REGDB_E_CLASSNOTREG;
1882 ret = E_OUTOFMEMORY;
1889 /******************************************************************************
1890 * CLSIDFromProgID [OLE32.@]
1892 * Converts a program id into the respective GUID.
1895 * progid [I] Unicode program ID, as found in registry.
1896 * clsid [O] Associated CLSID.
1900 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1902 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1904 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1905 WCHAR buf2[CHARS_IN_GUID];
1906 LONG buf2len = sizeof(buf2);
1910 if (!progid || !clsid)
1912 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1913 return E_INVALIDARG;
1916 /* initialise clsid in case of failure */
1917 memset(clsid, 0, sizeof(*clsid));
1919 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1920 strcpyW( buf, progid );
1921 strcatW( buf, clsidW );
1922 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1924 HeapFree(GetProcessHeap(),0,buf);
1925 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1926 return CO_E_CLASSSTRING;
1928 HeapFree(GetProcessHeap(),0,buf);
1930 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1933 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1934 return CO_E_CLASSSTRING;
1937 return __CLSIDFromString(buf2,clsid);
1941 /*****************************************************************************
1942 * CoGetPSClsid [OLE32.@]
1944 * Retrieves the CLSID of the proxy/stub factory that implements
1945 * IPSFactoryBuffer for the specified interface.
1948 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1949 * pclsid [O] Where to store returned proxy/stub CLSID.
1954 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1958 * The standard marshaller activates the object with the CLSID
1959 * returned and uses the CreateProxy and CreateStub methods on its
1960 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1963 * CoGetPSClsid determines this CLSID by searching the
1964 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1965 * in the registry and any interface id registered by
1966 * CoRegisterPSClsid within the current process.
1970 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1971 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1972 * considered a bug in native unless an application depends on this (unlikely).
1975 * CoRegisterPSClsid.
1977 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1979 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1980 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1981 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1982 WCHAR value[CHARS_IN_GUID];
1985 APARTMENT *apt = COM_CurrentApt();
1986 struct registered_psclsid *registered_psclsid;
1988 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1992 ERR("apartment not initialised\n");
1993 return CO_E_NOTINITIALIZED;
1998 ERR("pclsid isn't optional\n");
1999 return E_INVALIDARG;
2002 EnterCriticalSection(&apt->cs);
2004 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2005 if (IsEqualIID(®istered_psclsid->iid, riid))
2007 *pclsid = registered_psclsid->clsid;
2008 LeaveCriticalSection(&apt->cs);
2012 LeaveCriticalSection(&apt->cs);
2014 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2015 strcpyW(path, wszInterface);
2016 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2017 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2019 /* Open the key.. */
2020 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
2022 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2023 return REGDB_E_IIDNOTREG;
2026 /* ... Once we have the key, query the registry to get the
2027 value of CLSID as a string, and convert it into a
2028 proper CLSID structure to be passed back to the app */
2029 len = sizeof(value);
2030 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
2033 return REGDB_E_IIDNOTREG;
2037 /* We have the CLSID we want back from the registry as a string, so
2038 let's convert it into a CLSID structure */
2039 if (CLSIDFromString(value, pclsid) != NOERROR)
2040 return REGDB_E_IIDNOTREG;
2042 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2046 /*****************************************************************************
2047 * CoRegisterPSClsid [OLE32.@]
2049 * Register a proxy/stub CLSID for the given interface in the current process
2053 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2054 * rclsid [I] CLSID of the proxy/stub.
2058 * Failure: E_OUTOFMEMORY
2062 * This function does not add anything to the registry and the effects are
2063 * limited to the lifetime of the current process.
2068 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2070 APARTMENT *apt = COM_CurrentApt();
2071 struct registered_psclsid *registered_psclsid;
2073 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2077 ERR("apartment not initialised\n");
2078 return CO_E_NOTINITIALIZED;
2081 EnterCriticalSection(&apt->cs);
2083 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2084 if (IsEqualIID(®istered_psclsid->iid, riid))
2086 registered_psclsid->clsid = *rclsid;
2087 LeaveCriticalSection(&apt->cs);
2091 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2092 if (!registered_psclsid)
2094 LeaveCriticalSection(&apt->cs);
2095 return E_OUTOFMEMORY;
2098 registered_psclsid->iid = *riid;
2099 registered_psclsid->clsid = *rclsid;
2100 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
2102 LeaveCriticalSection(&apt->cs);
2109 * COM_GetRegisteredClassObject
2111 * This internal method is used to scan the registered class list to
2112 * find a class object.
2115 * rclsid Class ID of the class to find.
2116 * dwClsContext Class context to match.
2117 * ppv [out] returns a pointer to the class object. Complying
2118 * to normal COM usage, this method will increase the
2119 * reference count on this object.
2121 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2122 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2124 HRESULT hr = S_FALSE;
2125 RegisteredClass *curClass;
2127 EnterCriticalSection( &csRegisteredClassList );
2129 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2132 * Check if we have a match on the class ID and context.
2134 if ((apt->oxid == curClass->apartment_id) &&
2135 (dwClsContext & curClass->runContext) &&
2136 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2139 * We have a match, return the pointer to the class object.
2141 *ppUnk = curClass->classObject;
2143 IUnknown_AddRef(curClass->classObject);
2150 LeaveCriticalSection( &csRegisteredClassList );
2155 /******************************************************************************
2156 * CoRegisterClassObject [OLE32.@]
2158 * Registers the class object for a given class ID. Servers housed in EXE
2159 * files use this method instead of exporting DllGetClassObject to allow
2160 * other code to connect to their objects.
2163 * rclsid [I] CLSID of the object to register.
2164 * pUnk [I] IUnknown of the object.
2165 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2166 * flags [I] REGCLS flags indicating how connections are made.
2167 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2171 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2172 * CO_E_OBJISREG if the object is already registered. We should not return this.
2175 * CoRevokeClassObject, CoGetClassObject
2178 * In-process objects are only registered for the current apartment.
2179 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2180 * in other apartments.
2183 * MSDN claims that multiple interface registrations are legal, but we
2184 * can't do that with our current implementation.
2186 HRESULT WINAPI CoRegisterClassObject(
2191 LPDWORD lpdwRegister)
2193 static LONG next_cookie;
2194 RegisteredClass* newClass;
2195 LPUNKNOWN foundObject;
2199 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2200 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2202 if ( (lpdwRegister==0) || (pUnk==0) )
2203 return E_INVALIDARG;
2205 apt = COM_CurrentApt();
2208 ERR("COM was not initialized\n");
2209 return CO_E_NOTINITIALIZED;
2214 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2215 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2216 if (flags & REGCLS_MULTIPLEUSE)
2217 dwClsContext |= CLSCTX_INPROC_SERVER;
2220 * First, check if the class is already registered.
2221 * If it is, this should cause an error.
2223 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2225 if (flags & REGCLS_MULTIPLEUSE) {
2226 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2227 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2228 IUnknown_Release(foundObject);
2231 IUnknown_Release(foundObject);
2232 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2233 return CO_E_OBJISREG;
2236 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2237 if ( newClass == NULL )
2238 return E_OUTOFMEMORY;
2240 newClass->classIdentifier = *rclsid;
2241 newClass->apartment_id = apt->oxid;
2242 newClass->runContext = dwClsContext;
2243 newClass->connectFlags = flags;
2244 newClass->pMarshaledData = NULL;
2245 newClass->RpcRegistration = NULL;
2247 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2248 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2251 * Since we're making a copy of the object pointer, we have to increase its
2254 newClass->classObject = pUnk;
2255 IUnknown_AddRef(newClass->classObject);
2257 EnterCriticalSection( &csRegisteredClassList );
2258 list_add_tail(&RegisteredClassList, &newClass->entry);
2259 LeaveCriticalSection( &csRegisteredClassList );
2261 *lpdwRegister = newClass->dwCookie;
2263 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2264 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2266 FIXME("Failed to create stream on hglobal, %x\n", hr);
2269 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
2270 newClass->classObject, MSHCTX_LOCAL, NULL,
2271 MSHLFLAGS_TABLESTRONG);
2273 FIXME("CoMarshalInterface failed, %x!\n",hr);
2277 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2278 newClass->pMarshaledData,
2279 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2280 &newClass->RpcRegistration);
2285 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2287 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2290 DWORD dwLength = len * sizeof(WCHAR);
2292 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2293 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2297 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2298 REFCLSID rclsid, REFIID riid,
2299 BOOL hostifnecessary, void **ppv)
2301 WCHAR dllpath[MAX_PATH+1];
2302 BOOL apartment_threaded;
2304 if (hostifnecessary)
2306 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2307 static const WCHAR wszFree[] = {'F','r','e','e',0};
2308 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2309 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2311 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2313 if (!strcmpiW(threading_model, wszApartment))
2315 apartment_threaded = TRUE;
2316 if (apt->multi_threaded)
2317 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2320 else if (!strcmpiW(threading_model, wszFree))
2322 apartment_threaded = FALSE;
2323 if (!apt->multi_threaded)
2324 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2326 /* everything except "Apartment", "Free" and "Both" */
2327 else if (strcmpiW(threading_model, wszBoth))
2329 apartment_threaded = TRUE;
2330 /* everything else is main-threaded */
2331 if (threading_model[0])
2332 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2333 debugstr_w(threading_model), debugstr_guid(rclsid));
2335 if (apt->multi_threaded || !apt->main)
2336 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2339 apartment_threaded = FALSE;
2342 apartment_threaded = !apt->multi_threaded;
2344 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2346 /* failure: CLSID is not found in registry */
2347 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2348 return REGDB_E_CLASSNOTREG;
2351 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2355 /***********************************************************************
2356 * CoGetClassObject [OLE32.@]
2358 * Creates an object of the specified class.
2361 * rclsid [I] Class ID to create an instance of.
2362 * dwClsContext [I] Flags to restrict the location of the created instance.
2363 * pServerInfo [I] Optional. Details for connecting to a remote server.
2364 * iid [I] The ID of the interface of the instance to return.
2365 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2369 * Failure: HRESULT code.
2372 * The dwClsContext parameter can be one or more of the following:
2373 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2374 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2375 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2376 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2379 * CoCreateInstance()
2381 HRESULT WINAPI CoGetClassObject(
2382 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2383 REFIID iid, LPVOID *ppv)
2385 LPUNKNOWN regClassObject;
2386 HRESULT hres = E_UNEXPECTED;
2388 BOOL release_apt = FALSE;
2390 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2393 return E_INVALIDARG;
2397 if (!(apt = COM_CurrentApt()))
2399 if (!(apt = apartment_find_multi_threaded()))
2401 ERR("apartment not initialised\n");
2402 return CO_E_NOTINITIALIZED;
2408 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2409 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2413 * First, try and see if we can't match the class ID with one of the
2414 * registered classes.
2416 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2419 /* Get the required interface from the retrieved pointer. */
2420 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2423 * Since QI got another reference on the pointer, we want to release the
2424 * one we already have. If QI was unsuccessful, this will release the object. This
2425 * is good since we are not returning it in the "out" parameter.
2427 IUnknown_Release(regClassObject);
2428 if (release_apt) apartment_release(apt);
2432 /* First try in-process server */
2433 if (CLSCTX_INPROC_SERVER & dwClsContext)
2435 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2438 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2440 if (release_apt) apartment_release(apt);
2441 return FTMarshalCF_Create(iid, ppv);
2444 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2447 if (hres == REGDB_E_CLASSNOTREG)
2448 ERR("class %s not registered\n", debugstr_guid(rclsid));
2449 else if (hres == REGDB_E_KEYMISSING)
2451 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2452 hres = REGDB_E_CLASSNOTREG;
2456 if (SUCCEEDED(hres))
2458 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2459 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2463 /* return if we got a class, otherwise fall through to one of the
2465 if (SUCCEEDED(hres))
2467 if (release_apt) apartment_release(apt);
2472 /* Next try in-process handler */
2473 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2475 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2478 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2481 if (hres == REGDB_E_CLASSNOTREG)
2482 ERR("class %s not registered\n", debugstr_guid(rclsid));
2483 else if (hres == REGDB_E_KEYMISSING)
2485 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2486 hres = REGDB_E_CLASSNOTREG;
2490 if (SUCCEEDED(hres))
2492 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2493 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2497 /* return if we got a class, otherwise fall through to one of the
2499 if (SUCCEEDED(hres))
2501 if (release_apt) apartment_release(apt);
2505 if (release_apt) apartment_release(apt);
2507 /* Next try out of process */
2508 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2510 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2511 if (SUCCEEDED(hres))
2515 /* Finally try remote: this requires networked DCOM (a lot of work) */
2516 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2518 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2519 hres = REGDB_E_CLASSNOTREG;
2523 ERR("no class object %s could be created for context 0x%x\n",
2524 debugstr_guid(rclsid), dwClsContext);
2528 /***********************************************************************
2529 * CoResumeClassObjects (OLE32.@)
2531 * Resumes all class objects registered with REGCLS_SUSPENDED.
2535 * Failure: HRESULT code.
2537 HRESULT WINAPI CoResumeClassObjects(void)
2543 /***********************************************************************
2544 * CoCreateInstance [OLE32.@]
2546 * Creates an instance of the specified class.
2549 * rclsid [I] Class ID to create an instance of.
2550 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2551 * dwClsContext [I] Flags to restrict the location of the created instance.
2552 * iid [I] The ID of the interface of the instance to return.
2553 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2557 * Failure: HRESULT code.
2560 * The dwClsContext parameter can be one or more of the following:
2561 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2562 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2563 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2564 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2566 * Aggregation is the concept of deferring the IUnknown of an object to another
2567 * object. This allows a separate object to behave as though it was part of
2568 * the object and to allow this the pUnkOuter parameter can be set. Note that
2569 * not all objects support having an outer of unknown.
2572 * CoGetClassObject()
2574 HRESULT WINAPI CoCreateInstance(
2576 LPUNKNOWN pUnkOuter,
2582 LPCLASSFACTORY lpclf = 0;
2585 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2586 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2595 * Initialize the "out" parameter
2599 if (!(apt = COM_CurrentApt()))
2601 if (!(apt = apartment_find_multi_threaded()))
2603 ERR("apartment not initialised\n");
2604 return CO_E_NOTINITIALIZED;
2606 apartment_release(apt);
2610 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2611 * Rather than create a class factory, we can just check for it here
2613 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2614 if (StdGlobalInterfaceTableInstance == NULL)
2615 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2616 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2617 if (hres) return hres;
2619 TRACE("Retrieved GIT (%p)\n", *ppv);
2623 if (IsEqualCLSID(rclsid, &CLSID_ManualResetEvent))
2624 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
2627 * Get a class factory to construct the object we want.
2629 hres = CoGetClassObject(rclsid,
2639 * Create the object and don't forget to release the factory
2641 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2642 IClassFactory_Release(lpclf);
2645 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2646 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2648 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2654 /***********************************************************************
2655 * CoCreateInstanceEx [OLE32.@]
2657 HRESULT WINAPI CoCreateInstanceEx(
2659 LPUNKNOWN pUnkOuter,
2661 COSERVERINFO* pServerInfo,
2665 IUnknown* pUnk = NULL;
2668 ULONG successCount = 0;
2673 if ( (cmq==0) || (pResults==NULL))
2674 return E_INVALIDARG;
2676 if (pServerInfo!=NULL)
2677 FIXME("() non-NULL pServerInfo not supported!\n");
2680 * Initialize all the "out" parameters.
2682 for (index = 0; index < cmq; index++)
2684 pResults[index].pItf = NULL;
2685 pResults[index].hr = E_NOINTERFACE;
2689 * Get the object and get its IUnknown pointer.
2691 hr = CoCreateInstance(rclsid,
2701 * Then, query for all the interfaces requested.
2703 for (index = 0; index < cmq; index++)
2705 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2706 pResults[index].pIID,
2707 (VOID**)&(pResults[index].pItf));
2709 if (pResults[index].hr == S_OK)
2714 * Release our temporary unknown pointer.
2716 IUnknown_Release(pUnk);
2718 if (successCount == 0)
2719 return E_NOINTERFACE;
2721 if (successCount!=cmq)
2722 return CO_S_NOTALLINTERFACES;
2727 /***********************************************************************
2728 * CoLoadLibrary (OLE32.@)
2733 * lpszLibName [I] Path to library.
2734 * bAutoFree [I] Whether the library should automatically be freed.
2737 * Success: Handle to loaded library.
2741 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2743 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2745 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2747 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2750 /***********************************************************************
2751 * CoFreeLibrary [OLE32.@]
2753 * Unloads a library from memory.
2756 * hLibrary [I] Handle to library to unload.
2762 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2764 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2766 FreeLibrary(hLibrary);
2770 /***********************************************************************
2771 * CoFreeAllLibraries [OLE32.@]
2773 * Function for backwards compatibility only. Does nothing.
2779 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2781 void WINAPI CoFreeAllLibraries(void)
2786 /***********************************************************************
2787 * CoFreeUnusedLibrariesEx [OLE32.@]
2789 * Frees any previously unused libraries whose delay has expired and marks
2790 * currently unused libraries for unloading. Unused are identified as those that
2791 * return S_OK from their DllCanUnloadNow function.
2794 * dwUnloadDelay [I] Unload delay in milliseconds.
2795 * dwReserved [I] Reserved. Set to 0.
2801 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2803 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2805 struct apartment *apt = COM_CurrentApt();
2808 ERR("apartment not initialised\n");
2812 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2815 /***********************************************************************
2816 * CoFreeUnusedLibraries [OLE32.@]
2818 * Frees any unused libraries. Unused are identified as those that return
2819 * S_OK from their DllCanUnloadNow function.
2825 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2827 void WINAPI CoFreeUnusedLibraries(void)
2829 CoFreeUnusedLibrariesEx(INFINITE, 0);
2832 /***********************************************************************
2833 * CoFileTimeNow [OLE32.@]
2835 * Retrieves the current time in FILETIME format.
2838 * lpFileTime [O] The current time.
2843 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2845 GetSystemTimeAsFileTime( lpFileTime );
2849 /******************************************************************************
2850 * CoLockObjectExternal [OLE32.@]
2852 * Increments or decrements the external reference count of a stub object.
2855 * pUnk [I] Stub object.
2856 * fLock [I] If TRUE then increments the external ref-count,
2857 * otherwise decrements.
2858 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2859 * calling CoDisconnectObject.
2863 * Failure: HRESULT code.
2866 * If fLock is TRUE and an object is passed in that doesn't have a stub
2867 * manager then a new stub manager is created for the object.
2869 HRESULT WINAPI CoLockObjectExternal(
2872 BOOL fLastUnlockReleases)
2874 struct stub_manager *stubmgr;
2875 struct apartment *apt;
2877 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2878 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2880 apt = COM_CurrentApt();
2881 if (!apt) return CO_E_NOTINITIALIZED;
2883 stubmgr = get_stub_manager_from_object(apt, pUnk);
2888 stub_manager_ext_addref(stubmgr, 1, FALSE);
2890 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2892 stub_manager_int_release(stubmgr);
2898 stubmgr = new_stub_manager(apt, pUnk);
2902 stub_manager_ext_addref(stubmgr, 1, FALSE);
2903 stub_manager_int_release(stubmgr);
2910 WARN("stub object not found %p\n", pUnk);
2911 /* Note: native is pretty broken here because it just silently
2912 * fails, without returning an appropriate error code, making apps
2913 * think that the object was disconnected, when it actually wasn't */
2918 /***********************************************************************
2919 * CoInitializeWOW (OLE32.@)
2921 * WOW equivalent of CoInitialize?
2930 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2932 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2936 /***********************************************************************
2937 * CoGetState [OLE32.@]
2939 * Retrieves the thread state object previously stored by CoSetState().
2942 * ppv [I] Address where pointer to object will be stored.
2946 * Failure: E_OUTOFMEMORY.
2949 * Crashes on all invalid ppv addresses, including NULL.
2950 * If the function returns a non-NULL object then the caller must release its
2951 * reference on the object when the object is no longer required.
2956 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2958 struct oletls *info = COM_CurrentInfo();
2959 if (!info) return E_OUTOFMEMORY;
2965 IUnknown_AddRef(info->state);
2967 TRACE("apt->state=%p\n", info->state);
2973 /***********************************************************************
2974 * CoSetState [OLE32.@]
2976 * Sets the thread state object.
2979 * pv [I] Pointer to state object to be stored.
2982 * The system keeps a reference on the object while the object stored.
2986 * Failure: E_OUTOFMEMORY.
2988 HRESULT WINAPI CoSetState(IUnknown * pv)
2990 struct oletls *info = COM_CurrentInfo();
2991 if (!info) return E_OUTOFMEMORY;
2993 if (pv) IUnknown_AddRef(pv);
2997 TRACE("-- release %p now\n", info->state);
2998 IUnknown_Release(info->state);
3007 /******************************************************************************
3008 * CoTreatAsClass [OLE32.@]
3010 * Sets the TreatAs value of a class.
3013 * clsidOld [I] Class to set TreatAs value on.
3014 * clsidNew [I] The class the clsidOld should be treated as.
3018 * Failure: HRESULT code.
3023 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3025 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3026 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3028 WCHAR szClsidNew[CHARS_IN_GUID];
3030 WCHAR auto_treat_as[CHARS_IN_GUID];
3031 LONG auto_treat_as_size = sizeof(auto_treat_as);
3034 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3037 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
3039 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3040 CLSIDFromString(auto_treat_as, &id) == S_OK)
3042 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3044 res = REGDB_E_WRITEREGDB;
3050 RegDeleteKeyW(hkey, wszTreatAs);
3054 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
3055 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
3057 res = REGDB_E_WRITEREGDB;
3062 if (hkey) RegCloseKey(hkey);
3066 /******************************************************************************
3067 * CoGetTreatAsClass [OLE32.@]
3069 * Gets the TreatAs value of a class.
3072 * clsidOld [I] Class to get the TreatAs value of.
3073 * clsidNew [I] The class the clsidOld should be treated as.
3077 * Failure: HRESULT code.
3082 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3084 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3086 WCHAR szClsidNew[CHARS_IN_GUID];
3088 LONG len = sizeof(szClsidNew);
3090 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3091 *clsidNew = *clsidOld; /* copy over old value */
3093 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3099 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3104 res = CLSIDFromString(szClsidNew,clsidNew);
3106 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3108 if (hkey) RegCloseKey(hkey);
3112 /******************************************************************************
3113 * CoGetCurrentProcess [OLE32.@]
3115 * Gets the current process ID.
3118 * The current process ID.
3121 * Is DWORD really the correct return type for this function?
3123 DWORD WINAPI CoGetCurrentProcess(void)
3125 return GetCurrentProcessId();
3128 /******************************************************************************
3129 * CoRegisterMessageFilter [OLE32.@]
3131 * Registers a message filter.
3134 * lpMessageFilter [I] Pointer to interface.
3135 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3139 * Failure: HRESULT code.
3142 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3143 * lpMessageFilter removes the message filter.
3145 * If lplpMessageFilter is not NULL the previous message filter will be
3146 * returned in the memory pointer to this parameter and the caller is
3147 * responsible for releasing the object.
3149 * The current thread be in an apartment otherwise the function will crash.
3151 HRESULT WINAPI CoRegisterMessageFilter(
3152 LPMESSAGEFILTER lpMessageFilter,
3153 LPMESSAGEFILTER *lplpMessageFilter)
3155 struct apartment *apt;
3156 IMessageFilter *lpOldMessageFilter;
3158 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3160 apt = COM_CurrentApt();
3162 /* can't set a message filter in a multi-threaded apartment */
3163 if (!apt || apt->multi_threaded)
3165 WARN("can't set message filter in MTA or uninitialized apt\n");
3166 return CO_E_NOT_SUPPORTED;
3169 if (lpMessageFilter)
3170 IMessageFilter_AddRef(lpMessageFilter);
3172 EnterCriticalSection(&apt->cs);
3174 lpOldMessageFilter = apt->filter;
3175 apt->filter = lpMessageFilter;
3177 LeaveCriticalSection(&apt->cs);
3179 if (lplpMessageFilter)
3180 *lplpMessageFilter = lpOldMessageFilter;
3181 else if (lpOldMessageFilter)
3182 IMessageFilter_Release(lpOldMessageFilter);
3187 /***********************************************************************
3188 * CoIsOle1Class [OLE32.@]
3190 * Determines whether the specified class an OLE v1 class.
3193 * clsid [I] Class to test.
3196 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3198 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3200 FIXME("%s\n", debugstr_guid(clsid));
3204 /***********************************************************************
3205 * IsEqualGUID [OLE32.@]
3207 * Compares two Unique Identifiers.
3210 * rguid1 [I] The first GUID to compare.
3211 * rguid2 [I] The other GUID to compare.
3217 BOOL WINAPI IsEqualGUID(
3221 return !memcmp(rguid1,rguid2,sizeof(GUID));
3224 /***********************************************************************
3225 * CoInitializeSecurity [OLE32.@]
3227 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3228 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3229 void* pReserved1, DWORD dwAuthnLevel,
3230 DWORD dwImpLevel, void* pReserved2,
3231 DWORD dwCapabilities, void* pReserved3)
3233 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3234 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3235 dwCapabilities, pReserved3);
3239 /***********************************************************************
3240 * CoSuspendClassObjects [OLE32.@]
3242 * Suspends all registered class objects to prevent further requests coming in
3243 * for those objects.
3247 * Failure: HRESULT code.
3249 HRESULT WINAPI CoSuspendClassObjects(void)
3255 /***********************************************************************
3256 * CoAddRefServerProcess [OLE32.@]
3258 * Helper function for incrementing the reference count of a local-server
3262 * New reference count.
3265 * CoReleaseServerProcess().
3267 ULONG WINAPI CoAddRefServerProcess(void)
3273 EnterCriticalSection(&csRegisteredClassList);
3274 refs = ++s_COMServerProcessReferences;
3275 LeaveCriticalSection(&csRegisteredClassList);
3277 TRACE("refs before: %d\n", refs - 1);
3282 /***********************************************************************
3283 * CoReleaseServerProcess [OLE32.@]
3285 * Helper function for decrementing the reference count of a local-server
3289 * New reference count.
3292 * When reference count reaches 0, this function suspends all registered
3293 * classes so no new connections are accepted.
3296 * CoAddRefServerProcess(), CoSuspendClassObjects().
3298 ULONG WINAPI CoReleaseServerProcess(void)
3304 EnterCriticalSection(&csRegisteredClassList);
3306 refs = --s_COMServerProcessReferences;
3307 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3309 LeaveCriticalSection(&csRegisteredClassList);
3311 TRACE("refs after: %d\n", refs);
3316 /***********************************************************************
3317 * CoIsHandlerConnected [OLE32.@]
3319 * Determines whether a proxy is connected to a remote stub.
3322 * pUnk [I] Pointer to object that may or may not be connected.
3325 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3328 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3330 FIXME("%p\n", pUnk);
3335 /***********************************************************************
3336 * CoAllowSetForegroundWindow [OLE32.@]
3339 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3341 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3345 /***********************************************************************
3346 * CoQueryProxyBlanket [OLE32.@]
3348 * Retrieves the security settings being used by a proxy.
3351 * pProxy [I] Pointer to the proxy object.
3352 * pAuthnSvc [O] The type of authentication service.
3353 * pAuthzSvc [O] The type of authorization service.
3354 * ppServerPrincName [O] Optional. The server prinicple name.
3355 * pAuthnLevel [O] The authentication level.
3356 * pImpLevel [O] The impersonation level.
3357 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3358 * pCapabilities [O] Flags affecting the security behaviour.
3362 * Failure: HRESULT code.
3365 * CoCopyProxy, CoSetProxyBlanket.
3367 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3368 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3369 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3371 IClientSecurity *pCliSec;
3374 TRACE("%p\n", pProxy);
3376 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3379 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3380 pAuthzSvc, ppServerPrincName,
3381 pAuthnLevel, pImpLevel, ppAuthInfo,
3383 IClientSecurity_Release(pCliSec);
3386 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3390 /***********************************************************************
3391 * CoSetProxyBlanket [OLE32.@]
3393 * Sets the security settings for a proxy.
3396 * pProxy [I] Pointer to the proxy object.
3397 * AuthnSvc [I] The type of authentication service.
3398 * AuthzSvc [I] The type of authorization service.
3399 * pServerPrincName [I] The server prinicple name.
3400 * AuthnLevel [I] The authentication level.
3401 * ImpLevel [I] The impersonation level.
3402 * pAuthInfo [I] Information specific to the authorization/authentication service.
3403 * Capabilities [I] Flags affecting the security behaviour.
3407 * Failure: HRESULT code.
3410 * CoQueryProxyBlanket, CoCopyProxy.
3412 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3413 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3414 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3416 IClientSecurity *pCliSec;
3419 TRACE("%p\n", pProxy);
3421 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3424 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3425 AuthzSvc, pServerPrincName,
3426 AuthnLevel, ImpLevel, pAuthInfo,
3428 IClientSecurity_Release(pCliSec);
3431 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3435 /***********************************************************************
3436 * CoCopyProxy [OLE32.@]
3441 * pProxy [I] Pointer to the proxy object.
3442 * ppCopy [O] Copy of the proxy.
3446 * Failure: HRESULT code.
3449 * CoQueryProxyBlanket, CoSetProxyBlanket.
3451 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3453 IClientSecurity *pCliSec;
3456 TRACE("%p\n", pProxy);
3458 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3461 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3462 IClientSecurity_Release(pCliSec);
3465 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3470 /***********************************************************************
3471 * CoGetCallContext [OLE32.@]
3473 * Gets the context of the currently executing server call in the current
3477 * riid [I] Context interface to return.
3478 * ppv [O] Pointer to memory that will receive the context on return.
3482 * Failure: HRESULT code.
3484 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3486 struct oletls *info = COM_CurrentInfo();
3488 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3491 return E_OUTOFMEMORY;
3493 if (!info->call_state)
3494 return RPC_E_CALL_COMPLETE;
3496 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3499 /***********************************************************************
3500 * CoSwitchCallContext [OLE32.@]
3502 * Switches the context of the currently executing server call in the current
3506 * pObject [I] Pointer to new context object
3507 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3511 * Failure: HRESULT code.
3513 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3515 struct oletls *info = COM_CurrentInfo();
3517 TRACE("(%p, %p)\n", pObject, ppOldObject);
3520 return E_OUTOFMEMORY;
3522 *ppOldObject = info->call_state;
3523 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3528 /***********************************************************************
3529 * CoQueryClientBlanket [OLE32.@]
3531 * Retrieves the authentication information about the client of the currently
3532 * executing server call in the current thread.
3535 * pAuthnSvc [O] Optional. The type of authentication service.
3536 * pAuthzSvc [O] Optional. The type of authorization service.
3537 * pServerPrincName [O] Optional. The server prinicple name.
3538 * pAuthnLevel [O] Optional. The authentication level.
3539 * pImpLevel [O] Optional. The impersonation level.
3540 * pPrivs [O] Optional. Information about the privileges of the client.
3541 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3545 * Failure: HRESULT code.
3548 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3550 HRESULT WINAPI CoQueryClientBlanket(
3553 OLECHAR **pServerPrincName,
3556 RPC_AUTHZ_HANDLE *pPrivs,
3557 DWORD *pCapabilities)
3559 IServerSecurity *pSrvSec;
3562 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3563 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3564 pPrivs, pCapabilities);
3566 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3569 hr = IServerSecurity_QueryBlanket(
3570 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3571 pImpLevel, pPrivs, pCapabilities);
3572 IServerSecurity_Release(pSrvSec);
3578 /***********************************************************************
3579 * CoImpersonateClient [OLE32.@]
3581 * Impersonates the client of the currently executing server call in the
3589 * Failure: HRESULT code.
3592 * If this function fails then the current thread will not be impersonating
3593 * the client and all actions will take place on behalf of the server.
3594 * Therefore, it is important to check the return value from this function.
3597 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3599 HRESULT WINAPI CoImpersonateClient(void)
3601 IServerSecurity *pSrvSec;
3606 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3609 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3610 IServerSecurity_Release(pSrvSec);
3616 /***********************************************************************
3617 * CoRevertToSelf [OLE32.@]
3619 * Ends the impersonation of the client of the currently executing server
3620 * call in the current thread.
3627 * Failure: HRESULT code.
3630 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3632 HRESULT WINAPI CoRevertToSelf(void)
3634 IServerSecurity *pSrvSec;
3639 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3642 hr = IServerSecurity_RevertToSelf(pSrvSec);
3643 IServerSecurity_Release(pSrvSec);
3649 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3651 /* first try to retrieve messages for incoming COM calls to the apartment window */
3652 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3653 /* next retrieve other messages necessary for the app to remain responsive */
3654 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3655 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3658 /***********************************************************************
3659 * CoWaitForMultipleHandles [OLE32.@]
3661 * Waits for one or more handles to become signaled.
3664 * dwFlags [I] Flags. See notes.
3665 * dwTimeout [I] Timeout in milliseconds.
3666 * cHandles [I] Number of handles pointed to by pHandles.
3667 * pHandles [I] Handles to wait for.
3668 * lpdwindex [O] Index of handle that was signaled.
3672 * Failure: RPC_S_CALLPENDING on timeout.
3676 * The dwFlags parameter can be zero or more of the following:
3677 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3678 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3681 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3683 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3684 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3687 DWORD start_time = GetTickCount();
3688 APARTMENT *apt = COM_CurrentApt();
3689 BOOL message_loop = apt && !apt->multi_threaded;
3691 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3692 pHandles, lpdwindex);
3696 DWORD now = GetTickCount();
3699 if (now - start_time > dwTimeout)
3701 hr = RPC_S_CALLPENDING;
3707 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3708 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3710 TRACE("waiting for rpc completion or window message\n");
3712 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3713 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3714 QS_ALLINPUT, wait_flags);
3716 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3720 /* call message filter */
3722 if (COM_CurrentApt()->filter)
3724 PENDINGTYPE pendingtype =
3725 COM_CurrentInfo()->pending_call_count_server ?
3726 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3727 DWORD be_handled = IMessageFilter_MessagePending(
3728 COM_CurrentApt()->filter, 0 /* FIXME */,
3729 now - start_time, pendingtype);
3730 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3733 case PENDINGMSG_CANCELCALL:
3734 WARN("call canceled\n");
3735 hr = RPC_E_CALL_CANCELED;
3737 case PENDINGMSG_WAITNOPROCESS:
3738 case PENDINGMSG_WAITDEFPROCESS:
3740 /* FIXME: MSDN is very vague about the difference
3741 * between WAITNOPROCESS and WAITDEFPROCESS - there
3742 * appears to be none, so it is possibly a left-over
3743 * from the 16-bit world. */
3748 /* note: using "if" here instead of "while" might seem less
3749 * efficient, but only if we are optimising for quick delivery
3750 * of pending messages, rather than quick completion of the
3752 if (COM_PeekMessage(apt, &msg))
3754 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3755 TranslateMessage(&msg);
3756 DispatchMessageW(&msg);
3757 if (msg.message == WM_QUIT)
3759 TRACE("resending WM_QUIT to outer message loop\n");
3760 PostQuitMessage(msg.wParam);
3761 /* no longer need to process messages */
3762 message_loop = FALSE;
3770 TRACE("waiting for rpc completion\n");
3772 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3773 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3774 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3775 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3781 hr = RPC_S_CALLPENDING;
3784 hr = HRESULT_FROM_WIN32( GetLastError() );
3792 TRACE("-- 0x%08x\n", hr);
3797 /***********************************************************************
3798 * CoGetObject [OLE32.@]
3800 * Gets the object named by converting the name to a moniker and binding to it.
3803 * pszName [I] String representing the object.
3804 * pBindOptions [I] Parameters affecting the binding to the named object.
3805 * riid [I] Interface to bind to on the objecct.
3806 * ppv [O] On output, the interface riid of the object represented
3811 * Failure: HRESULT code.
3814 * MkParseDisplayName.
3816 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3817 REFIID riid, void **ppv)
3824 hr = CreateBindCtx(0, &pbc);
3828 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3835 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3838 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3839 IMoniker_Release(pmk);
3843 IBindCtx_Release(pbc);
3848 /***********************************************************************
3849 * CoRegisterChannelHook [OLE32.@]
3851 * Registers a process-wide hook that is called during ORPC calls.
3854 * guidExtension [I] GUID of the channel hook to register.
3855 * pChannelHook [I] Channel hook object to register.
3859 * Failure: HRESULT code.
3861 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3863 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3865 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3868 typedef struct Context
3870 IComThreadingInfo IComThreadingInfo_iface;
3871 IContextCallback IContextCallback_iface;
3872 IObjContext IObjContext_iface;
3877 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3879 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
3882 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3884 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
3887 static inline Context *impl_from_IObjContext( IObjContext *iface )
3889 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
3892 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3896 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3897 IsEqualIID(riid, &IID_IUnknown))
3899 *ppv = &iface->IComThreadingInfo_iface;
3901 else if (IsEqualIID(riid, &IID_IContextCallback))
3903 *ppv = &iface->IContextCallback_iface;
3905 else if (IsEqualIID(riid, &IID_IObjContext))
3907 *ppv = &iface->IObjContext_iface;
3912 IUnknown_AddRef((IUnknown*)*ppv);
3916 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3917 return E_NOINTERFACE;
3920 static ULONG Context_AddRef(Context *This)
3922 return InterlockedIncrement(&This->refs);
3925 static ULONG Context_Release(Context *This)
3927 ULONG refs = InterlockedDecrement(&This->refs);
3929 HeapFree(GetProcessHeap(), 0, This);
3933 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3935 Context *This = impl_from_IComThreadingInfo(iface);
3936 return Context_QueryInterface(This, riid, ppv);
3939 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3941 Context *This = impl_from_IComThreadingInfo(iface);
3942 return Context_AddRef(This);
3945 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3947 Context *This = impl_from_IComThreadingInfo(iface);
3948 return Context_Release(This);
3951 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3953 Context *This = impl_from_IComThreadingInfo(iface);
3955 TRACE("(%p)\n", apttype);
3957 *apttype = This->apttype;
3961 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3963 Context *This = impl_from_IComThreadingInfo(iface);
3965 TRACE("(%p)\n", thdtype);
3967 switch (This->apttype)
3970 case APTTYPE_MAINSTA:
3971 *thdtype = THDTYPE_PROCESSMESSAGES;
3974 *thdtype = THDTYPE_BLOCKMESSAGES;
3980 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3982 FIXME("(%p): stub\n", logical_thread_id);
3986 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3988 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3992 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3994 Context_CTI_QueryInterface,
3996 Context_CTI_Release,
3997 Context_CTI_GetCurrentApartmentType,
3998 Context_CTI_GetCurrentThreadType,
3999 Context_CTI_GetCurrentLogicalThreadId,
4000 Context_CTI_SetCurrentLogicalThreadId
4003 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4005 Context *This = impl_from_IContextCallback(iface);
4006 return Context_QueryInterface(This, riid, ppv);
4009 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4011 Context *This = impl_from_IContextCallback(iface);
4012 return Context_AddRef(This);
4015 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4017 Context *This = impl_from_IContextCallback(iface);
4018 return Context_Release(This);
4021 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4022 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4024 Context *This = impl_from_IContextCallback(iface);
4026 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4030 static const IContextCallbackVtbl Context_Callback_Vtbl =
4032 Context_CC_QueryInterface,
4035 Context_CC_ContextCallback
4038 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4040 Context *This = impl_from_IObjContext(iface);
4041 return Context_QueryInterface(This, riid, ppv);
4044 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4046 Context *This = impl_from_IObjContext(iface);
4047 return Context_AddRef(This);
4050 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4052 Context *This = impl_from_IObjContext(iface);
4053 return Context_Release(This);
4056 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4058 Context *This = impl_from_IObjContext(iface);
4060 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4064 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4066 Context *This = impl_from_IObjContext(iface);
4068 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4072 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4074 Context *This = impl_from_IObjContext(iface);
4076 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4080 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4082 Context *This = impl_from_IObjContext(iface);
4084 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4088 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4090 Context *This = impl_from_IObjContext(iface);
4091 FIXME("(%p/%p)\n", This, iface);
4094 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4096 Context *This = impl_from_IObjContext(iface);
4097 FIXME("(%p/%p)\n", This, iface);
4100 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4102 Context *This = impl_from_IObjContext(iface);
4103 FIXME("(%p/%p)\n", This, iface);
4106 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4108 Context *This = impl_from_IObjContext(iface);
4109 FIXME("(%p/%p)\n", This, iface);
4112 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4114 Context *This = impl_from_IObjContext(iface);
4115 FIXME("(%p/%p)\n", This, iface);
4118 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4120 Context *This = impl_from_IObjContext(iface);
4121 FIXME("(%p/%p)\n", This, iface);
4124 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4126 Context *This = impl_from_IObjContext(iface);
4127 FIXME("(%p/%p)\n", This, iface);
4130 static const IObjContextVtbl Context_Object_Vtbl =
4132 Context_OC_QueryInterface,
4135 Context_OC_SetProperty,
4136 Context_OC_RemoveProperty,
4137 Context_OC_GetProperty,
4138 Context_OC_EnumContextProps,
4139 Context_OC_Reserved1,
4140 Context_OC_Reserved2,
4141 Context_OC_Reserved3,
4142 Context_OC_Reserved4,
4143 Context_OC_Reserved5,
4144 Context_OC_Reserved6,
4145 Context_OC_Reserved7
4148 /***********************************************************************
4149 * CoGetObjectContext [OLE32.@]
4151 * Retrieves an object associated with the current context (i.e. apartment).
4154 * riid [I] ID of the interface of the object to retrieve.
4155 * ppv [O] Address where object will be stored on return.
4159 * Failure: HRESULT code.
4161 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4163 APARTMENT *apt = COM_CurrentApt();
4167 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4172 if (!(apt = apartment_find_multi_threaded()))
4174 ERR("apartment not initialised\n");
4175 return CO_E_NOTINITIALIZED;
4177 apartment_release(apt);
4180 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4182 return E_OUTOFMEMORY;
4184 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4185 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4186 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4188 if (apt->multi_threaded)
4189 context->apttype = APTTYPE_MTA;
4191 context->apttype = APTTYPE_MAINSTA;
4193 context->apttype = APTTYPE_STA;
4195 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4196 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4202 /***********************************************************************
4203 * CoGetContextToken [OLE32.@]
4205 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4207 struct oletls *info = COM_CurrentInfo();
4209 TRACE("(%p)\n", token);
4212 return E_OUTOFMEMORY;
4217 if (!(apt = apartment_find_multi_threaded()))
4219 ERR("apartment not initialised\n");
4220 return CO_E_NOTINITIALIZED;
4222 apartment_release(apt);
4228 if (!info->context_token)
4233 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4234 if (FAILED(hr)) return hr;
4235 info->context_token = ctx;
4238 *token = (ULONG_PTR)info->context_token;
4239 TRACE("apt->context_token=%p\n", info->context_token);
4244 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4246 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4250 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4251 if (SUCCEEDED(hres))
4253 WCHAR dllpath[MAX_PATH+1];
4255 if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4257 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4258 if (!strcmpiW(dllpath, wszOle32))
4261 return HandlerCF_Create(rclsid, riid, ppv);
4265 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4269 return CLASS_E_CLASSNOTAVAILABLE;
4272 /***********************************************************************
4275 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4277 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4280 case DLL_PROCESS_ATTACH:
4281 hProxyDll = hinstDLL;
4282 COMPOBJ_InitProcess();
4285 case DLL_PROCESS_DETACH:
4286 COMPOBJ_UninitProcess();
4287 RPC_UnregisterAllChannelHooks();
4288 COMPOBJ_DllList_Free();
4291 case DLL_THREAD_DETACH:
4298 /***********************************************************************
4299 * DllRegisterServer (OLE32.@)
4301 HRESULT WINAPI DllRegisterServer(void)
4303 return OLE32_DllRegisterServer();
4306 /***********************************************************************
4307 * DllUnregisterServer (OLE32.@)
4309 HRESULT WINAPI DllUnregisterServer(void)
4311 return OLE32_DllUnregisterServer();