4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
37 * - Make all ole interface marshaling use NDR to be wire compatible with
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
62 #include "compobj_private.h"
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
69 HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
71 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
73 /****************************************************************************
74 * This section defines variables internal to the COM module.
76 * TODO: Most of these things will have to be made thread-safe.
79 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
80 DWORD dwClsContext, LPUNKNOWN* ppUnk);
81 static void COM_RevokeAllClasses(const struct apartment *apt);
82 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv);
84 static APARTMENT *MTA; /* protected by csApartment */
85 static APARTMENT *MainApartment; /* the first STA apartment */
86 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
88 static CRITICAL_SECTION csApartment;
89 static CRITICAL_SECTION_DEBUG critsect_debug =
92 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
93 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
95 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
97 struct registered_psclsid
105 * This lock count counts the number of times CoInitialize is called. It is
106 * decreased every time CoUninitialize is called. When it hits 0, the COM
107 * libraries are freed
109 static LONG s_COMLockCount = 0;
110 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
111 static LONG s_COMServerProcessReferences = 0;
114 * This linked list contains the list of registered class objects. These
115 * are mostly used to register the factories for out-of-proc servers of OLE
118 * TODO: Make this data structure aware of inter-process communication. This
119 * means that parts of this will be exported to the Wine Server.
121 typedef struct tagRegisteredClass
124 CLSID classIdentifier;
126 LPUNKNOWN classObject;
130 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
131 void *RpcRegistration;
134 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
136 static CRITICAL_SECTION csRegisteredClassList;
137 static CRITICAL_SECTION_DEBUG class_cs_debug =
139 0, 0, &csRegisteredClassList,
140 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
141 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
143 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
145 /*****************************************************************************
146 * This section contains OpenDllList definitions
148 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
149 * other functions that do LoadLibrary _without_ giving back a HMODULE.
150 * Without this list these handles would never be freed.
152 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
153 * next unload-call but not before 600 sec.
156 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
157 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
159 typedef struct tagOpenDll
164 DllGetClassObjectFunc DllGetClassObject;
165 DllCanUnloadNowFunc DllCanUnloadNow;
169 static struct list openDllList = LIST_INIT(openDllList);
171 static CRITICAL_SECTION csOpenDllList;
172 static CRITICAL_SECTION_DEBUG dll_cs_debug =
174 0, 0, &csOpenDllList,
175 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
176 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
178 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
180 struct apartment_loaded_dll
187 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',' ',
188 '0','x','#','#','#','#','#','#','#','#',' ',0};
189 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
190 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
191 REFCLSID rclsid, REFIID riid, void **ppv);
192 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
194 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
195 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
196 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
198 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
200 static void COMPOBJ_InitProcess( void )
204 /* Dispatching to the correct thread in an apartment is done through
205 * window messages rather than RPC transports. When an interface is
206 * marshalled into another apartment in the same process, a window of the
207 * following class is created. The *caller* of CoMarshalInterface (ie the
208 * application) is responsible for pumping the message loop in that thread.
209 * The WM_USER messages which point to the RPCs are then dispatched to
210 * COM_AptWndProc by the user's code from the apartment in which the interface
213 memset(&wclass, 0, sizeof(wclass));
214 wclass.lpfnWndProc = apartment_wndproc;
215 wclass.hInstance = OLE32_hInstance;
216 wclass.lpszClassName = wszAptWinClass;
217 RegisterClassW(&wclass);
220 static void COMPOBJ_UninitProcess( void )
222 UnregisterClassW(wszAptWinClass, OLE32_hInstance);
225 static void COM_TlsDestroy(void)
227 struct oletls *info = NtCurrentTeb()->ReservedForOle;
230 if (info->apt) apartment_release(info->apt);
231 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
232 if (info->state) IUnknown_Release(info->state);
233 HeapFree(GetProcessHeap(), 0, info);
234 NtCurrentTeb()->ReservedForOle = NULL;
238 /******************************************************************************
242 /* allocates memory and fills in the necessary fields for a new apartment
243 * object. must be called inside apartment cs */
244 static APARTMENT *apartment_construct(DWORD model)
248 TRACE("creating new apartment, model=%d\n", model);
250 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
251 apt->tid = GetCurrentThreadId();
253 list_init(&apt->proxies);
254 list_init(&apt->stubmgrs);
255 list_init(&apt->psclsids);
256 list_init(&apt->loaded_dlls);
259 apt->remunk_exported = FALSE;
261 InitializeCriticalSection(&apt->cs);
262 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
264 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
266 if (apt->multi_threaded)
268 /* FIXME: should be randomly generated by in an RPC call to rpcss */
269 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
273 /* FIXME: should be randomly generated by in an RPC call to rpcss */
274 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
277 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
279 list_add_head(&apts, &apt->entry);
284 /* gets and existing apartment if one exists or otherwise creates an apartment
285 * structure which stores OLE apartment-local information and stores a pointer
286 * to it in the thread-local storage */
287 static APARTMENT *apartment_get_or_create(DWORD model)
289 APARTMENT *apt = COM_CurrentApt();
293 if (model & COINIT_APARTMENTTHREADED)
295 EnterCriticalSection(&csApartment);
297 apt = apartment_construct(model);
302 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
305 LeaveCriticalSection(&csApartment);
309 EnterCriticalSection(&csApartment);
311 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
312 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
316 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
317 apartment_addref(MTA);
320 MTA = apartment_construct(model);
324 LeaveCriticalSection(&csApartment);
326 COM_CurrentInfo()->apt = apt;
332 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
334 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
337 DWORD apartment_addref(struct apartment *apt)
339 DWORD refs = InterlockedIncrement(&apt->refs);
340 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
344 DWORD apartment_release(struct apartment *apt)
348 EnterCriticalSection(&csApartment);
350 ret = InterlockedDecrement(&apt->refs);
351 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
352 /* destruction stuff that needs to happen under csApartment CS */
355 if (apt == MTA) MTA = NULL;
356 else if (apt == MainApartment) MainApartment = NULL;
357 list_remove(&apt->entry);
360 LeaveCriticalSection(&csApartment);
364 struct list *cursor, *cursor2;
366 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
368 /* Release the references to the registered class objects */
369 COM_RevokeAllClasses(apt);
371 /* no locking is needed for this apartment, because no other thread
372 * can access it at this point */
374 apartment_disconnectproxies(apt);
376 if (apt->win) DestroyWindow(apt->win);
377 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
379 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
381 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
382 /* release the implicit reference given by the fact that the
383 * stub has external references (it must do since it is in the
384 * stub manager list in the apartment and all non-apartment users
385 * must have a ref on the apartment and so it cannot be destroyed).
387 stub_manager_int_release(stubmgr);
390 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
392 struct registered_psclsid *registered_psclsid =
393 LIST_ENTRY(cursor, struct registered_psclsid, entry);
395 list_remove(®istered_psclsid->entry);
396 HeapFree(GetProcessHeap(), 0, registered_psclsid);
399 /* if this assert fires, then another thread took a reference to a
400 * stub manager without taking a reference to the containing
401 * apartment, which it must do. */
402 assert(list_empty(&apt->stubmgrs));
404 if (apt->filter) IUnknown_Release(apt->filter);
406 /* free as many unused libraries as possible... */
407 apartment_freeunusedlibraries(apt, 0);
409 /* ... and free the memory for the apartment loaded dll entry and
410 * release the dll list reference without freeing the library for the
412 while ((cursor = list_head(&apt->loaded_dlls)))
414 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
415 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
417 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
420 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
421 DeleteCriticalSection(&apt->cs);
423 HeapFree(GetProcessHeap(), 0, apt);
429 /* The given OXID must be local to this process:
431 * The ref parameter is here mostly to ensure people remember that
432 * they get one, you should normally take a ref for thread safety.
434 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
436 APARTMENT *result = NULL;
439 EnterCriticalSection(&csApartment);
440 LIST_FOR_EACH( cursor, &apts )
442 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
443 if (apt->oxid == oxid)
446 if (ref) apartment_addref(result);
450 LeaveCriticalSection(&csApartment);
455 /* gets the apartment which has a given creator thread ID. The caller must
456 * release the reference from the apartment as soon as the apartment pointer
457 * is no longer required. */
458 APARTMENT *apartment_findfromtid(DWORD tid)
460 APARTMENT *result = NULL;
463 EnterCriticalSection(&csApartment);
464 LIST_FOR_EACH( cursor, &apts )
466 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
470 apartment_addref(result);
474 LeaveCriticalSection(&csApartment);
479 /* gets the main apartment if it exists. The caller must
480 * release the reference from the apartment as soon as the apartment pointer
481 * is no longer required. */
482 static APARTMENT *apartment_findmain(void)
486 EnterCriticalSection(&csApartment);
488 result = MainApartment;
489 if (result) apartment_addref(result);
491 LeaveCriticalSection(&csApartment);
496 struct host_object_params
499 CLSID clsid; /* clsid of object to marshal */
500 IID iid; /* interface to marshal */
501 HANDLE event; /* event signalling when ready for multi-threaded case */
502 HRESULT hr; /* result for multi-threaded case */
503 IStream *stream; /* stream that the object will be marshaled into */
506 static HRESULT apartment_hostobject(struct apartment *apt,
507 const struct host_object_params *params)
511 static const LARGE_INTEGER llZero;
512 WCHAR dllpath[MAX_PATH+1];
514 TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid));
516 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
518 /* failure: CLSID is not found in registry */
519 WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid));
520 return REGDB_E_CLASSNOTREG;
523 hr = apartment_getclassobject(apt, dllpath, ¶ms->clsid, ¶ms->iid, (void **)&object);
527 hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
529 IUnknown_Release(object);
530 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
535 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
540 RPC_ExecuteCall((struct dispatch_params *)lParam);
543 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
545 return DefWindowProcW(hWnd, msg, wParam, lParam);
549 struct host_thread_params
551 COINIT threading_model;
556 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
558 struct host_thread_params *params = p;
561 struct apartment *apt;
565 hr = CoInitializeEx(NULL, params->threading_model);
566 if (FAILED(hr)) return hr;
568 apt = COM_CurrentApt();
569 if (params->threading_model == COINIT_APARTMENTTHREADED)
571 apartment_createwindowifneeded(apt);
572 params->apartment_hwnd = apartment_getwindow(apt);
575 params->apartment_hwnd = NULL;
577 /* force the message queue to be created before signaling parent thread */
578 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
580 SetEvent(params->ready_event);
581 params = NULL; /* can't touch params after here as it may be invalid */
583 while (GetMessageW(&msg, NULL, 0, 0))
585 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
587 struct host_object_params *params = (struct host_object_params *)msg.lParam;
588 params->hr = apartment_hostobject(apt, params);
589 SetEvent(params->event);
593 TranslateMessage(&msg);
594 DispatchMessageW(&msg);
605 static HRESULT apartment_hostobject_in_hostapt(struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
607 struct host_object_params params;
608 HWND apartment_hwnd = NULL;
609 DWORD apartment_tid = 0;
612 if (!multi_threaded && main_apartment)
614 APARTMENT *host_apt = apartment_findmain();
617 apartment_hwnd = apartment_getwindow(host_apt);
618 apartment_release(host_apt);
624 EnterCriticalSection(&apt->cs);
626 if (!apt->host_apt_tid)
628 struct host_thread_params thread_params;
632 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
633 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
634 thread_params.apartment_hwnd = NULL;
635 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
638 CloseHandle(handles[0]);
639 LeaveCriticalSection(&apt->cs);
640 return E_OUTOFMEMORY;
642 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
643 CloseHandle(handles[0]);
644 CloseHandle(handles[1]);
645 if (wait_value == WAIT_OBJECT_0)
646 apt->host_apt_hwnd = thread_params.apartment_hwnd;
649 LeaveCriticalSection(&apt->cs);
650 return E_OUTOFMEMORY;
654 if (multi_threaded || !main_apartment)
656 apartment_hwnd = apt->host_apt_hwnd;
657 apartment_tid = apt->host_apt_tid;
660 LeaveCriticalSection(&apt->cs);
663 /* another thread may have become the main apartment in the time it took
664 * us to create the thread for the host apartment */
665 if (!apartment_hwnd && !multi_threaded && main_apartment)
667 APARTMENT *host_apt = apartment_findmain();
670 apartment_hwnd = apartment_getwindow(host_apt);
671 apartment_release(host_apt);
675 params.hkeydll = hkeydll;
676 params.clsid = *rclsid;
678 hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream);
684 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
685 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms))
689 WaitForSingleObject(params.event, INFINITE);
692 CloseHandle(params.event);
698 ERR("host apartment didn't create window\n");
702 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms);
705 hr = CoUnmarshalInterface(params.stream, riid, ppv);
706 IStream_Release(params.stream);
710 HRESULT apartment_createwindowifneeded(struct apartment *apt)
712 if (apt->multi_threaded)
717 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
719 0, 0, OLE32_hInstance, NULL);
722 ERR("CreateWindow failed with error %d\n", GetLastError());
723 return HRESULT_FROM_WIN32(GetLastError());
725 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
726 /* someone beat us to it */
733 HWND apartment_getwindow(const struct apartment *apt)
735 assert(!apt->multi_threaded);
739 void apartment_joinmta(void)
741 apartment_addref(MTA);
742 COM_CurrentInfo()->apt = MTA;
745 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
746 REFCLSID rclsid, REFIID riid, void **ppv)
748 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
751 struct apartment_loaded_dll *apartment_loaded_dll;
753 if (!strcmpiW(dllpath, wszOle32))
755 /* we don't need to control the lifetime of this dll, so use the local
756 * implementation of DllGetClassObject directly */
757 TRACE("calling ole32!DllGetClassObject\n");
758 hr = DllGetClassObject(rclsid, riid, ppv);
761 ERR("DllGetClassObject returned error 0x%08x\n", hr);
766 EnterCriticalSection(&apt->cs);
768 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
769 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
771 TRACE("found %s already loaded\n", debugstr_w(dllpath));
778 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
779 if (!apartment_loaded_dll)
783 apartment_loaded_dll->unload_time = 0;
784 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
786 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
790 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
791 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
795 LeaveCriticalSection(&apt->cs);
799 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
800 /* OK: get the ClassObject */
801 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
804 ERR("DllGetClassObject returned error 0x%08x\n", hr);
810 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
812 struct apartment_loaded_dll *entry, *next;
813 EnterCriticalSection(&apt->cs);
814 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
816 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
818 if (!delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
820 list_remove(&entry->entry);
821 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
822 HeapFree(GetProcessHeap(), 0, entry);
825 entry->unload_time = GetTickCount() + delay;
827 else if (entry->unload_time)
828 entry->unload_time = 0;
830 LeaveCriticalSection(&apt->cs);
833 /*****************************************************************************
834 * This section contains OpenDllList implementation
837 /* caller must ensure that library_name is not already in the open dll list */
838 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
844 DllCanUnloadNowFunc DllCanUnloadNow;
845 DllGetClassObjectFunc DllGetClassObject;
849 *ret = COMPOBJ_DllList_Get(library_name);
850 if (*ret) return S_OK;
852 /* do this outside the csOpenDllList to avoid creating a lock dependency on
854 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
857 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
858 /* failure: DLL could not be loaded */
859 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
862 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
863 /* Note: failing to find DllCanUnloadNow is not a failure */
864 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
865 if (!DllGetClassObject)
867 /* failure: the dll did not export DllGetClassObject */
868 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
869 FreeLibrary(hLibrary);
870 return CO_E_DLLNOTFOUND;
873 EnterCriticalSection( &csOpenDllList );
875 *ret = COMPOBJ_DllList_Get(library_name);
878 /* another caller to this function already added the dll while we
879 * weren't in the critical section */
880 FreeLibrary(hLibrary);
884 len = strlenW(library_name);
885 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
887 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
888 if (entry && entry->library_name)
890 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
891 entry->library = hLibrary;
893 entry->DllCanUnloadNow = DllCanUnloadNow;
894 entry->DllGetClassObject = DllGetClassObject;
895 list_add_tail(&openDllList, &entry->entry);
900 FreeLibrary(hLibrary);
905 LeaveCriticalSection( &csOpenDllList );
910 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
914 EnterCriticalSection(&csOpenDllList);
915 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
917 if (!strcmpiW(library_name, ptr->library_name) &&
918 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
924 LeaveCriticalSection(&csOpenDllList);
928 /* pass FALSE for free_entry to release a reference without destroying the
929 * entry if it reaches zero or TRUE otherwise */
930 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
932 if (!InterlockedDecrement(&entry->refs) && free_entry)
934 EnterCriticalSection(&csOpenDllList);
935 list_remove(&entry->entry);
936 LeaveCriticalSection(&csOpenDllList);
938 TRACE("freeing %p\n", entry->library);
939 FreeLibrary(entry->library);
941 HeapFree(GetProcessHeap(), 0, entry->library_name);
942 HeapFree(GetProcessHeap(), 0, entry);
946 /******************************************************************************
947 * CoBuildVersion [OLE32.@]
948 * CoBuildVersion [COMPOBJ.1]
950 * Gets the build version of the DLL.
955 * Current build version, hiword is majornumber, loword is minornumber
957 DWORD WINAPI CoBuildVersion(void)
959 TRACE("Returning version %d, build %d.\n", rmm, rup);
960 return (rmm<<16)+rup;
963 /******************************************************************************
964 * CoInitialize [OLE32.@]
966 * Initializes the COM libraries by calling CoInitializeEx with
967 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
970 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
973 * Success: S_OK if not already initialized, S_FALSE otherwise.
974 * Failure: HRESULT code.
979 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
982 * Just delegate to the newer method.
984 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
987 /******************************************************************************
988 * CoInitializeEx [OLE32.@]
990 * Initializes the COM libraries.
993 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
994 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
997 * S_OK if successful,
998 * S_FALSE if this function was called already.
999 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1004 * The behavior used to set the IMalloc used for memory management is
1006 * The dwCoInit parameter must specify one of the following apartment
1008 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1009 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1010 * The parameter may also specify zero or more of the following flags:
1011 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1012 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1017 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1022 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1024 if (lpReserved!=NULL)
1026 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1030 * Check the lock count. If this is the first time going through the initialize
1031 * process, we have to initialize the libraries.
1033 * And crank-up that lock count.
1035 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1038 * Initialize the various COM libraries and data structures.
1040 TRACE("() - Initializing the COM libraries\n");
1042 /* we may need to defer this until after apartment initialisation */
1043 RunningObjectTableImpl_Initialize();
1046 if (!(apt = COM_CurrentInfo()->apt))
1048 apt = apartment_get_or_create(dwCoInit);
1049 if (!apt) return E_OUTOFMEMORY;
1051 else if (!apartment_is_model(apt, dwCoInit))
1053 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1054 code then we are probably using the wrong threading model to implement that API. */
1055 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1056 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1057 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1058 return RPC_E_CHANGED_MODE;
1063 COM_CurrentInfo()->inits++;
1068 /***********************************************************************
1069 * CoUninitialize [OLE32.@]
1071 * This method will decrement the refcount on the current apartment, freeing
1072 * the resources associated with it if it is the last thread in the apartment.
1073 * If the last apartment is freed, the function will additionally release
1074 * any COM resources associated with the process.
1084 void WINAPI CoUninitialize(void)
1086 struct oletls * info = COM_CurrentInfo();
1091 /* will only happen on OOM */
1097 ERR("Mismatched CoUninitialize\n");
1103 apartment_release(info->apt);
1108 * Decrease the reference count.
1109 * If we are back to 0 locks on the COM library, make sure we free
1110 * all the associated data structures.
1112 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1115 TRACE("() - Releasing the COM libraries\n");
1117 RunningObjectTableImpl_UnInitialize();
1119 else if (lCOMRefCnt<1) {
1120 ERR( "CoUninitialize() - not CoInitialized.\n" );
1121 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1125 /******************************************************************************
1126 * CoDisconnectObject [OLE32.@]
1128 * Disconnects all connections to this object from remote processes. Dispatches
1129 * pending RPCs while blocking new RPCs from occurring, and then calls
1130 * IMarshal::DisconnectObject on the given object.
1132 * Typically called when the object server is forced to shut down, for instance by
1136 * lpUnk [I] The object whose stub should be disconnected.
1137 * reserved [I] Reserved. Should be set to 0.
1141 * Failure: HRESULT code.
1144 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1146 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1152 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1154 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1157 hr = IMarshal_DisconnectObject(marshal, reserved);
1158 IMarshal_Release(marshal);
1162 apt = COM_CurrentApt();
1164 return CO_E_NOTINITIALIZED;
1166 apartment_disconnectobject(apt, lpUnk);
1168 /* Note: native is pretty broken here because it just silently
1169 * fails, without returning an appropriate error code if the object was
1170 * not found, making apps think that the object was disconnected, when
1171 * it actually wasn't */
1176 /******************************************************************************
1177 * CoCreateGuid [OLE32.@]
1179 * Simply forwards to UuidCreate in RPCRT4.
1182 * pguid [O] Points to the GUID to initialize.
1186 * Failure: HRESULT code.
1191 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1193 return UuidCreate(pguid);
1196 /******************************************************************************
1197 * CLSIDFromString [OLE32.@]
1198 * IIDFromString [OLE32.@]
1200 * Converts a unique identifier from its string representation into
1204 * idstr [I] The string representation of the GUID.
1205 * id [O] GUID converted from the string.
1209 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1214 static HRESULT WINAPI __CLSIDFromString(LPCWSTR s, CLSID *id)
1220 memset( id, 0, sizeof (CLSID) );
1224 /* validate the CLSID string */
1225 if (strlenW(s) != 38)
1226 return CO_E_CLASSSTRING;
1228 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1229 return CO_E_CLASSSTRING;
1231 for (i=1; i<37; i++) {
1232 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1233 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1234 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1235 ((s[i] >= 'A') && (s[i] <= 'F'))))
1236 return CO_E_CLASSSTRING;
1239 TRACE("%s -> %p\n", debugstr_w(s), id);
1241 /* quick lookup table */
1242 memset(table, 0, 256);
1244 for (i = 0; i < 10; i++) {
1247 for (i = 0; i < 6; i++) {
1248 table['A' + i] = i+10;
1249 table['a' + i] = i+10;
1252 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1254 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1255 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1256 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1257 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1259 /* these are just sequential bytes */
1260 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1261 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1262 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1263 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1264 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1265 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1266 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1267 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1272 /*****************************************************************************/
1274 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1279 return E_INVALIDARG;
1281 ret = __CLSIDFromString(idstr, id);
1282 if(ret != S_OK) { /* It appears a ProgID is also valid */
1283 ret = CLSIDFromProgID(idstr, id);
1288 /* Converts a GUID into the respective string representation. */
1289 HRESULT WINE_StringFromCLSID(
1290 const CLSID *id, /* [in] GUID to be converted */
1291 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1293 static const char hex[] = "0123456789ABCDEF";
1298 { ERR("called with id=Null\n");
1303 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1304 id->Data1, id->Data2, id->Data3,
1305 id->Data4[0], id->Data4[1]);
1309 for (i = 2; i < 8; i++) {
1310 *s++ = hex[id->Data4[i]>>4];
1311 *s++ = hex[id->Data4[i] & 0xf];
1317 TRACE("%p->%s\n", id, idstr);
1323 /******************************************************************************
1324 * StringFromCLSID [OLE32.@]
1325 * StringFromIID [OLE32.@]
1327 * Converts a GUID into the respective string representation.
1328 * The target string is allocated using the OLE IMalloc.
1331 * id [I] the GUID to be converted.
1332 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1339 * StringFromGUID2, CLSIDFromString
1341 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1347 if ((ret = CoGetMalloc(0,&mllc)))
1350 ret=WINE_StringFromCLSID(id,buf);
1352 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1353 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1354 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1359 /******************************************************************************
1360 * StringFromGUID2 [OLE32.@]
1361 * StringFromGUID2 [COMPOBJ.76]
1363 * Modified version of StringFromCLSID that allows you to specify max
1367 * id [I] GUID to convert to string.
1368 * str [O] Buffer where the result will be stored.
1369 * cmax [I] Size of the buffer in characters.
1372 * Success: The length of the resulting string in characters.
1375 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1379 if (WINE_StringFromCLSID(id,xguid))
1381 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1384 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1385 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1387 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1388 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1392 strcpyW(path, wszCLSIDSlash);
1393 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1394 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1395 if (res == ERROR_FILE_NOT_FOUND)
1396 return REGDB_E_CLASSNOTREG;
1397 else if (res != ERROR_SUCCESS)
1398 return REGDB_E_READREGDB;
1406 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1408 if (res == ERROR_FILE_NOT_FOUND)
1409 return REGDB_E_KEYMISSING;
1410 else if (res != ERROR_SUCCESS)
1411 return REGDB_E_READREGDB;
1416 /* open HKCR\\AppId\\{string form of appid clsid} key */
1417 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1419 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1420 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1422 WCHAR buf[CHARS_IN_GUID];
1423 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1429 /* read the AppID value under the class's key */
1430 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1435 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1437 if (res == ERROR_FILE_NOT_FOUND)
1438 return REGDB_E_KEYMISSING;
1439 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1440 return REGDB_E_READREGDB;
1442 strcpyW(keyname, szAppIdKey);
1443 strcatW(keyname, buf);
1444 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1445 if (res == ERROR_FILE_NOT_FOUND)
1446 return REGDB_E_KEYMISSING;
1447 else if (res != ERROR_SUCCESS)
1448 return REGDB_E_READREGDB;
1453 /******************************************************************************
1454 * ProgIDFromCLSID [OLE32.@]
1456 * Converts a class id into the respective program ID.
1459 * clsid [I] Class ID, as found in registry.
1460 * ppszProgID [O] Associated ProgID.
1465 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1467 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1469 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1476 ERR("ppszProgId isn't optional\n");
1477 return E_INVALIDARG;
1481 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1485 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1486 ret = REGDB_E_CLASSNOTREG;
1490 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1493 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1494 ret = REGDB_E_CLASSNOTREG;
1497 ret = E_OUTOFMEMORY;
1504 /******************************************************************************
1505 * CLSIDFromProgID [OLE32.@]
1507 * Converts a program id into the respective GUID.
1510 * progid [I] Unicode program ID, as found in registry.
1511 * clsid [O] Associated CLSID.
1515 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1517 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1519 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1520 WCHAR buf2[CHARS_IN_GUID];
1521 LONG buf2len = sizeof(buf2);
1525 if (!progid || !clsid)
1527 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1528 return E_INVALIDARG;
1531 /* initialise clsid in case of failure */
1532 memset(clsid, 0, sizeof(*clsid));
1534 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1535 strcpyW( buf, progid );
1536 strcatW( buf, clsidW );
1537 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1539 HeapFree(GetProcessHeap(),0,buf);
1540 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1541 return CO_E_CLASSSTRING;
1543 HeapFree(GetProcessHeap(),0,buf);
1545 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1548 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1549 return CO_E_CLASSSTRING;
1552 return CLSIDFromString(buf2,clsid);
1556 /*****************************************************************************
1557 * CoGetPSClsid [OLE32.@]
1559 * Retrieves the CLSID of the proxy/stub factory that implements
1560 * IPSFactoryBuffer for the specified interface.
1563 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1564 * pclsid [O] Where to store returned proxy/stub CLSID.
1569 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1573 * The standard marshaller activates the object with the CLSID
1574 * returned and uses the CreateProxy and CreateStub methods on its
1575 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1578 * CoGetPSClsid determines this CLSID by searching the
1579 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1580 * in the registry and any interface id registered by
1581 * CoRegisterPSClsid within the current process.
1585 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1586 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1587 * considered a bug in native unless an application depends on this (unlikely).
1590 * CoRegisterPSClsid.
1592 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1594 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1595 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1596 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1597 WCHAR value[CHARS_IN_GUID];
1600 APARTMENT *apt = COM_CurrentApt();
1601 struct registered_psclsid *registered_psclsid;
1603 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1607 ERR("apartment not initialised\n");
1608 return CO_E_NOTINITIALIZED;
1613 ERR("pclsid isn't optional\n");
1614 return E_INVALIDARG;
1617 EnterCriticalSection(&apt->cs);
1619 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1620 if (IsEqualIID(®istered_psclsid->iid, riid))
1622 *pclsid = registered_psclsid->clsid;
1623 LeaveCriticalSection(&apt->cs);
1627 LeaveCriticalSection(&apt->cs);
1629 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1630 strcpyW(path, wszInterface);
1631 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1632 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1634 /* Open the key.. */
1635 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1637 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1638 return REGDB_E_IIDNOTREG;
1641 /* ... Once we have the key, query the registry to get the
1642 value of CLSID as a string, and convert it into a
1643 proper CLSID structure to be passed back to the app */
1644 len = sizeof(value);
1645 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1648 return REGDB_E_IIDNOTREG;
1652 /* We have the CLSid we want back from the registry as a string, so
1653 lets convert it into a CLSID structure */
1654 if (CLSIDFromString(value, pclsid) != NOERROR)
1655 return REGDB_E_IIDNOTREG;
1657 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1661 /*****************************************************************************
1662 * CoRegisterPSClsid [OLE32.@]
1664 * Register a proxy/stub CLSID for the given interface in the current process
1668 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1669 * rclsid [I] CLSID of the proxy/stub.
1673 * Failure: E_OUTOFMEMORY
1677 * This function does not add anything to the registry and the effects are
1678 * limited to the lifetime of the current process.
1683 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1685 APARTMENT *apt = COM_CurrentApt();
1686 struct registered_psclsid *registered_psclsid;
1688 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1692 ERR("apartment not initialised\n");
1693 return CO_E_NOTINITIALIZED;
1696 EnterCriticalSection(&apt->cs);
1698 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1699 if (IsEqualIID(®istered_psclsid->iid, riid))
1701 registered_psclsid->clsid = *rclsid;
1702 LeaveCriticalSection(&apt->cs);
1706 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1707 if (!registered_psclsid)
1709 LeaveCriticalSection(&apt->cs);
1710 return E_OUTOFMEMORY;
1713 registered_psclsid->iid = *riid;
1714 registered_psclsid->clsid = *rclsid;
1715 list_add_head(&apt->psclsids, ®istered_psclsid->entry);
1717 LeaveCriticalSection(&apt->cs);
1724 * COM_GetRegisteredClassObject
1726 * This internal method is used to scan the registered class list to
1727 * find a class object.
1730 * rclsid Class ID of the class to find.
1731 * dwClsContext Class context to match.
1732 * ppv [out] returns a pointer to the class object. Complying
1733 * to normal COM usage, this method will increase the
1734 * reference count on this object.
1736 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1737 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1739 HRESULT hr = S_FALSE;
1740 RegisteredClass *curClass;
1747 EnterCriticalSection( &csRegisteredClassList );
1749 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1752 * Check if we have a match on the class ID and context.
1754 if ((apt->oxid == curClass->apartment_id) &&
1755 (dwClsContext & curClass->runContext) &&
1756 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1759 * We have a match, return the pointer to the class object.
1761 *ppUnk = curClass->classObject;
1763 IUnknown_AddRef(curClass->classObject);
1770 LeaveCriticalSection( &csRegisteredClassList );
1775 /******************************************************************************
1776 * CoRegisterClassObject [OLE32.@]
1778 * Registers the class object for a given class ID. Servers housed in EXE
1779 * files use this method instead of exporting DllGetClassObject to allow
1780 * other code to connect to their objects.
1783 * rclsid [I] CLSID of the object to register.
1784 * pUnk [I] IUnknown of the object.
1785 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1786 * flags [I] REGCLS flags indicating how connections are made.
1787 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1791 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1792 * CO_E_OBJISREG if the object is already registered. We should not return this.
1795 * CoRevokeClassObject, CoGetClassObject
1798 * In-process objects are only registered for the current apartment.
1799 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1800 * in other apartments.
1803 * MSDN claims that multiple interface registrations are legal, but we
1804 * can't do that with our current implementation.
1806 HRESULT WINAPI CoRegisterClassObject(
1811 LPDWORD lpdwRegister)
1813 RegisteredClass* newClass;
1814 LPUNKNOWN foundObject;
1818 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1819 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1821 if ( (lpdwRegister==0) || (pUnk==0) )
1822 return E_INVALIDARG;
1824 apt = COM_CurrentApt();
1827 ERR("COM was not initialized\n");
1828 return CO_E_NOTINITIALIZED;
1833 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1834 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1835 if (flags & REGCLS_MULTIPLEUSE)
1836 dwClsContext |= CLSCTX_INPROC_SERVER;
1839 * First, check if the class is already registered.
1840 * If it is, this should cause an error.
1842 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1844 if (flags & REGCLS_MULTIPLEUSE) {
1845 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1846 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1847 IUnknown_Release(foundObject);
1850 IUnknown_Release(foundObject);
1851 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1852 return CO_E_OBJISREG;
1855 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1856 if ( newClass == NULL )
1857 return E_OUTOFMEMORY;
1859 newClass->classIdentifier = *rclsid;
1860 newClass->apartment_id = apt->oxid;
1861 newClass->runContext = dwClsContext;
1862 newClass->connectFlags = flags;
1863 newClass->pMarshaledData = NULL;
1864 newClass->RpcRegistration = NULL;
1867 * Use the address of the chain node as the cookie since we are sure it's
1868 * unique. FIXME: not on 64-bit platforms.
1870 newClass->dwCookie = (DWORD)newClass;
1873 * Since we're making a copy of the object pointer, we have to increase its
1876 newClass->classObject = pUnk;
1877 IUnknown_AddRef(newClass->classObject);
1879 EnterCriticalSection( &csRegisteredClassList );
1880 list_add_tail(&RegisteredClassList, &newClass->entry);
1881 LeaveCriticalSection( &csRegisteredClassList );
1883 *lpdwRegister = newClass->dwCookie;
1885 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1886 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1888 FIXME("Failed to create stream on hglobal, %x\n", hr);
1891 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1892 newClass->classObject, MSHCTX_LOCAL, NULL,
1893 MSHLFLAGS_TABLESTRONG);
1895 FIXME("CoMarshalInterface failed, %x!\n",hr);
1899 hr = RPC_StartLocalServer(&newClass->classIdentifier,
1900 newClass->pMarshaledData,
1901 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
1902 &newClass->RpcRegistration);
1907 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
1909 list_remove(&curClass->entry);
1911 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
1912 RPC_StopLocalServer(curClass->RpcRegistration);
1915 * Release the reference to the class object.
1917 IUnknown_Release(curClass->classObject);
1919 if (curClass->pMarshaledData)
1922 memset(&zero, 0, sizeof(zero));
1923 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
1924 CoReleaseMarshalData(curClass->pMarshaledData);
1927 HeapFree(GetProcessHeap(), 0, curClass);
1930 static void COM_RevokeAllClasses(const struct apartment *apt)
1932 RegisteredClass *curClass, *cursor;
1934 EnterCriticalSection( &csRegisteredClassList );
1936 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
1938 if (curClass->apartment_id == apt->oxid)
1939 COM_RevokeRegisteredClassObject(curClass);
1942 LeaveCriticalSection( &csRegisteredClassList );
1945 /***********************************************************************
1946 * CoRevokeClassObject [OLE32.@]
1948 * Removes a class object from the class registry.
1951 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1955 * Failure: HRESULT code.
1958 * Must be called from the same apartment that called CoRegisterClassObject(),
1959 * otherwise it will fail with RPC_E_WRONG_THREAD.
1962 * CoRegisterClassObject
1964 HRESULT WINAPI CoRevokeClassObject(
1967 HRESULT hr = E_INVALIDARG;
1968 RegisteredClass *curClass;
1971 TRACE("(%08x)\n",dwRegister);
1973 apt = COM_CurrentApt();
1976 ERR("COM was not initialized\n");
1977 return CO_E_NOTINITIALIZED;
1980 EnterCriticalSection( &csRegisteredClassList );
1982 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1985 * Check if we have a match on the cookie.
1987 if (curClass->dwCookie == dwRegister)
1989 if (curClass->apartment_id == apt->oxid)
1991 COM_RevokeRegisteredClassObject(curClass);
1996 ERR("called from wrong apartment, should be called from %s\n",
1997 wine_dbgstr_longlong(curClass->apartment_id));
1998 hr = RPC_E_WRONG_THREAD;
2004 LeaveCriticalSection( &csRegisteredClassList );
2009 /***********************************************************************
2010 * COM_RegReadPath [internal]
2012 * Reads a registry value and expands it when necessary
2014 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2019 WCHAR src[MAX_PATH];
2020 DWORD dwLength = dstlen * sizeof(WCHAR);
2022 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
2023 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2024 if (keytype == REG_EXPAND_SZ) {
2025 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2027 lstrcpynW(dst, src, dstlen);
2035 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2037 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2040 DWORD dwLength = len * sizeof(WCHAR);
2042 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2043 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2047 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2048 REFCLSID rclsid, REFIID riid, void **ppv)
2050 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2051 static const WCHAR wszFree[] = {'F','r','e','e',0};
2052 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2053 WCHAR dllpath[MAX_PATH+1];
2054 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2056 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2058 if (!strcmpiW(threading_model, wszApartment))
2060 if (apt->multi_threaded)
2061 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2064 else if (!strcmpiW(threading_model, wszFree))
2066 if (!apt->multi_threaded)
2067 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2069 /* everything except "Apartment", "Free" and "Both" */
2070 else if (strcmpiW(threading_model, wszBoth))
2072 /* everything else is main-threaded */
2073 if (threading_model[0])
2074 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2075 debugstr_w(threading_model), debugstr_guid(rclsid));
2077 if (apt->multi_threaded || !apt->main)
2078 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2081 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2083 /* failure: CLSID is not found in registry */
2084 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2085 return REGDB_E_CLASSNOTREG;
2088 return apartment_getclassobject(apt, dllpath, rclsid, riid, ppv);
2091 /***********************************************************************
2092 * CoGetClassObject [OLE32.@]
2094 * Creates an object of the specified class.
2097 * rclsid [I] Class ID to create an instance of.
2098 * dwClsContext [I] Flags to restrict the location of the created instance.
2099 * pServerInfo [I] Optional. Details for connecting to a remote server.
2100 * iid [I] The ID of the interface of the instance to return.
2101 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2105 * Failure: HRESULT code.
2108 * The dwClsContext parameter can be one or more of the following:
2109 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2110 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2111 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2112 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2115 * CoCreateInstance()
2117 HRESULT WINAPI CoGetClassObject(
2118 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2119 REFIID iid, LPVOID *ppv)
2121 LPUNKNOWN regClassObject;
2122 HRESULT hres = E_UNEXPECTED;
2125 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2128 return E_INVALIDARG;
2132 apt = COM_CurrentApt();
2135 ERR("apartment not initialised\n");
2136 return CO_E_NOTINITIALIZED;
2140 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2141 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2145 * First, try and see if we can't match the class ID with one of the
2146 * registered classes.
2148 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2151 /* Get the required interface from the retrieved pointer. */
2152 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2155 * Since QI got another reference on the pointer, we want to release the
2156 * one we already have. If QI was unsuccessful, this will release the object. This
2157 * is good since we are not returning it in the "out" parameter.
2159 IUnknown_Release(regClassObject);
2164 /* First try in-process server */
2165 if (CLSCTX_INPROC_SERVER & dwClsContext)
2167 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2170 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2171 return FTMarshalCF_Create(iid, ppv);
2173 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2176 if (hres == REGDB_E_CLASSNOTREG)
2177 ERR("class %s not registered\n", debugstr_guid(rclsid));
2178 else if (hres == REGDB_E_KEYMISSING)
2180 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2181 hres = REGDB_E_CLASSNOTREG;
2185 if (SUCCEEDED(hres))
2187 hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
2191 /* return if we got a class, otherwise fall through to one of the
2193 if (SUCCEEDED(hres))
2197 /* Next try in-process handler */
2198 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2200 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2203 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2206 if (hres == REGDB_E_CLASSNOTREG)
2207 ERR("class %s not registered\n", debugstr_guid(rclsid));
2208 else if (hres == REGDB_E_KEYMISSING)
2210 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2211 hres = REGDB_E_CLASSNOTREG;
2215 if (SUCCEEDED(hres))
2217 hres = get_inproc_class_object(apt, hkey, rclsid, iid, ppv);
2221 /* return if we got a class, otherwise fall through to one of the
2223 if (SUCCEEDED(hres))
2227 /* Next try out of process */
2228 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2230 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2231 if (SUCCEEDED(hres))
2235 /* Finally try remote: this requires networked DCOM (a lot of work) */
2236 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2238 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2239 hres = E_NOINTERFACE;
2243 ERR("no class object %s could be created for context 0x%x\n",
2244 debugstr_guid(rclsid), dwClsContext);
2248 /***********************************************************************
2249 * CoResumeClassObjects (OLE32.@)
2251 * Resumes all class objects registered with REGCLS_SUSPENDED.
2255 * Failure: HRESULT code.
2257 HRESULT WINAPI CoResumeClassObjects(void)
2263 /***********************************************************************
2264 * CoCreateInstance [OLE32.@]
2266 * Creates an instance of the specified class.
2269 * rclsid [I] Class ID to create an instance of.
2270 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2271 * dwClsContext [I] Flags to restrict the location of the created instance.
2272 * iid [I] The ID of the interface of the instance to return.
2273 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2277 * Failure: HRESULT code.
2280 * The dwClsContext parameter can be one or more of the following:
2281 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2282 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2283 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2284 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2286 * Aggregation is the concept of deferring the IUnknown of an object to another
2287 * object. This allows a separate object to behave as though it was part of
2288 * the object and to allow this the pUnkOuter parameter can be set. Note that
2289 * not all objects support having an outer of unknown.
2292 * CoGetClassObject()
2294 HRESULT WINAPI CoCreateInstance(
2296 LPUNKNOWN pUnkOuter,
2302 LPCLASSFACTORY lpclf = 0;
2304 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2305 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2314 * Initialize the "out" parameter
2318 if (!COM_CurrentApt())
2320 ERR("apartment not initialised\n");
2321 return CO_E_NOTINITIALIZED;
2325 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2326 * Rather than create a class factory, we can just check for it here
2328 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2329 if (StdGlobalInterfaceTableInstance == NULL)
2330 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2331 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2332 if (hres) return hres;
2334 TRACE("Retrieved GIT (%p)\n", *ppv);
2339 * Get a class factory to construct the object we want.
2341 hres = CoGetClassObject(rclsid,
2351 * Create the object and don't forget to release the factory
2353 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2354 IClassFactory_Release(lpclf);
2356 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
2357 debugstr_guid(iid), debugstr_guid(rclsid),hres);
2362 /***********************************************************************
2363 * CoCreateInstanceEx [OLE32.@]
2365 HRESULT WINAPI CoCreateInstanceEx(
2367 LPUNKNOWN pUnkOuter,
2369 COSERVERINFO* pServerInfo,
2373 IUnknown* pUnk = NULL;
2376 ULONG successCount = 0;
2381 if ( (cmq==0) || (pResults==NULL))
2382 return E_INVALIDARG;
2384 if (pServerInfo!=NULL)
2385 FIXME("() non-NULL pServerInfo not supported!\n");
2388 * Initialize all the "out" parameters.
2390 for (index = 0; index < cmq; index++)
2392 pResults[index].pItf = NULL;
2393 pResults[index].hr = E_NOINTERFACE;
2397 * Get the object and get its IUnknown pointer.
2399 hr = CoCreateInstance(rclsid,
2409 * Then, query for all the interfaces requested.
2411 for (index = 0; index < cmq; index++)
2413 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2414 pResults[index].pIID,
2415 (VOID**)&(pResults[index].pItf));
2417 if (pResults[index].hr == S_OK)
2422 * Release our temporary unknown pointer.
2424 IUnknown_Release(pUnk);
2426 if (successCount == 0)
2427 return E_NOINTERFACE;
2429 if (successCount!=cmq)
2430 return CO_S_NOTALLINTERFACES;
2435 /***********************************************************************
2436 * CoLoadLibrary (OLE32.@)
2441 * lpszLibName [I] Path to library.
2442 * bAutoFree [I] Whether the library should automatically be freed.
2445 * Success: Handle to loaded library.
2449 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2451 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2453 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2455 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2458 /***********************************************************************
2459 * CoFreeLibrary [OLE32.@]
2461 * Unloads a library from memory.
2464 * hLibrary [I] Handle to library to unload.
2470 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2472 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2474 FreeLibrary(hLibrary);
2478 /***********************************************************************
2479 * CoFreeAllLibraries [OLE32.@]
2481 * Function for backwards compatibility only. Does nothing.
2487 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2489 void WINAPI CoFreeAllLibraries(void)
2494 /***********************************************************************
2495 * CoFreeUnusedLibrariesEx [OLE32.@]
2497 * Frees any previously unused libraries whose delay has expired and marks
2498 * currently unused libraries for unloading. Unused are identified as those that
2499 * return S_OK from their DllCanUnloadNow function.
2502 * dwUnloadDelay [I] Unload delay in milliseconds.
2503 * dwReserved [I] Reserved. Set to 0.
2509 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2511 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2513 struct apartment *apt = COM_CurrentApt();
2516 ERR("apartment not initialised\n");
2520 if (dwUnloadDelay == INFINITE)
2522 if (apt->multi_threaded)
2523 dwUnloadDelay = 10 * 60 * 1000; /* 10 minutes */
2528 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2531 /***********************************************************************
2532 * CoFreeUnusedLibraries [OLE32.@]
2533 * CoFreeUnusedLibraries [COMPOBJ.17]
2535 * Frees any unused libraries. Unused are identified as those that return
2536 * S_OK from their DllCanUnloadNow function.
2542 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2544 void WINAPI CoFreeUnusedLibraries(void)
2546 CoFreeUnusedLibrariesEx(INFINITE, 0);
2549 /***********************************************************************
2550 * CoFileTimeNow [OLE32.@]
2551 * CoFileTimeNow [COMPOBJ.82]
2553 * Retrieves the current time in FILETIME format.
2556 * lpFileTime [O] The current time.
2561 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2563 GetSystemTimeAsFileTime( lpFileTime );
2567 /******************************************************************************
2568 * CoLockObjectExternal [OLE32.@]
2570 * Increments or decrements the external reference count of a stub object.
2573 * pUnk [I] Stub object.
2574 * fLock [I] If TRUE then increments the external ref-count,
2575 * otherwise decrements.
2576 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2577 * calling CoDisconnectObject.
2581 * Failure: HRESULT code.
2584 * If fLock is TRUE and an object is passed in that doesn't have a stub
2585 * manager then a new stub manager is created for the object.
2587 HRESULT WINAPI CoLockObjectExternal(
2590 BOOL fLastUnlockReleases)
2592 struct stub_manager *stubmgr;
2593 struct apartment *apt;
2595 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2596 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2598 apt = COM_CurrentApt();
2599 if (!apt) return CO_E_NOTINITIALIZED;
2601 stubmgr = get_stub_manager_from_object(apt, pUnk);
2606 stub_manager_ext_addref(stubmgr, 1);
2608 stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
2610 stub_manager_int_release(stubmgr);
2616 stubmgr = new_stub_manager(apt, pUnk);
2620 stub_manager_ext_addref(stubmgr, 1);
2621 stub_manager_int_release(stubmgr);
2628 WARN("stub object not found %p\n", pUnk);
2629 /* Note: native is pretty broken here because it just silently
2630 * fails, without returning an appropriate error code, making apps
2631 * think that the object was disconnected, when it actually wasn't */
2636 /***********************************************************************
2637 * CoInitializeWOW (OLE32.@)
2639 * WOW equivalent of CoInitialize?
2648 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2650 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2654 /***********************************************************************
2655 * CoGetState [OLE32.@]
2657 * Retrieves the thread state object previously stored by CoSetState().
2660 * ppv [I] Address where pointer to object will be stored.
2664 * Failure: E_OUTOFMEMORY.
2667 * Crashes on all invalid ppv addresses, including NULL.
2668 * If the function returns a non-NULL object then the caller must release its
2669 * reference on the object when the object is no longer required.
2674 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2676 struct oletls *info = COM_CurrentInfo();
2677 if (!info) return E_OUTOFMEMORY;
2683 IUnknown_AddRef(info->state);
2685 TRACE("apt->state=%p\n", info->state);
2691 /***********************************************************************
2692 * CoSetState [OLE32.@]
2694 * Sets the thread state object.
2697 * pv [I] Pointer to state object to be stored.
2700 * The system keeps a reference on the object while the object stored.
2704 * Failure: E_OUTOFMEMORY.
2706 HRESULT WINAPI CoSetState(IUnknown * pv)
2708 struct oletls *info = COM_CurrentInfo();
2709 if (!info) return E_OUTOFMEMORY;
2711 if (pv) IUnknown_AddRef(pv);
2715 TRACE("-- release %p now\n", info->state);
2716 IUnknown_Release(info->state);
2725 /******************************************************************************
2726 * CoTreatAsClass [OLE32.@]
2728 * Sets the TreatAs value of a class.
2731 * clsidOld [I] Class to set TreatAs value on.
2732 * clsidNew [I] The class the clsidOld should be treated as.
2736 * Failure: HRESULT code.
2741 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2743 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2744 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2746 WCHAR szClsidNew[CHARS_IN_GUID];
2748 WCHAR auto_treat_as[CHARS_IN_GUID];
2749 LONG auto_treat_as_size = sizeof(auto_treat_as);
2752 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2755 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2757 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2758 !CLSIDFromString(auto_treat_as, &id))
2760 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2762 res = REGDB_E_WRITEREGDB;
2768 RegDeleteKeyW(hkey, wszTreatAs);
2772 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2773 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2775 res = REGDB_E_WRITEREGDB;
2780 if (hkey) RegCloseKey(hkey);
2784 /******************************************************************************
2785 * CoGetTreatAsClass [OLE32.@]
2787 * Gets the TreatAs value of a class.
2790 * clsidOld [I] Class to get the TreatAs value of.
2791 * clsidNew [I] The class the clsidOld should be treated as.
2795 * Failure: HRESULT code.
2800 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2802 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2804 WCHAR szClsidNew[CHARS_IN_GUID];
2806 LONG len = sizeof(szClsidNew);
2808 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2809 memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2811 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2814 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2819 res = CLSIDFromString(szClsidNew,clsidNew);
2821 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2823 if (hkey) RegCloseKey(hkey);
2827 /******************************************************************************
2828 * CoGetCurrentProcess [OLE32.@]
2829 * CoGetCurrentProcess [COMPOBJ.34]
2831 * Gets the current process ID.
2834 * The current process ID.
2837 * Is DWORD really the correct return type for this function?
2839 DWORD WINAPI CoGetCurrentProcess(void)
2841 return GetCurrentProcessId();
2844 /******************************************************************************
2845 * CoRegisterMessageFilter [OLE32.@]
2847 * Registers a message filter.
2850 * lpMessageFilter [I] Pointer to interface.
2851 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2855 * Failure: HRESULT code.
2858 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2859 * lpMessageFilter removes the message filter.
2861 * If lplpMessageFilter is not NULL the previous message filter will be
2862 * returned in the memory pointer to this parameter and the caller is
2863 * responsible for releasing the object.
2865 * The current thread be in an apartment otherwise the function will crash.
2867 HRESULT WINAPI CoRegisterMessageFilter(
2868 LPMESSAGEFILTER lpMessageFilter,
2869 LPMESSAGEFILTER *lplpMessageFilter)
2871 struct apartment *apt;
2872 IMessageFilter *lpOldMessageFilter;
2874 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
2876 apt = COM_CurrentApt();
2878 /* can't set a message filter in a multi-threaded apartment */
2879 if (!apt || apt->multi_threaded)
2881 WARN("can't set message filter in MTA or uninitialized apt\n");
2882 return CO_E_NOT_SUPPORTED;
2885 if (lpMessageFilter)
2886 IMessageFilter_AddRef(lpMessageFilter);
2888 EnterCriticalSection(&apt->cs);
2890 lpOldMessageFilter = apt->filter;
2891 apt->filter = lpMessageFilter;
2893 LeaveCriticalSection(&apt->cs);
2895 if (lplpMessageFilter)
2896 *lplpMessageFilter = lpOldMessageFilter;
2897 else if (lpOldMessageFilter)
2898 IMessageFilter_Release(lpOldMessageFilter);
2903 /***********************************************************************
2904 * CoIsOle1Class [OLE32.@]
2906 * Determines whether the specified class an OLE v1 class.
2909 * clsid [I] Class to test.
2912 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
2914 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2916 FIXME("%s\n", debugstr_guid(clsid));
2920 /***********************************************************************
2921 * IsEqualGUID [OLE32.@]
2923 * Compares two Unique Identifiers.
2926 * rguid1 [I] The first GUID to compare.
2927 * rguid2 [I] The other GUID to compare.
2933 BOOL WINAPI IsEqualGUID(
2937 return !memcmp(rguid1,rguid2,sizeof(GUID));
2940 /***********************************************************************
2941 * CoInitializeSecurity [OLE32.@]
2943 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2944 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2945 void* pReserved1, DWORD dwAuthnLevel,
2946 DWORD dwImpLevel, void* pReserved2,
2947 DWORD dwCapabilities, void* pReserved3)
2949 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
2950 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2951 dwCapabilities, pReserved3);
2955 /***********************************************************************
2956 * CoSuspendClassObjects [OLE32.@]
2958 * Suspends all registered class objects to prevent further requests coming in
2959 * for those objects.
2963 * Failure: HRESULT code.
2965 HRESULT WINAPI CoSuspendClassObjects(void)
2971 /***********************************************************************
2972 * CoAddRefServerProcess [OLE32.@]
2974 * Helper function for incrementing the reference count of a local-server
2978 * New reference count.
2981 * CoReleaseServerProcess().
2983 ULONG WINAPI CoAddRefServerProcess(void)
2989 EnterCriticalSection(&csRegisteredClassList);
2990 refs = ++s_COMServerProcessReferences;
2991 LeaveCriticalSection(&csRegisteredClassList);
2993 TRACE("refs before: %d\n", refs - 1);
2998 /***********************************************************************
2999 * CoReleaseServerProcess [OLE32.@]
3001 * Helper function for decrementing the reference count of a local-server
3005 * New reference count.
3008 * When reference count reaches 0, this function suspends all registered
3009 * classes so no new connections are accepted.
3012 * CoAddRefServerProcess(), CoSuspendClassObjects().
3014 ULONG WINAPI CoReleaseServerProcess(void)
3020 EnterCriticalSection(&csRegisteredClassList);
3022 refs = --s_COMServerProcessReferences;
3023 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3025 LeaveCriticalSection(&csRegisteredClassList);
3027 TRACE("refs after: %d\n", refs);
3032 /***********************************************************************
3033 * CoIsHandlerConnected [OLE32.@]
3035 * Determines whether a proxy is connected to a remote stub.
3038 * pUnk [I] Pointer to object that may or may not be connected.
3041 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3044 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3046 FIXME("%p\n", pUnk);
3051 /***********************************************************************
3052 * CoAllowSetForegroundWindow [OLE32.@]
3055 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3057 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3061 /***********************************************************************
3062 * CoQueryProxyBlanket [OLE32.@]
3064 * Retrieves the security settings being used by a proxy.
3067 * pProxy [I] Pointer to the proxy object.
3068 * pAuthnSvc [O] The type of authentication service.
3069 * pAuthzSvc [O] The type of authorization service.
3070 * ppServerPrincName [O] Optional. The server prinicple name.
3071 * pAuthnLevel [O] The authentication level.
3072 * pImpLevel [O] The impersonation level.
3073 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3074 * pCapabilities [O] Flags affecting the security behaviour.
3078 * Failure: HRESULT code.
3081 * CoCopyProxy, CoSetProxyBlanket.
3083 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3084 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3085 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3087 IClientSecurity *pCliSec;
3090 TRACE("%p\n", pProxy);
3092 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3095 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3096 pAuthzSvc, ppServerPrincName,
3097 pAuthnLevel, pImpLevel, ppAuthInfo,
3099 IClientSecurity_Release(pCliSec);
3102 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3106 /***********************************************************************
3107 * CoSetProxyBlanket [OLE32.@]
3109 * Sets the security settings for a proxy.
3112 * pProxy [I] Pointer to the proxy object.
3113 * AuthnSvc [I] The type of authentication service.
3114 * AuthzSvc [I] The type of authorization service.
3115 * pServerPrincName [I] The server prinicple name.
3116 * AuthnLevel [I] The authentication level.
3117 * ImpLevel [I] The impersonation level.
3118 * pAuthInfo [I] Information specific to the authorization/authentication service.
3119 * Capabilities [I] Flags affecting the security behaviour.
3123 * Failure: HRESULT code.
3126 * CoQueryProxyBlanket, CoCopyProxy.
3128 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3129 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3130 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3132 IClientSecurity *pCliSec;
3135 TRACE("%p\n", pProxy);
3137 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3140 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3141 AuthzSvc, pServerPrincName,
3142 AuthnLevel, ImpLevel, pAuthInfo,
3144 IClientSecurity_Release(pCliSec);
3147 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3151 /***********************************************************************
3152 * CoCopyProxy [OLE32.@]
3157 * pProxy [I] Pointer to the proxy object.
3158 * ppCopy [O] Copy of the proxy.
3162 * Failure: HRESULT code.
3165 * CoQueryProxyBlanket, CoSetProxyBlanket.
3167 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3169 IClientSecurity *pCliSec;
3172 TRACE("%p\n", pProxy);
3174 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3177 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3178 IClientSecurity_Release(pCliSec);
3181 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3186 /***********************************************************************
3187 * CoGetCallContext [OLE32.@]
3189 * Gets the context of the currently executing server call in the current
3193 * riid [I] Context interface to return.
3194 * ppv [O] Pointer to memory that will receive the context on return.
3198 * Failure: HRESULT code.
3200 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3202 FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
3205 return E_NOINTERFACE;
3208 /***********************************************************************
3209 * CoQueryClientBlanket [OLE32.@]
3211 * Retrieves the authentication information about the client of the currently
3212 * executing server call in the current thread.
3215 * pAuthnSvc [O] Optional. The type of authentication service.
3216 * pAuthzSvc [O] Optional. The type of authorization service.
3217 * pServerPrincName [O] Optional. The server prinicple name.
3218 * pAuthnLevel [O] Optional. The authentication level.
3219 * pImpLevel [O] Optional. The impersonation level.
3220 * pPrivs [O] Optional. Information about the privileges of the client.
3221 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3225 * Failure: HRESULT code.
3228 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3230 HRESULT WINAPI CoQueryClientBlanket(
3233 OLECHAR **pServerPrincName,
3236 RPC_AUTHZ_HANDLE *pPrivs,
3237 DWORD *pCapabilities)
3239 IServerSecurity *pSrvSec;
3242 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3243 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3244 pPrivs, pCapabilities);
3246 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3249 hr = IServerSecurity_QueryBlanket(
3250 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3251 pImpLevel, pPrivs, pCapabilities);
3252 IServerSecurity_Release(pSrvSec);
3258 /***********************************************************************
3259 * CoImpersonateClient [OLE32.@]
3261 * Impersonates the client of the currently executing server call in the
3269 * Failure: HRESULT code.
3272 * If this function fails then the current thread will not be impersonating
3273 * the client and all actions will take place on behalf of the server.
3274 * Therefore, it is important to check the return value from this function.
3277 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3279 HRESULT WINAPI CoImpersonateClient(void)
3281 IServerSecurity *pSrvSec;
3286 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3289 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3290 IServerSecurity_Release(pSrvSec);
3296 /***********************************************************************
3297 * CoRevertToSelf [OLE32.@]
3299 * Ends the impersonation of the client of the currently executing server
3300 * call in the current thread.
3307 * Failure: HRESULT code.
3310 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3312 HRESULT WINAPI CoRevertToSelf(void)
3314 IServerSecurity *pSrvSec;
3319 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3322 hr = IServerSecurity_RevertToSelf(pSrvSec);
3323 IServerSecurity_Release(pSrvSec);
3329 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3331 /* first try to retrieve messages for incoming COM calls to the apartment window */
3332 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3333 /* next retrieve other messages necessary for the app to remain responsive */
3334 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3337 /***********************************************************************
3338 * CoWaitForMultipleHandles [OLE32.@]
3340 * Waits for one or more handles to become signaled.
3343 * dwFlags [I] Flags. See notes.
3344 * dwTimeout [I] Timeout in milliseconds.
3345 * cHandles [I] Number of handles pointed to by pHandles.
3346 * pHandles [I] Handles to wait for.
3347 * lpdwindex [O] Index of handle that was signaled.
3351 * Failure: RPC_S_CALLPENDING on timeout.
3355 * The dwFlags parameter can be zero or more of the following:
3356 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3357 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3360 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3362 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3363 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3366 DWORD start_time = GetTickCount();
3367 APARTMENT *apt = COM_CurrentApt();
3368 BOOL message_loop = apt && !apt->multi_threaded;
3370 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3371 pHandles, lpdwindex);
3375 DWORD now = GetTickCount();
3378 if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now))
3380 hr = RPC_S_CALLPENDING;
3386 DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 |
3387 (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0;
3389 TRACE("waiting for rpc completion or window message\n");
3391 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3392 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3393 QS_ALLINPUT, wait_flags);
3395 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3399 /* call message filter */
3401 if (COM_CurrentApt()->filter)
3403 PENDINGTYPE pendingtype =
3404 COM_CurrentInfo()->pending_call_count_server ?
3405 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3406 DWORD be_handled = IMessageFilter_MessagePending(
3407 COM_CurrentApt()->filter, 0 /* FIXME */,
3408 now - start_time, pendingtype);
3409 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3412 case PENDINGMSG_CANCELCALL:
3413 WARN("call canceled\n");
3414 hr = RPC_E_CALL_CANCELED;
3416 case PENDINGMSG_WAITNOPROCESS:
3417 case PENDINGMSG_WAITDEFPROCESS:
3419 /* FIXME: MSDN is very vague about the difference
3420 * between WAITNOPROCESS and WAITDEFPROCESS - there
3421 * appears to be none, so it is possibly a left-over
3422 * from the 16-bit world. */
3427 /* note: using "if" here instead of "while" might seem less
3428 * efficient, but only if we are optimising for quick delivery
3429 * of pending messages, rather than quick completion of the
3431 if (COM_PeekMessage(apt, &msg))
3433 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3434 TranslateMessage(&msg);
3435 DispatchMessageW(&msg);
3436 if (msg.message == WM_QUIT)
3438 TRACE("resending WM_QUIT to outer message loop\n");
3439 PostQuitMessage(msg.wParam);
3440 /* no longer need to process messages */
3441 message_loop = FALSE;
3449 TRACE("waiting for rpc completion\n");
3451 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3452 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3453 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3454 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3457 if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles))
3459 /* handle signaled, store index */
3460 *lpdwindex = (res - WAIT_OBJECT_0);
3463 else if (res == WAIT_TIMEOUT)
3465 hr = RPC_S_CALLPENDING;
3470 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3475 TRACE("-- 0x%08x\n", hr);
3480 /***********************************************************************
3481 * CoGetObject [OLE32.@]
3483 * Gets the object named by coverting the name to a moniker and binding to it.
3486 * pszName [I] String representing the object.
3487 * pBindOptions [I] Parameters affecting the binding to the named object.
3488 * riid [I] Interface to bind to on the objecct.
3489 * ppv [O] On output, the interface riid of the object represented
3494 * Failure: HRESULT code.
3497 * MkParseDisplayName.
3499 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3500 REFIID riid, void **ppv)
3507 hr = CreateBindCtx(0, &pbc);
3511 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3518 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3521 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3522 IMoniker_Release(pmk);
3526 IBindCtx_Release(pbc);
3531 /***********************************************************************
3532 * CoRegisterChannelHook [OLE32.@]
3534 * Registers a process-wide hook that is called during ORPC calls.
3537 * guidExtension [I] GUID of the channel hook to register.
3538 * pChannelHook [I] Channel hook object to register.
3542 * Failure: HRESULT code.
3544 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3546 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3548 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3551 /***********************************************************************
3554 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3556 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3559 case DLL_PROCESS_ATTACH:
3560 OLE32_hInstance = hinstDLL;
3561 COMPOBJ_InitProcess();
3562 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3565 case DLL_PROCESS_DETACH:
3566 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3567 OLEDD_UnInitialize();
3568 COMPOBJ_UninitProcess();
3569 RPC_UnregisterAllChannelHooks();
3570 OLE32_hInstance = 0;
3573 case DLL_THREAD_DETACH:
3580 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */