mlang/tests: Use a table for testing GetLcidFromRfc1766.
[wine.git] / dlls / ole32 / compobj.c
blob154c18d67df3d0694f3df01069f1b65a1597cd2f
1 /*
2 * COMPOBJ library
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
26 * Note
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
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #include "objbase.h"
56 #include "ole2.h"
57 #include "ole2ver.h"
58 #include "ctxtcall.h"
59 #include "dde.h"
61 #include "compobj_private.h"
63 #include "wine/unicode.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(ole);
68 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
70 /****************************************************************************
71 * This section defines variables internal to the COM module.
74 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
75 DWORD dwClsContext, LPUNKNOWN* ppUnk);
76 static void COM_RevokeAllClasses(const struct apartment *apt);
77 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv);
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
86 0, 0, &csApartment,
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 struct registered_psclsid
94 struct list entry;
95 IID iid;
96 CLSID clsid;
100 * This lock count counts the number of times CoInitialize is called. It is
101 * decreased every time CoUninitialize is called. When it hits 0, the COM
102 * libraries are freed
104 static LONG s_COMLockCount = 0;
105 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
106 static LONG s_COMServerProcessReferences = 0;
109 * This linked list contains the list of registered class objects. These
110 * are mostly used to register the factories for out-of-proc servers of OLE
111 * objects.
113 * TODO: Make this data structure aware of inter-process communication. This
114 * means that parts of this will be exported to rpcss.
116 typedef struct tagRegisteredClass
118 struct list entry;
119 CLSID classIdentifier;
120 OXID apartment_id;
121 LPUNKNOWN classObject;
122 DWORD runContext;
123 DWORD connectFlags;
124 DWORD dwCookie;
125 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
126 void *RpcRegistration;
127 } RegisteredClass;
129 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
131 static CRITICAL_SECTION csRegisteredClassList;
132 static CRITICAL_SECTION_DEBUG class_cs_debug =
134 0, 0, &csRegisteredClassList,
135 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
136 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
138 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
140 /*****************************************************************************
141 * This section contains OpenDllList definitions
143 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
144 * other functions that do LoadLibrary _without_ giving back a HMODULE.
145 * Without this list these handles would never be freed.
147 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
148 * next unload-call but not before 600 sec.
151 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
152 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
154 typedef struct tagOpenDll
156 LONG refs;
157 LPWSTR library_name;
158 HANDLE library;
159 DllGetClassObjectFunc DllGetClassObject;
160 DllCanUnloadNowFunc DllCanUnloadNow;
161 struct list entry;
162 } OpenDll;
164 static struct list openDllList = LIST_INIT(openDllList);
166 static CRITICAL_SECTION csOpenDllList;
167 static CRITICAL_SECTION_DEBUG dll_cs_debug =
169 0, 0, &csOpenDllList,
170 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
171 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
173 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
175 struct apartment_loaded_dll
177 struct list entry;
178 OpenDll *dll;
179 DWORD unload_time;
180 BOOL multi_threaded;
183 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',' ',
184 '0','x','#','#','#','#','#','#','#','#',' ',0};
185 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
186 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
187 BOOL apartment_threaded,
188 REFCLSID rclsid, REFIID riid, void **ppv);
189 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
191 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
192 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
193 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
195 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
197 static void COMPOBJ_InitProcess( void )
199 WNDCLASSW wclass;
201 /* Dispatching to the correct thread in an apartment is done through
202 * window messages rather than RPC transports. When an interface is
203 * marshalled into another apartment in the same process, a window of the
204 * following class is created. The *caller* of CoMarshalInterface (i.e., the
205 * application) is responsible for pumping the message loop in that thread.
206 * The WM_USER messages which point to the RPCs are then dispatched to
207 * apartment_wndproc by the user's code from the apartment in which the
208 * interface was unmarshalled.
210 memset(&wclass, 0, sizeof(wclass));
211 wclass.lpfnWndProc = apartment_wndproc;
212 wclass.hInstance = hProxyDll;
213 wclass.lpszClassName = wszAptWinClass;
214 RegisterClassW(&wclass);
217 static void COMPOBJ_UninitProcess( void )
219 UnregisterClassW(wszAptWinClass, hProxyDll);
222 static void COM_TlsDestroy(void)
224 struct oletls *info = NtCurrentTeb()->ReservedForOle;
225 if (info)
227 if (info->apt) apartment_release(info->apt);
228 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
229 if (info->state) IUnknown_Release(info->state);
230 if (info->spy) IUnknown_Release(info->spy);
231 HeapFree(GetProcessHeap(), 0, info);
232 NtCurrentTeb()->ReservedForOle = NULL;
236 /******************************************************************************
237 * Manage apartments.
240 /* allocates memory and fills in the necessary fields for a new apartment
241 * object. must be called inside apartment cs */
242 static APARTMENT *apartment_construct(DWORD model)
244 APARTMENT *apt;
246 TRACE("creating new apartment, model=%d\n", model);
248 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
249 apt->tid = GetCurrentThreadId();
251 list_init(&apt->proxies);
252 list_init(&apt->stubmgrs);
253 list_init(&apt->psclsids);
254 list_init(&apt->loaded_dlls);
255 apt->ipidc = 0;
256 apt->refs = 1;
257 apt->remunk_exported = FALSE;
258 apt->oidc = 1;
259 InitializeCriticalSection(&apt->cs);
260 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
262 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
264 if (apt->multi_threaded)
266 /* FIXME: should be randomly generated by in an RPC call to rpcss */
267 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
269 else
271 /* FIXME: should be randomly generated by in an RPC call to rpcss */
272 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
275 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
277 list_add_head(&apts, &apt->entry);
279 return apt;
282 /* gets and existing apartment if one exists or otherwise creates an apartment
283 * structure which stores OLE apartment-local information and stores a pointer
284 * to it in the thread-local storage */
285 static APARTMENT *apartment_get_or_create(DWORD model)
287 APARTMENT *apt = COM_CurrentApt();
289 if (!apt)
291 if (model & COINIT_APARTMENTTHREADED)
293 EnterCriticalSection(&csApartment);
295 apt = apartment_construct(model);
296 if (!MainApartment)
298 MainApartment = apt;
299 apt->main = TRUE;
300 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
303 LeaveCriticalSection(&csApartment);
305 if (apt->main)
306 apartment_createwindowifneeded(apt);
308 else
310 EnterCriticalSection(&csApartment);
312 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
313 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
314 * in a process */
315 if (MTA)
317 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
318 apartment_addref(MTA);
320 else
321 MTA = apartment_construct(model);
323 apt = MTA;
325 LeaveCriticalSection(&csApartment);
327 COM_CurrentInfo()->apt = apt;
330 return apt;
333 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
335 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
338 DWORD apartment_addref(struct apartment *apt)
340 DWORD refs = InterlockedIncrement(&apt->refs);
341 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
342 return refs;
345 DWORD apartment_release(struct apartment *apt)
347 DWORD ret;
349 EnterCriticalSection(&csApartment);
351 ret = InterlockedDecrement(&apt->refs);
352 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
353 /* destruction stuff that needs to happen under csApartment CS */
354 if (ret == 0)
356 if (apt == MTA) MTA = NULL;
357 else if (apt == MainApartment) MainApartment = NULL;
358 list_remove(&apt->entry);
361 LeaveCriticalSection(&csApartment);
363 if (ret == 0)
365 struct list *cursor, *cursor2;
367 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
369 /* Release the references to the registered class objects */
370 COM_RevokeAllClasses(apt);
372 /* no locking is needed for this apartment, because no other thread
373 * can access it at this point */
375 apartment_disconnectproxies(apt);
377 if (apt->win) DestroyWindow(apt->win);
378 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
380 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
382 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
383 /* release the implicit reference given by the fact that the
384 * stub has external references (it must do since it is in the
385 * stub manager list in the apartment and all non-apartment users
386 * must have a ref on the apartment and so it cannot be destroyed).
388 stub_manager_int_release(stubmgr);
391 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
393 struct registered_psclsid *registered_psclsid =
394 LIST_ENTRY(cursor, struct registered_psclsid, entry);
396 list_remove(&registered_psclsid->entry);
397 HeapFree(GetProcessHeap(), 0, registered_psclsid);
400 /* if this assert fires, then another thread took a reference to a
401 * stub manager without taking a reference to the containing
402 * apartment, which it must do. */
403 assert(list_empty(&apt->stubmgrs));
405 if (apt->filter) IUnknown_Release(apt->filter);
407 /* free as many unused libraries as possible... */
408 apartment_freeunusedlibraries(apt, 0);
410 /* ... and free the memory for the apartment loaded dll entry and
411 * release the dll list reference without freeing the library for the
412 * rest */
413 while ((cursor = list_head(&apt->loaded_dlls)))
415 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
416 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
417 list_remove(cursor);
418 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
421 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
422 DeleteCriticalSection(&apt->cs);
424 HeapFree(GetProcessHeap(), 0, apt);
427 return ret;
430 /* The given OXID must be local to this process:
432 * The ref parameter is here mostly to ensure people remember that
433 * they get one, you should normally take a ref for thread safety.
435 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
437 APARTMENT *result = NULL;
438 struct list *cursor;
440 EnterCriticalSection(&csApartment);
441 LIST_FOR_EACH( cursor, &apts )
443 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
444 if (apt->oxid == oxid)
446 result = apt;
447 if (ref) apartment_addref(result);
448 break;
451 LeaveCriticalSection(&csApartment);
453 return result;
456 /* gets the apartment which has a given creator thread ID. The caller must
457 * release the reference from the apartment as soon as the apartment pointer
458 * is no longer required. */
459 APARTMENT *apartment_findfromtid(DWORD tid)
461 APARTMENT *result = NULL;
462 struct list *cursor;
464 EnterCriticalSection(&csApartment);
465 LIST_FOR_EACH( cursor, &apts )
467 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
468 if (apt->tid == tid)
470 result = apt;
471 apartment_addref(result);
472 break;
475 LeaveCriticalSection(&csApartment);
477 return result;
480 /* gets the main apartment if it exists. The caller must
481 * release the reference from the apartment as soon as the apartment pointer
482 * is no longer required. */
483 static APARTMENT *apartment_findmain(void)
485 APARTMENT *result;
487 EnterCriticalSection(&csApartment);
489 result = MainApartment;
490 if (result) apartment_addref(result);
492 LeaveCriticalSection(&csApartment);
494 return result;
497 /* gets the multi-threaded apartment if it exists. The caller must
498 * release the reference from the apartment as soon as the apartment pointer
499 * is no longer required. */
500 static APARTMENT *apartment_find_multi_threaded(void)
502 APARTMENT *result = NULL;
503 struct list *cursor;
505 EnterCriticalSection(&csApartment);
507 LIST_FOR_EACH( cursor, &apts )
509 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
510 if (apt->multi_threaded)
512 result = apt;
513 apartment_addref(result);
514 break;
518 LeaveCriticalSection(&csApartment);
519 return result;
522 struct host_object_params
524 HKEY hkeydll;
525 CLSID clsid; /* clsid of object to marshal */
526 IID iid; /* interface to marshal */
527 HANDLE event; /* event signalling when ready for multi-threaded case */
528 HRESULT hr; /* result for multi-threaded case */
529 IStream *stream; /* stream that the object will be marshaled into */
530 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
533 static HRESULT apartment_hostobject(struct apartment *apt,
534 const struct host_object_params *params)
536 IUnknown *object;
537 HRESULT hr;
538 static const LARGE_INTEGER llZero;
539 WCHAR dllpath[MAX_PATH+1];
541 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
543 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
545 /* failure: CLSID is not found in registry */
546 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
547 return REGDB_E_CLASSNOTREG;
550 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
551 &params->clsid, &params->iid, (void **)&object);
552 if (FAILED(hr))
553 return hr;
555 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
556 if (FAILED(hr))
557 IUnknown_Release(object);
558 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
560 return hr;
563 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
565 switch (msg)
567 case DM_EXECUTERPC:
568 RPC_ExecuteCall((struct dispatch_params *)lParam);
569 return 0;
570 case DM_HOSTOBJECT:
571 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
572 default:
573 return DefWindowProcW(hWnd, msg, wParam, lParam);
577 struct host_thread_params
579 COINIT threading_model;
580 HANDLE ready_event;
581 HWND apartment_hwnd;
584 /* thread for hosting an object to allow an object to appear to be created in
585 * an apartment with an incompatible threading model */
586 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
588 struct host_thread_params *params = p;
589 MSG msg;
590 HRESULT hr;
591 struct apartment *apt;
593 TRACE("\n");
595 hr = CoInitializeEx(NULL, params->threading_model);
596 if (FAILED(hr)) return hr;
598 apt = COM_CurrentApt();
599 if (params->threading_model == COINIT_APARTMENTTHREADED)
601 apartment_createwindowifneeded(apt);
602 params->apartment_hwnd = apartment_getwindow(apt);
604 else
605 params->apartment_hwnd = NULL;
607 /* force the message queue to be created before signaling parent thread */
608 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
610 SetEvent(params->ready_event);
611 params = NULL; /* can't touch params after here as it may be invalid */
613 while (GetMessageW(&msg, NULL, 0, 0))
615 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
617 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
618 obj_params->hr = apartment_hostobject(apt, obj_params);
619 SetEvent(obj_params->event);
621 else
623 TranslateMessage(&msg);
624 DispatchMessageW(&msg);
628 TRACE("exiting\n");
630 CoUninitialize();
632 return S_OK;
635 /* finds or creates a host apartment, creates the object inside it and returns
636 * a proxy to it so that the object can be used in the apartment of the
637 * caller of this function */
638 static HRESULT apartment_hostobject_in_hostapt(
639 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
640 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
642 struct host_object_params params;
643 HWND apartment_hwnd = NULL;
644 DWORD apartment_tid = 0;
645 HRESULT hr;
647 if (!multi_threaded && main_apartment)
649 APARTMENT *host_apt = apartment_findmain();
650 if (host_apt)
652 apartment_hwnd = apartment_getwindow(host_apt);
653 apartment_release(host_apt);
657 if (!apartment_hwnd)
659 EnterCriticalSection(&apt->cs);
661 if (!apt->host_apt_tid)
663 struct host_thread_params thread_params;
664 HANDLE handles[2];
665 DWORD wait_value;
667 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
668 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
669 thread_params.apartment_hwnd = NULL;
670 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
671 if (!handles[1])
673 CloseHandle(handles[0]);
674 LeaveCriticalSection(&apt->cs);
675 return E_OUTOFMEMORY;
677 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
678 CloseHandle(handles[0]);
679 CloseHandle(handles[1]);
680 if (wait_value == WAIT_OBJECT_0)
681 apt->host_apt_hwnd = thread_params.apartment_hwnd;
682 else
684 LeaveCriticalSection(&apt->cs);
685 return E_OUTOFMEMORY;
689 if (multi_threaded || !main_apartment)
691 apartment_hwnd = apt->host_apt_hwnd;
692 apartment_tid = apt->host_apt_tid;
695 LeaveCriticalSection(&apt->cs);
698 /* another thread may have become the main apartment in the time it took
699 * us to create the thread for the host apartment */
700 if (!apartment_hwnd && !multi_threaded && main_apartment)
702 APARTMENT *host_apt = apartment_findmain();
703 if (host_apt)
705 apartment_hwnd = apartment_getwindow(host_apt);
706 apartment_release(host_apt);
710 params.hkeydll = hkeydll;
711 params.clsid = *rclsid;
712 params.iid = *riid;
713 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
714 if (FAILED(hr))
715 return hr;
716 params.apartment_threaded = !multi_threaded;
717 if (multi_threaded)
719 params.hr = S_OK;
720 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
721 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
722 hr = E_OUTOFMEMORY;
723 else
725 WaitForSingleObject(params.event, INFINITE);
726 hr = params.hr;
728 CloseHandle(params.event);
730 else
732 if (!apartment_hwnd)
734 ERR("host apartment didn't create window\n");
735 hr = E_OUTOFMEMORY;
737 else
738 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
740 if (SUCCEEDED(hr))
741 hr = CoUnmarshalInterface(params.stream, riid, ppv);
742 IStream_Release(params.stream);
743 return hr;
746 /* create a window for the apartment or return the current one if one has
747 * already been created */
748 HRESULT apartment_createwindowifneeded(struct apartment *apt)
750 if (apt->multi_threaded)
751 return S_OK;
753 if (!apt->win)
755 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
756 0, 0, 0, 0,
757 HWND_MESSAGE, 0, hProxyDll, NULL);
758 if (!hwnd)
760 ERR("CreateWindow failed with error %d\n", GetLastError());
761 return HRESULT_FROM_WIN32(GetLastError());
763 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
764 /* someone beat us to it */
765 DestroyWindow(hwnd);
768 return S_OK;
771 /* retrieves the window for the main- or apartment-threaded apartment */
772 HWND apartment_getwindow(const struct apartment *apt)
774 assert(!apt->multi_threaded);
775 return apt->win;
778 void apartment_joinmta(void)
780 apartment_addref(MTA);
781 COM_CurrentInfo()->apt = MTA;
784 /* gets the specified class object by loading the appropriate DLL, if
785 * necessary and calls the DllGetClassObject function for the DLL */
786 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
787 BOOL apartment_threaded,
788 REFCLSID rclsid, REFIID riid, void **ppv)
790 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
791 HRESULT hr = S_OK;
792 BOOL found = FALSE;
793 struct apartment_loaded_dll *apartment_loaded_dll;
795 if (!strcmpiW(dllpath, wszOle32))
797 /* we don't need to control the lifetime of this dll, so use the local
798 * implementation of DllGetClassObject directly */
799 TRACE("calling ole32!DllGetClassObject\n");
800 hr = DllGetClassObject(rclsid, riid, ppv);
802 if (hr != S_OK)
803 ERR("DllGetClassObject returned error 0x%08x\n", hr);
805 return hr;
808 EnterCriticalSection(&apt->cs);
810 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
811 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
813 TRACE("found %s already loaded\n", debugstr_w(dllpath));
814 found = TRUE;
815 break;
818 if (!found)
820 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
821 if (!apartment_loaded_dll)
822 hr = E_OUTOFMEMORY;
823 if (SUCCEEDED(hr))
825 apartment_loaded_dll->unload_time = 0;
826 apartment_loaded_dll->multi_threaded = FALSE;
827 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
828 if (FAILED(hr))
829 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
831 if (SUCCEEDED(hr))
833 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
834 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
838 LeaveCriticalSection(&apt->cs);
840 if (SUCCEEDED(hr))
842 /* one component being multi-threaded overrides any number of
843 * apartment-threaded components */
844 if (!apartment_threaded)
845 apartment_loaded_dll->multi_threaded = TRUE;
847 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
848 /* OK: get the ClassObject */
849 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
851 if (hr != S_OK)
852 ERR("DllGetClassObject returned error 0x%08x\n", hr);
855 return hr;
858 /* frees unused libraries loaded by apartment_getclassobject by calling the
859 * DLL's DllCanUnloadNow entry point */
860 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
862 struct apartment_loaded_dll *entry, *next;
863 EnterCriticalSection(&apt->cs);
864 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
866 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
868 DWORD real_delay = delay;
870 if (real_delay == INFINITE)
872 /* DLLs that return multi-threaded objects aren't unloaded
873 * straight away to cope for programs that have races between
874 * last object destruction and threads in the DLLs that haven't
875 * finished, despite DllCanUnloadNow returning S_OK */
876 if (entry->multi_threaded)
877 real_delay = 10 * 60 * 1000; /* 10 minutes */
878 else
879 real_delay = 0;
882 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
884 list_remove(&entry->entry);
885 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
886 HeapFree(GetProcessHeap(), 0, entry);
888 else
889 entry->unload_time = GetTickCount() + real_delay;
891 else if (entry->unload_time)
892 entry->unload_time = 0;
894 LeaveCriticalSection(&apt->cs);
897 /*****************************************************************************
898 * This section contains OpenDllList implementation
901 /* caller must ensure that library_name is not already in the open dll list */
902 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
904 OpenDll *entry;
905 int len;
906 HRESULT hr = S_OK;
907 HANDLE hLibrary;
908 DllCanUnloadNowFunc DllCanUnloadNow;
909 DllGetClassObjectFunc DllGetClassObject;
911 TRACE("\n");
913 *ret = COMPOBJ_DllList_Get(library_name);
914 if (*ret) return S_OK;
916 /* do this outside the csOpenDllList to avoid creating a lock dependency on
917 * the loader lock */
918 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
919 if (!hLibrary)
921 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
922 /* failure: DLL could not be loaded */
923 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
926 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
927 /* Note: failing to find DllCanUnloadNow is not a failure */
928 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
929 if (!DllGetClassObject)
931 /* failure: the dll did not export DllGetClassObject */
932 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
933 FreeLibrary(hLibrary);
934 return CO_E_DLLNOTFOUND;
937 EnterCriticalSection( &csOpenDllList );
939 *ret = COMPOBJ_DllList_Get(library_name);
940 if (*ret)
942 /* another caller to this function already added the dll while we
943 * weren't in the critical section */
944 FreeLibrary(hLibrary);
946 else
948 len = strlenW(library_name);
949 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
950 if (entry)
951 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
952 if (entry && entry->library_name)
954 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
955 entry->library = hLibrary;
956 entry->refs = 1;
957 entry->DllCanUnloadNow = DllCanUnloadNow;
958 entry->DllGetClassObject = DllGetClassObject;
959 list_add_tail(&openDllList, &entry->entry);
961 else
963 HeapFree(GetProcessHeap(), 0, entry);
964 hr = E_OUTOFMEMORY;
965 FreeLibrary(hLibrary);
967 *ret = entry;
970 LeaveCriticalSection( &csOpenDllList );
972 return hr;
975 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
977 OpenDll *ptr;
978 OpenDll *ret = NULL;
979 EnterCriticalSection(&csOpenDllList);
980 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
982 if (!strcmpiW(library_name, ptr->library_name) &&
983 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
985 ret = ptr;
986 break;
989 LeaveCriticalSection(&csOpenDllList);
990 return ret;
993 /* pass FALSE for free_entry to release a reference without destroying the
994 * entry if it reaches zero or TRUE otherwise */
995 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
997 if (!InterlockedDecrement(&entry->refs) && free_entry)
999 EnterCriticalSection(&csOpenDllList);
1000 list_remove(&entry->entry);
1001 LeaveCriticalSection(&csOpenDllList);
1003 TRACE("freeing %p\n", entry->library);
1004 FreeLibrary(entry->library);
1006 HeapFree(GetProcessHeap(), 0, entry->library_name);
1007 HeapFree(GetProcessHeap(), 0, entry);
1011 /* frees memory associated with active dll list */
1012 static void COMPOBJ_DllList_Free(void)
1014 OpenDll *entry, *cursor2;
1015 EnterCriticalSection(&csOpenDllList);
1016 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
1018 list_remove(&entry->entry);
1020 HeapFree(GetProcessHeap(), 0, entry->library_name);
1021 HeapFree(GetProcessHeap(), 0, entry);
1023 LeaveCriticalSection(&csOpenDllList);
1026 /******************************************************************************
1027 * CoBuildVersion [OLE32.@]
1029 * Gets the build version of the DLL.
1031 * PARAMS
1033 * RETURNS
1034 * Current build version, hiword is majornumber, loword is minornumber
1036 DWORD WINAPI CoBuildVersion(void)
1038 TRACE("Returning version %d, build %d.\n", rmm, rup);
1039 return (rmm<<16)+rup;
1042 /******************************************************************************
1043 * CoRegisterInitializeSpy [OLE32.@]
1045 * Add a Spy that watches CoInitializeEx calls
1047 * PARAMS
1048 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1049 * cookie [II] cookie receiver
1051 * RETURNS
1052 * Success: S_OK if not already initialized, S_FALSE otherwise.
1053 * Failure: HRESULT code.
1055 * SEE ALSO
1056 * CoInitializeEx
1058 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1060 struct oletls *info = COM_CurrentInfo();
1061 HRESULT hr;
1063 TRACE("(%p, %p)\n", spy, cookie);
1065 if (!spy || !cookie || !info)
1067 if (!info)
1068 WARN("Could not allocate tls\n");
1069 return E_INVALIDARG;
1072 if (info->spy)
1074 FIXME("Already registered?\n");
1075 return E_UNEXPECTED;
1078 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1079 if (SUCCEEDED(hr))
1081 cookie->QuadPart = (DWORD_PTR)spy;
1082 return S_OK;
1084 return hr;
1087 /******************************************************************************
1088 * CoRevokeInitializeSpy [OLE32.@]
1090 * Remove a spy that previously watched CoInitializeEx calls
1092 * PARAMS
1093 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1095 * RETURNS
1096 * Success: S_OK if a spy is removed
1097 * Failure: E_INVALIDARG
1099 * SEE ALSO
1100 * CoInitializeEx
1102 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1104 struct oletls *info = COM_CurrentInfo();
1105 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1107 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1108 return E_INVALIDARG;
1110 IUnknown_Release(info->spy);
1111 info->spy = NULL;
1112 return S_OK;
1116 /******************************************************************************
1117 * CoInitialize [OLE32.@]
1119 * Initializes the COM libraries by calling CoInitializeEx with
1120 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1122 * PARAMS
1123 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1125 * RETURNS
1126 * Success: S_OK if not already initialized, S_FALSE otherwise.
1127 * Failure: HRESULT code.
1129 * SEE ALSO
1130 * CoInitializeEx
1132 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1135 * Just delegate to the newer method.
1137 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1140 /******************************************************************************
1141 * CoInitializeEx [OLE32.@]
1143 * Initializes the COM libraries.
1145 * PARAMS
1146 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1147 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1149 * RETURNS
1150 * S_OK if successful,
1151 * S_FALSE if this function was called already.
1152 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1153 * threading model.
1155 * NOTES
1157 * The behavior used to set the IMalloc used for memory management is
1158 * obsolete.
1159 * The dwCoInit parameter must specify one of the following apartment
1160 * threading models:
1161 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1162 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1163 * The parameter may also specify zero or more of the following flags:
1164 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1165 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1167 * SEE ALSO
1168 * CoUninitialize
1170 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1172 struct oletls *info = COM_CurrentInfo();
1173 HRESULT hr = S_OK;
1174 APARTMENT *apt;
1176 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1178 if (lpReserved!=NULL)
1180 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1184 * Check the lock count. If this is the first time going through the initialize
1185 * process, we have to initialize the libraries.
1187 * And crank-up that lock count.
1189 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1192 * Initialize the various COM libraries and data structures.
1194 TRACE("() - Initializing the COM libraries\n");
1196 /* we may need to defer this until after apartment initialisation */
1197 RunningObjectTableImpl_Initialize();
1200 if (info->spy)
1201 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1203 if (!(apt = info->apt))
1205 apt = apartment_get_or_create(dwCoInit);
1206 if (!apt) return E_OUTOFMEMORY;
1208 else if (!apartment_is_model(apt, dwCoInit))
1210 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1211 code then we are probably using the wrong threading model to implement that API. */
1212 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1213 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1214 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1215 return RPC_E_CHANGED_MODE;
1217 else
1218 hr = S_FALSE;
1220 info->inits++;
1222 if (info->spy)
1223 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1225 return hr;
1228 /***********************************************************************
1229 * CoUninitialize [OLE32.@]
1231 * This method will decrement the refcount on the current apartment, freeing
1232 * the resources associated with it if it is the last thread in the apartment.
1233 * If the last apartment is freed, the function will additionally release
1234 * any COM resources associated with the process.
1236 * PARAMS
1238 * RETURNS
1239 * Nothing.
1241 * SEE ALSO
1242 * CoInitializeEx
1244 void WINAPI CoUninitialize(void)
1246 struct oletls * info = COM_CurrentInfo();
1247 LONG lCOMRefCnt;
1249 TRACE("()\n");
1251 /* will only happen on OOM */
1252 if (!info) return;
1254 if (info->spy)
1255 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1257 /* sanity check */
1258 if (!info->inits)
1260 ERR("Mismatched CoUninitialize\n");
1262 if (info->spy)
1263 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1264 return;
1267 if (!--info->inits)
1269 apartment_release(info->apt);
1270 info->apt = NULL;
1274 * Decrease the reference count.
1275 * If we are back to 0 locks on the COM library, make sure we free
1276 * all the associated data structures.
1278 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1279 if (lCOMRefCnt==1)
1281 TRACE("() - Releasing the COM libraries\n");
1283 RunningObjectTableImpl_UnInitialize();
1285 else if (lCOMRefCnt<1) {
1286 ERR( "CoUninitialize() - not CoInitialized.\n" );
1287 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1289 if (info->spy)
1290 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1293 /******************************************************************************
1294 * CoDisconnectObject [OLE32.@]
1296 * Disconnects all connections to this object from remote processes. Dispatches
1297 * pending RPCs while blocking new RPCs from occurring, and then calls
1298 * IMarshal::DisconnectObject on the given object.
1300 * Typically called when the object server is forced to shut down, for instance by
1301 * the user.
1303 * PARAMS
1304 * lpUnk [I] The object whose stub should be disconnected.
1305 * reserved [I] Reserved. Should be set to 0.
1307 * RETURNS
1308 * Success: S_OK.
1309 * Failure: HRESULT code.
1311 * SEE ALSO
1312 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1314 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1316 HRESULT hr;
1317 IMarshal *marshal;
1318 APARTMENT *apt;
1320 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1322 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1323 if (hr == S_OK)
1325 hr = IMarshal_DisconnectObject(marshal, reserved);
1326 IMarshal_Release(marshal);
1327 return hr;
1330 apt = COM_CurrentApt();
1331 if (!apt)
1332 return CO_E_NOTINITIALIZED;
1334 apartment_disconnectobject(apt, lpUnk);
1336 /* Note: native is pretty broken here because it just silently
1337 * fails, without returning an appropriate error code if the object was
1338 * not found, making apps think that the object was disconnected, when
1339 * it actually wasn't */
1341 return S_OK;
1344 /******************************************************************************
1345 * CoCreateGuid [OLE32.@]
1347 * Simply forwards to UuidCreate in RPCRT4.
1349 * PARAMS
1350 * pguid [O] Points to the GUID to initialize.
1352 * RETURNS
1353 * Success: S_OK.
1354 * Failure: HRESULT code.
1356 * SEE ALSO
1357 * UuidCreate
1359 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1361 DWORD status = UuidCreate(pguid);
1362 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1363 return HRESULT_FROM_WIN32( status );
1366 /******************************************************************************
1367 * CLSIDFromString [OLE32.@]
1368 * IIDFromString [OLE32.@]
1370 * Converts a unique identifier from its string representation into
1371 * the GUID struct.
1373 * PARAMS
1374 * idstr [I] The string representation of the GUID.
1375 * id [O] GUID converted from the string.
1377 * RETURNS
1378 * S_OK on success
1379 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1381 * SEE ALSO
1382 * StringFromCLSID
1384 static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1386 int i;
1387 BYTE table[256];
1389 if (!s) {
1390 memset( id, 0, sizeof (CLSID) );
1391 return S_OK;
1394 /* validate the CLSID string */
1395 if (strlenW(s) != 38)
1396 return CO_E_CLASSSTRING;
1398 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1399 return CO_E_CLASSSTRING;
1401 for (i=1; i<37; i++) {
1402 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1403 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1404 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1405 ((s[i] >= 'A') && (s[i] <= 'F'))))
1406 return CO_E_CLASSSTRING;
1409 TRACE("%s -> %p\n", debugstr_w(s), id);
1411 /* quick lookup table */
1412 memset(table, 0, 256);
1414 for (i = 0; i < 10; i++) {
1415 table['0' + i] = i;
1417 for (i = 0; i < 6; i++) {
1418 table['A' + i] = i+10;
1419 table['a' + i] = i+10;
1422 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1424 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1425 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1426 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1427 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1429 /* these are just sequential bytes */
1430 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1431 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1432 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1433 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1434 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1435 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1436 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1437 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1439 return S_OK;
1442 /*****************************************************************************/
1444 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1446 HRESULT ret;
1448 if (!id)
1449 return E_INVALIDARG;
1451 ret = __CLSIDFromString(idstr, id);
1452 if(ret != S_OK) { /* It appears a ProgID is also valid */
1453 ret = CLSIDFromProgID(idstr, id);
1455 return ret;
1459 /******************************************************************************
1460 * StringFromCLSID [OLE32.@]
1461 * StringFromIID [OLE32.@]
1463 * Converts a GUID into the respective string representation.
1464 * The target string is allocated using the OLE IMalloc.
1466 * PARAMS
1467 * id [I] the GUID to be converted.
1468 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1470 * RETURNS
1471 * S_OK
1472 * E_FAIL
1474 * SEE ALSO
1475 * StringFromGUID2, CLSIDFromString
1477 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1479 HRESULT ret;
1480 LPMALLOC mllc;
1482 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1483 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1484 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1485 return S_OK;
1488 /******************************************************************************
1489 * StringFromGUID2 [OLE32.@]
1491 * Modified version of StringFromCLSID that allows you to specify max
1492 * buffer size.
1494 * PARAMS
1495 * id [I] GUID to convert to string.
1496 * str [O] Buffer where the result will be stored.
1497 * cmax [I] Size of the buffer in characters.
1499 * RETURNS
1500 * Success: The length of the resulting string in characters.
1501 * Failure: 0.
1503 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1505 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1506 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1507 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1508 '%','0','2','X','%','0','2','X','}',0 };
1509 if (cmax < CHARS_IN_GUID) return 0;
1510 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1511 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1512 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1513 return CHARS_IN_GUID;
1516 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1517 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1519 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1520 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1521 LONG res;
1522 HKEY key;
1524 strcpyW(path, wszCLSIDSlash);
1525 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1526 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1527 if (res == ERROR_FILE_NOT_FOUND)
1528 return REGDB_E_CLASSNOTREG;
1529 else if (res != ERROR_SUCCESS)
1530 return REGDB_E_READREGDB;
1532 if (!keyname)
1534 *subkey = key;
1535 return S_OK;
1538 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1539 RegCloseKey(key);
1540 if (res == ERROR_FILE_NOT_FOUND)
1541 return REGDB_E_KEYMISSING;
1542 else if (res != ERROR_SUCCESS)
1543 return REGDB_E_READREGDB;
1545 return S_OK;
1548 /* open HKCR\\AppId\\{string form of appid clsid} key */
1549 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1551 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1552 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1553 DWORD res;
1554 WCHAR buf[CHARS_IN_GUID];
1555 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1556 DWORD size;
1557 HKEY hkey;
1558 DWORD type;
1559 HRESULT hr;
1561 /* read the AppID value under the class's key */
1562 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1563 if (FAILED(hr))
1564 return hr;
1566 size = sizeof(buf);
1567 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1568 RegCloseKey(hkey);
1569 if (res == ERROR_FILE_NOT_FOUND)
1570 return REGDB_E_KEYMISSING;
1571 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1572 return REGDB_E_READREGDB;
1574 strcpyW(keyname, szAppIdKey);
1575 strcatW(keyname, buf);
1576 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1577 if (res == ERROR_FILE_NOT_FOUND)
1578 return REGDB_E_KEYMISSING;
1579 else if (res != ERROR_SUCCESS)
1580 return REGDB_E_READREGDB;
1582 return S_OK;
1585 /******************************************************************************
1586 * ProgIDFromCLSID [OLE32.@]
1588 * Converts a class id into the respective program ID.
1590 * PARAMS
1591 * clsid [I] Class ID, as found in registry.
1592 * ppszProgID [O] Associated ProgID.
1594 * RETURNS
1595 * S_OK
1596 * E_OUTOFMEMORY
1597 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1599 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1601 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1602 HKEY hkey;
1603 HRESULT ret;
1604 LONG progidlen = 0;
1606 if (!ppszProgID)
1608 ERR("ppszProgId isn't optional\n");
1609 return E_INVALIDARG;
1612 *ppszProgID = NULL;
1613 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1614 if (FAILED(ret))
1615 return ret;
1617 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1618 ret = REGDB_E_CLASSNOTREG;
1620 if (ret == S_OK)
1622 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1623 if (*ppszProgID)
1625 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1626 ret = REGDB_E_CLASSNOTREG;
1628 else
1629 ret = E_OUTOFMEMORY;
1632 RegCloseKey(hkey);
1633 return ret;
1636 /******************************************************************************
1637 * CLSIDFromProgID [OLE32.@]
1639 * Converts a program id into the respective GUID.
1641 * PARAMS
1642 * progid [I] Unicode program ID, as found in registry.
1643 * clsid [O] Associated CLSID.
1645 * RETURNS
1646 * Success: S_OK
1647 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1649 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1651 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1652 WCHAR buf2[CHARS_IN_GUID];
1653 LONG buf2len = sizeof(buf2);
1654 HKEY xhkey;
1655 WCHAR *buf;
1657 if (!progid || !clsid)
1659 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1660 return E_INVALIDARG;
1663 /* initialise clsid in case of failure */
1664 memset(clsid, 0, sizeof(*clsid));
1666 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1667 strcpyW( buf, progid );
1668 strcatW( buf, clsidW );
1669 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1671 HeapFree(GetProcessHeap(),0,buf);
1672 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1673 return CO_E_CLASSSTRING;
1675 HeapFree(GetProcessHeap(),0,buf);
1677 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1679 RegCloseKey(xhkey);
1680 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1681 return CO_E_CLASSSTRING;
1683 RegCloseKey(xhkey);
1684 return __CLSIDFromString(buf2,clsid);
1688 /*****************************************************************************
1689 * CoGetPSClsid [OLE32.@]
1691 * Retrieves the CLSID of the proxy/stub factory that implements
1692 * IPSFactoryBuffer for the specified interface.
1694 * PARAMS
1695 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1696 * pclsid [O] Where to store returned proxy/stub CLSID.
1698 * RETURNS
1699 * S_OK
1700 * E_OUTOFMEMORY
1701 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1703 * NOTES
1705 * The standard marshaller activates the object with the CLSID
1706 * returned and uses the CreateProxy and CreateStub methods on its
1707 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1708 * given object.
1710 * CoGetPSClsid determines this CLSID by searching the
1711 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1712 * in the registry and any interface id registered by
1713 * CoRegisterPSClsid within the current process.
1715 * BUGS
1717 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1718 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1719 * considered a bug in native unless an application depends on this (unlikely).
1721 * SEE ALSO
1722 * CoRegisterPSClsid.
1724 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1726 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1727 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1728 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1729 WCHAR value[CHARS_IN_GUID];
1730 LONG len;
1731 HKEY hkey;
1732 APARTMENT *apt = COM_CurrentApt();
1733 struct registered_psclsid *registered_psclsid;
1735 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1737 if (!apt)
1739 ERR("apartment not initialised\n");
1740 return CO_E_NOTINITIALIZED;
1743 if (!pclsid)
1745 ERR("pclsid isn't optional\n");
1746 return E_INVALIDARG;
1749 EnterCriticalSection(&apt->cs);
1751 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1752 if (IsEqualIID(&registered_psclsid->iid, riid))
1754 *pclsid = registered_psclsid->clsid;
1755 LeaveCriticalSection(&apt->cs);
1756 return S_OK;
1759 LeaveCriticalSection(&apt->cs);
1761 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1762 strcpyW(path, wszInterface);
1763 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1764 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1766 /* Open the key.. */
1767 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1769 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1770 return REGDB_E_IIDNOTREG;
1773 /* ... Once we have the key, query the registry to get the
1774 value of CLSID as a string, and convert it into a
1775 proper CLSID structure to be passed back to the app */
1776 len = sizeof(value);
1777 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1779 RegCloseKey(hkey);
1780 return REGDB_E_IIDNOTREG;
1782 RegCloseKey(hkey);
1784 /* We have the CLSID we want back from the registry as a string, so
1785 let's convert it into a CLSID structure */
1786 if (CLSIDFromString(value, pclsid) != NOERROR)
1787 return REGDB_E_IIDNOTREG;
1789 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1790 return S_OK;
1793 /*****************************************************************************
1794 * CoRegisterPSClsid [OLE32.@]
1796 * Register a proxy/stub CLSID for the given interface in the current process
1797 * only.
1799 * PARAMS
1800 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1801 * rclsid [I] CLSID of the proxy/stub.
1803 * RETURNS
1804 * Success: S_OK
1805 * Failure: E_OUTOFMEMORY
1807 * NOTES
1809 * This function does not add anything to the registry and the effects are
1810 * limited to the lifetime of the current process.
1812 * SEE ALSO
1813 * CoGetPSClsid.
1815 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1817 APARTMENT *apt = COM_CurrentApt();
1818 struct registered_psclsid *registered_psclsid;
1820 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1822 if (!apt)
1824 ERR("apartment not initialised\n");
1825 return CO_E_NOTINITIALIZED;
1828 EnterCriticalSection(&apt->cs);
1830 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1831 if (IsEqualIID(&registered_psclsid->iid, riid))
1833 registered_psclsid->clsid = *rclsid;
1834 LeaveCriticalSection(&apt->cs);
1835 return S_OK;
1838 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1839 if (!registered_psclsid)
1841 LeaveCriticalSection(&apt->cs);
1842 return E_OUTOFMEMORY;
1845 registered_psclsid->iid = *riid;
1846 registered_psclsid->clsid = *rclsid;
1847 list_add_head(&apt->psclsids, &registered_psclsid->entry);
1849 LeaveCriticalSection(&apt->cs);
1851 return S_OK;
1855 /***
1856 * COM_GetRegisteredClassObject
1858 * This internal method is used to scan the registered class list to
1859 * find a class object.
1861 * Params:
1862 * rclsid Class ID of the class to find.
1863 * dwClsContext Class context to match.
1864 * ppv [out] returns a pointer to the class object. Complying
1865 * to normal COM usage, this method will increase the
1866 * reference count on this object.
1868 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1869 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1871 HRESULT hr = S_FALSE;
1872 RegisteredClass *curClass;
1874 EnterCriticalSection( &csRegisteredClassList );
1876 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1879 * Check if we have a match on the class ID and context.
1881 if ((apt->oxid == curClass->apartment_id) &&
1882 (dwClsContext & curClass->runContext) &&
1883 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1886 * We have a match, return the pointer to the class object.
1888 *ppUnk = curClass->classObject;
1890 IUnknown_AddRef(curClass->classObject);
1892 hr = S_OK;
1893 break;
1897 LeaveCriticalSection( &csRegisteredClassList );
1899 return hr;
1902 /******************************************************************************
1903 * CoRegisterClassObject [OLE32.@]
1905 * Registers the class object for a given class ID. Servers housed in EXE
1906 * files use this method instead of exporting DllGetClassObject to allow
1907 * other code to connect to their objects.
1909 * PARAMS
1910 * rclsid [I] CLSID of the object to register.
1911 * pUnk [I] IUnknown of the object.
1912 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1913 * flags [I] REGCLS flags indicating how connections are made.
1914 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1916 * RETURNS
1917 * S_OK on success,
1918 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1919 * CO_E_OBJISREG if the object is already registered. We should not return this.
1921 * SEE ALSO
1922 * CoRevokeClassObject, CoGetClassObject
1924 * NOTES
1925 * In-process objects are only registered for the current apartment.
1926 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1927 * in other apartments.
1929 * BUGS
1930 * MSDN claims that multiple interface registrations are legal, but we
1931 * can't do that with our current implementation.
1933 HRESULT WINAPI CoRegisterClassObject(
1934 REFCLSID rclsid,
1935 LPUNKNOWN pUnk,
1936 DWORD dwClsContext,
1937 DWORD flags,
1938 LPDWORD lpdwRegister)
1940 RegisteredClass* newClass;
1941 LPUNKNOWN foundObject;
1942 HRESULT hr;
1943 APARTMENT *apt;
1945 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1946 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1948 if ( (lpdwRegister==0) || (pUnk==0) )
1949 return E_INVALIDARG;
1951 apt = COM_CurrentApt();
1952 if (!apt)
1954 ERR("COM was not initialized\n");
1955 return CO_E_NOTINITIALIZED;
1958 *lpdwRegister = 0;
1960 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1961 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1962 if (flags & REGCLS_MULTIPLEUSE)
1963 dwClsContext |= CLSCTX_INPROC_SERVER;
1966 * First, check if the class is already registered.
1967 * If it is, this should cause an error.
1969 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1970 if (hr == S_OK) {
1971 if (flags & REGCLS_MULTIPLEUSE) {
1972 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1973 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1974 IUnknown_Release(foundObject);
1975 return hr;
1977 IUnknown_Release(foundObject);
1978 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1979 return CO_E_OBJISREG;
1982 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1983 if ( newClass == NULL )
1984 return E_OUTOFMEMORY;
1986 newClass->classIdentifier = *rclsid;
1987 newClass->apartment_id = apt->oxid;
1988 newClass->runContext = dwClsContext;
1989 newClass->connectFlags = flags;
1990 newClass->pMarshaledData = NULL;
1991 newClass->RpcRegistration = NULL;
1994 * Use the address of the chain node as the cookie since we are sure it's
1995 * unique. FIXME: not on 64-bit platforms.
1997 newClass->dwCookie = (DWORD)newClass;
2000 * Since we're making a copy of the object pointer, we have to increase its
2001 * reference count.
2003 newClass->classObject = pUnk;
2004 IUnknown_AddRef(newClass->classObject);
2006 EnterCriticalSection( &csRegisteredClassList );
2007 list_add_tail(&RegisteredClassList, &newClass->entry);
2008 LeaveCriticalSection( &csRegisteredClassList );
2010 *lpdwRegister = newClass->dwCookie;
2012 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2013 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2014 if (hr) {
2015 FIXME("Failed to create stream on hglobal, %x\n", hr);
2016 return hr;
2018 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
2019 newClass->classObject, MSHCTX_LOCAL, NULL,
2020 MSHLFLAGS_TABLESTRONG);
2021 if (hr) {
2022 FIXME("CoMarshalInterface failed, %x!\n",hr);
2023 return hr;
2026 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2027 newClass->pMarshaledData,
2028 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2029 &newClass->RpcRegistration);
2031 return S_OK;
2034 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
2036 list_remove(&curClass->entry);
2038 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
2039 RPC_StopLocalServer(curClass->RpcRegistration);
2042 * Release the reference to the class object.
2044 IUnknown_Release(curClass->classObject);
2046 if (curClass->pMarshaledData)
2048 LARGE_INTEGER zero;
2049 memset(&zero, 0, sizeof(zero));
2050 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
2051 CoReleaseMarshalData(curClass->pMarshaledData);
2052 IStream_Release(curClass->pMarshaledData);
2055 HeapFree(GetProcessHeap(), 0, curClass);
2058 static void COM_RevokeAllClasses(const struct apartment *apt)
2060 RegisteredClass *curClass, *cursor;
2062 EnterCriticalSection( &csRegisteredClassList );
2064 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
2066 if (curClass->apartment_id == apt->oxid)
2067 COM_RevokeRegisteredClassObject(curClass);
2070 LeaveCriticalSection( &csRegisteredClassList );
2073 /***********************************************************************
2074 * CoRevokeClassObject [OLE32.@]
2076 * Removes a class object from the class registry.
2078 * PARAMS
2079 * dwRegister [I] Cookie returned from CoRegisterClassObject().
2081 * RETURNS
2082 * Success: S_OK.
2083 * Failure: HRESULT code.
2085 * NOTES
2086 * Must be called from the same apartment that called CoRegisterClassObject(),
2087 * otherwise it will fail with RPC_E_WRONG_THREAD.
2089 * SEE ALSO
2090 * CoRegisterClassObject
2092 HRESULT WINAPI CoRevokeClassObject(
2093 DWORD dwRegister)
2095 HRESULT hr = E_INVALIDARG;
2096 RegisteredClass *curClass;
2097 APARTMENT *apt;
2099 TRACE("(%08x)\n",dwRegister);
2101 apt = COM_CurrentApt();
2102 if (!apt)
2104 ERR("COM was not initialized\n");
2105 return CO_E_NOTINITIALIZED;
2108 EnterCriticalSection( &csRegisteredClassList );
2110 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2113 * Check if we have a match on the cookie.
2115 if (curClass->dwCookie == dwRegister)
2117 if (curClass->apartment_id == apt->oxid)
2119 COM_RevokeRegisteredClassObject(curClass);
2120 hr = S_OK;
2122 else
2124 ERR("called from wrong apartment, should be called from %s\n",
2125 wine_dbgstr_longlong(curClass->apartment_id));
2126 hr = RPC_E_WRONG_THREAD;
2128 break;
2132 LeaveCriticalSection( &csRegisteredClassList );
2134 return hr;
2137 /***********************************************************************
2138 * COM_RegReadPath [internal]
2140 * Reads a registry value and expands it when necessary
2142 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2144 DWORD ret;
2145 HKEY key;
2146 DWORD keytype;
2147 WCHAR src[MAX_PATH];
2148 DWORD dwLength = dstlen * sizeof(WCHAR);
2150 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
2151 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2152 if (keytype == REG_EXPAND_SZ) {
2153 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2154 } else {
2155 lstrcpynW(dst, src, dstlen);
2158 RegCloseKey (key);
2160 return ret;
2163 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2165 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2166 DWORD keytype;
2167 DWORD ret;
2168 DWORD dwLength = len * sizeof(WCHAR);
2170 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2171 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2172 value[0] = '\0';
2175 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2176 REFCLSID rclsid, REFIID riid,
2177 BOOL hostifnecessary, void **ppv)
2179 WCHAR dllpath[MAX_PATH+1];
2180 BOOL apartment_threaded;
2182 if (hostifnecessary)
2184 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2185 static const WCHAR wszFree[] = {'F','r','e','e',0};
2186 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2187 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2189 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2190 /* "Apartment" */
2191 if (!strcmpiW(threading_model, wszApartment))
2193 apartment_threaded = TRUE;
2194 if (apt->multi_threaded)
2195 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2197 /* "Free" */
2198 else if (!strcmpiW(threading_model, wszFree))
2200 apartment_threaded = FALSE;
2201 if (!apt->multi_threaded)
2202 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2204 /* everything except "Apartment", "Free" and "Both" */
2205 else if (strcmpiW(threading_model, wszBoth))
2207 apartment_threaded = TRUE;
2208 /* everything else is main-threaded */
2209 if (threading_model[0])
2210 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2211 debugstr_w(threading_model), debugstr_guid(rclsid));
2213 if (apt->multi_threaded || !apt->main)
2214 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2216 else
2217 apartment_threaded = FALSE;
2219 else
2220 apartment_threaded = !apt->multi_threaded;
2222 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2224 /* failure: CLSID is not found in registry */
2225 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2226 return REGDB_E_CLASSNOTREG;
2229 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2230 rclsid, riid, ppv);
2233 /***********************************************************************
2234 * CoGetClassObject [OLE32.@]
2236 * Creates an object of the specified class.
2238 * PARAMS
2239 * rclsid [I] Class ID to create an instance of.
2240 * dwClsContext [I] Flags to restrict the location of the created instance.
2241 * pServerInfo [I] Optional. Details for connecting to a remote server.
2242 * iid [I] The ID of the interface of the instance to return.
2243 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2245 * RETURNS
2246 * Success: S_OK
2247 * Failure: HRESULT code.
2249 * NOTES
2250 * The dwClsContext parameter can be one or more of the following:
2251 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2252 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2253 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2254 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2256 * SEE ALSO
2257 * CoCreateInstance()
2259 HRESULT WINAPI CoGetClassObject(
2260 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2261 REFIID iid, LPVOID *ppv)
2263 LPUNKNOWN regClassObject;
2264 HRESULT hres = E_UNEXPECTED;
2265 APARTMENT *apt;
2266 BOOL release_apt = FALSE;
2268 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2270 if (!ppv)
2271 return E_INVALIDARG;
2273 *ppv = NULL;
2275 if (!(apt = COM_CurrentApt()))
2277 if (!(apt = apartment_find_multi_threaded()))
2279 ERR("apartment not initialised\n");
2280 return CO_E_NOTINITIALIZED;
2282 release_apt = TRUE;
2285 if (pServerInfo) {
2286 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2287 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2291 * First, try and see if we can't match the class ID with one of the
2292 * registered classes.
2294 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2295 &regClassObject))
2297 /* Get the required interface from the retrieved pointer. */
2298 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2301 * Since QI got another reference on the pointer, we want to release the
2302 * one we already have. If QI was unsuccessful, this will release the object. This
2303 * is good since we are not returning it in the "out" parameter.
2305 IUnknown_Release(regClassObject);
2306 if (release_apt) apartment_release(apt);
2307 return hres;
2310 /* First try in-process server */
2311 if (CLSCTX_INPROC_SERVER & dwClsContext)
2313 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2314 HKEY hkey;
2316 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2318 if (release_apt) apartment_release(apt);
2319 return FTMarshalCF_Create(iid, ppv);
2322 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2323 if (FAILED(hres))
2325 if (hres == REGDB_E_CLASSNOTREG)
2326 ERR("class %s not registered\n", debugstr_guid(rclsid));
2327 else if (hres == REGDB_E_KEYMISSING)
2329 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2330 hres = REGDB_E_CLASSNOTREG;
2334 if (SUCCEEDED(hres))
2336 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2337 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2338 RegCloseKey(hkey);
2341 /* return if we got a class, otherwise fall through to one of the
2342 * other types */
2343 if (SUCCEEDED(hres))
2345 if (release_apt) apartment_release(apt);
2346 return hres;
2350 /* Next try in-process handler */
2351 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2353 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2354 HKEY hkey;
2356 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2357 if (FAILED(hres))
2359 if (hres == REGDB_E_CLASSNOTREG)
2360 ERR("class %s not registered\n", debugstr_guid(rclsid));
2361 else if (hres == REGDB_E_KEYMISSING)
2363 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2364 hres = REGDB_E_CLASSNOTREG;
2368 if (SUCCEEDED(hres))
2370 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2371 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2372 RegCloseKey(hkey);
2375 /* return if we got a class, otherwise fall through to one of the
2376 * other types */
2377 if (SUCCEEDED(hres))
2379 if (release_apt) apartment_release(apt);
2380 return hres;
2383 if (release_apt) apartment_release(apt);
2385 /* Next try out of process */
2386 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2388 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2389 if (SUCCEEDED(hres))
2390 return hres;
2393 /* Finally try remote: this requires networked DCOM (a lot of work) */
2394 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2396 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2397 hres = E_NOINTERFACE;
2400 if (FAILED(hres))
2401 ERR("no class object %s could be created for context 0x%x\n",
2402 debugstr_guid(rclsid), dwClsContext);
2403 return hres;
2406 /***********************************************************************
2407 * CoResumeClassObjects (OLE32.@)
2409 * Resumes all class objects registered with REGCLS_SUSPENDED.
2411 * RETURNS
2412 * Success: S_OK.
2413 * Failure: HRESULT code.
2415 HRESULT WINAPI CoResumeClassObjects(void)
2417 FIXME("stub\n");
2418 return S_OK;
2421 /***********************************************************************
2422 * CoCreateInstance [OLE32.@]
2424 * Creates an instance of the specified class.
2426 * PARAMS
2427 * rclsid [I] Class ID to create an instance of.
2428 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2429 * dwClsContext [I] Flags to restrict the location of the created instance.
2430 * iid [I] The ID of the interface of the instance to return.
2431 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2433 * RETURNS
2434 * Success: S_OK
2435 * Failure: HRESULT code.
2437 * NOTES
2438 * The dwClsContext parameter can be one or more of the following:
2439 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2440 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2441 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2442 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2444 * Aggregation is the concept of deferring the IUnknown of an object to another
2445 * object. This allows a separate object to behave as though it was part of
2446 * the object and to allow this the pUnkOuter parameter can be set. Note that
2447 * not all objects support having an outer of unknown.
2449 * SEE ALSO
2450 * CoGetClassObject()
2452 HRESULT WINAPI CoCreateInstance(
2453 REFCLSID rclsid,
2454 LPUNKNOWN pUnkOuter,
2455 DWORD dwClsContext,
2456 REFIID iid,
2457 LPVOID *ppv)
2459 HRESULT hres;
2460 LPCLASSFACTORY lpclf = 0;
2461 APARTMENT *apt;
2463 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2464 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2467 * Sanity check
2469 if (ppv==0)
2470 return E_POINTER;
2473 * Initialize the "out" parameter
2475 *ppv = 0;
2477 if (!(apt = COM_CurrentApt()))
2479 if (!(apt = apartment_find_multi_threaded()))
2481 ERR("apartment not initialised\n");
2482 return CO_E_NOTINITIALIZED;
2484 apartment_release(apt);
2488 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2489 * Rather than create a class factory, we can just check for it here
2491 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2492 if (StdGlobalInterfaceTableInstance == NULL)
2493 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2494 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2495 if (hres) return hres;
2497 TRACE("Retrieved GIT (%p)\n", *ppv);
2498 return S_OK;
2502 * Get a class factory to construct the object we want.
2504 hres = CoGetClassObject(rclsid,
2505 dwClsContext,
2506 NULL,
2507 &IID_IClassFactory,
2508 (LPVOID)&lpclf);
2510 if (FAILED(hres))
2511 return hres;
2514 * Create the object and don't forget to release the factory
2516 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2517 IClassFactory_Release(lpclf);
2518 if(FAILED(hres))
2520 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2521 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2522 else
2523 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2526 return hres;
2529 /***********************************************************************
2530 * CoCreateInstanceEx [OLE32.@]
2532 HRESULT WINAPI CoCreateInstanceEx(
2533 REFCLSID rclsid,
2534 LPUNKNOWN pUnkOuter,
2535 DWORD dwClsContext,
2536 COSERVERINFO* pServerInfo,
2537 ULONG cmq,
2538 MULTI_QI* pResults)
2540 IUnknown* pUnk = NULL;
2541 HRESULT hr;
2542 ULONG index;
2543 ULONG successCount = 0;
2546 * Sanity check
2548 if ( (cmq==0) || (pResults==NULL))
2549 return E_INVALIDARG;
2551 if (pServerInfo!=NULL)
2552 FIXME("() non-NULL pServerInfo not supported!\n");
2555 * Initialize all the "out" parameters.
2557 for (index = 0; index < cmq; index++)
2559 pResults[index].pItf = NULL;
2560 pResults[index].hr = E_NOINTERFACE;
2564 * Get the object and get its IUnknown pointer.
2566 hr = CoCreateInstance(rclsid,
2567 pUnkOuter,
2568 dwClsContext,
2569 &IID_IUnknown,
2570 (VOID**)&pUnk);
2572 if (hr)
2573 return hr;
2576 * Then, query for all the interfaces requested.
2578 for (index = 0; index < cmq; index++)
2580 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2581 pResults[index].pIID,
2582 (VOID**)&(pResults[index].pItf));
2584 if (pResults[index].hr == S_OK)
2585 successCount++;
2589 * Release our temporary unknown pointer.
2591 IUnknown_Release(pUnk);
2593 if (successCount == 0)
2594 return E_NOINTERFACE;
2596 if (successCount!=cmq)
2597 return CO_S_NOTALLINTERFACES;
2599 return S_OK;
2602 /***********************************************************************
2603 * CoLoadLibrary (OLE32.@)
2605 * Loads a library.
2607 * PARAMS
2608 * lpszLibName [I] Path to library.
2609 * bAutoFree [I] Whether the library should automatically be freed.
2611 * RETURNS
2612 * Success: Handle to loaded library.
2613 * Failure: NULL.
2615 * SEE ALSO
2616 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2618 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2620 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2622 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2625 /***********************************************************************
2626 * CoFreeLibrary [OLE32.@]
2628 * Unloads a library from memory.
2630 * PARAMS
2631 * hLibrary [I] Handle to library to unload.
2633 * RETURNS
2634 * Nothing
2636 * SEE ALSO
2637 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2639 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2641 FreeLibrary(hLibrary);
2645 /***********************************************************************
2646 * CoFreeAllLibraries [OLE32.@]
2648 * Function for backwards compatibility only. Does nothing.
2650 * RETURNS
2651 * Nothing.
2653 * SEE ALSO
2654 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2656 void WINAPI CoFreeAllLibraries(void)
2658 /* NOP */
2661 /***********************************************************************
2662 * CoFreeUnusedLibrariesEx [OLE32.@]
2664 * Frees any previously unused libraries whose delay has expired and marks
2665 * currently unused libraries for unloading. Unused are identified as those that
2666 * return S_OK from their DllCanUnloadNow function.
2668 * PARAMS
2669 * dwUnloadDelay [I] Unload delay in milliseconds.
2670 * dwReserved [I] Reserved. Set to 0.
2672 * RETURNS
2673 * Nothing.
2675 * SEE ALSO
2676 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2678 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2680 struct apartment *apt = COM_CurrentApt();
2681 if (!apt)
2683 ERR("apartment not initialised\n");
2684 return;
2687 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2690 /***********************************************************************
2691 * CoFreeUnusedLibraries [OLE32.@]
2693 * Frees any unused libraries. Unused are identified as those that return
2694 * S_OK from their DllCanUnloadNow function.
2696 * RETURNS
2697 * Nothing.
2699 * SEE ALSO
2700 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2702 void WINAPI CoFreeUnusedLibraries(void)
2704 CoFreeUnusedLibrariesEx(INFINITE, 0);
2707 /***********************************************************************
2708 * CoFileTimeNow [OLE32.@]
2710 * Retrieves the current time in FILETIME format.
2712 * PARAMS
2713 * lpFileTime [O] The current time.
2715 * RETURNS
2716 * S_OK.
2718 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2720 GetSystemTimeAsFileTime( lpFileTime );
2721 return S_OK;
2724 /******************************************************************************
2725 * CoLockObjectExternal [OLE32.@]
2727 * Increments or decrements the external reference count of a stub object.
2729 * PARAMS
2730 * pUnk [I] Stub object.
2731 * fLock [I] If TRUE then increments the external ref-count,
2732 * otherwise decrements.
2733 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2734 * calling CoDisconnectObject.
2736 * RETURNS
2737 * Success: S_OK.
2738 * Failure: HRESULT code.
2740 * NOTES
2741 * If fLock is TRUE and an object is passed in that doesn't have a stub
2742 * manager then a new stub manager is created for the object.
2744 HRESULT WINAPI CoLockObjectExternal(
2745 LPUNKNOWN pUnk,
2746 BOOL fLock,
2747 BOOL fLastUnlockReleases)
2749 struct stub_manager *stubmgr;
2750 struct apartment *apt;
2752 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2753 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2755 apt = COM_CurrentApt();
2756 if (!apt) return CO_E_NOTINITIALIZED;
2758 stubmgr = get_stub_manager_from_object(apt, pUnk);
2760 if (stubmgr)
2762 if (fLock)
2763 stub_manager_ext_addref(stubmgr, 1, FALSE);
2764 else
2765 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2767 stub_manager_int_release(stubmgr);
2769 return S_OK;
2771 else if (fLock)
2773 stubmgr = new_stub_manager(apt, pUnk);
2775 if (stubmgr)
2777 stub_manager_ext_addref(stubmgr, 1, FALSE);
2778 stub_manager_int_release(stubmgr);
2781 return S_OK;
2783 else
2785 WARN("stub object not found %p\n", pUnk);
2786 /* Note: native is pretty broken here because it just silently
2787 * fails, without returning an appropriate error code, making apps
2788 * think that the object was disconnected, when it actually wasn't */
2789 return S_OK;
2793 /***********************************************************************
2794 * CoInitializeWOW (OLE32.@)
2796 * WOW equivalent of CoInitialize?
2798 * PARAMS
2799 * x [I] Unknown.
2800 * y [I] Unknown.
2802 * RETURNS
2803 * Unknown.
2805 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2807 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2808 return 0;
2811 /***********************************************************************
2812 * CoGetState [OLE32.@]
2814 * Retrieves the thread state object previously stored by CoSetState().
2816 * PARAMS
2817 * ppv [I] Address where pointer to object will be stored.
2819 * RETURNS
2820 * Success: S_OK.
2821 * Failure: E_OUTOFMEMORY.
2823 * NOTES
2824 * Crashes on all invalid ppv addresses, including NULL.
2825 * If the function returns a non-NULL object then the caller must release its
2826 * reference on the object when the object is no longer required.
2828 * SEE ALSO
2829 * CoSetState().
2831 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2833 struct oletls *info = COM_CurrentInfo();
2834 if (!info) return E_OUTOFMEMORY;
2836 *ppv = NULL;
2838 if (info->state)
2840 IUnknown_AddRef(info->state);
2841 *ppv = info->state;
2842 TRACE("apt->state=%p\n", info->state);
2845 return S_OK;
2848 /***********************************************************************
2849 * CoSetState [OLE32.@]
2851 * Sets the thread state object.
2853 * PARAMS
2854 * pv [I] Pointer to state object to be stored.
2856 * NOTES
2857 * The system keeps a reference on the object while the object stored.
2859 * RETURNS
2860 * Success: S_OK.
2861 * Failure: E_OUTOFMEMORY.
2863 HRESULT WINAPI CoSetState(IUnknown * pv)
2865 struct oletls *info = COM_CurrentInfo();
2866 if (!info) return E_OUTOFMEMORY;
2868 if (pv) IUnknown_AddRef(pv);
2870 if (info->state)
2872 TRACE("-- release %p now\n", info->state);
2873 IUnknown_Release(info->state);
2876 info->state = pv;
2878 return S_OK;
2882 /******************************************************************************
2883 * CoTreatAsClass [OLE32.@]
2885 * Sets the TreatAs value of a class.
2887 * PARAMS
2888 * clsidOld [I] Class to set TreatAs value on.
2889 * clsidNew [I] The class the clsidOld should be treated as.
2891 * RETURNS
2892 * Success: S_OK.
2893 * Failure: HRESULT code.
2895 * SEE ALSO
2896 * CoGetTreatAsClass
2898 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2900 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2901 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2902 HKEY hkey = NULL;
2903 WCHAR szClsidNew[CHARS_IN_GUID];
2904 HRESULT res = S_OK;
2905 WCHAR auto_treat_as[CHARS_IN_GUID];
2906 LONG auto_treat_as_size = sizeof(auto_treat_as);
2907 CLSID id;
2909 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2910 if (FAILED(res))
2911 goto done;
2912 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2914 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2915 CLSIDFromString(auto_treat_as, &id) == S_OK)
2917 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2919 res = REGDB_E_WRITEREGDB;
2920 goto done;
2923 else
2925 RegDeleteKeyW(hkey, wszTreatAs);
2926 goto done;
2929 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2930 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2932 res = REGDB_E_WRITEREGDB;
2933 goto done;
2936 done:
2937 if (hkey) RegCloseKey(hkey);
2938 return res;
2941 /******************************************************************************
2942 * CoGetTreatAsClass [OLE32.@]
2944 * Gets the TreatAs value of a class.
2946 * PARAMS
2947 * clsidOld [I] Class to get the TreatAs value of.
2948 * clsidNew [I] The class the clsidOld should be treated as.
2950 * RETURNS
2951 * Success: S_OK.
2952 * Failure: HRESULT code.
2954 * SEE ALSO
2955 * CoSetTreatAsClass
2957 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2959 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2960 HKEY hkey = NULL;
2961 WCHAR szClsidNew[CHARS_IN_GUID];
2962 HRESULT res = S_OK;
2963 LONG len = sizeof(szClsidNew);
2965 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2966 *clsidNew = *clsidOld; /* copy over old value */
2968 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2969 if (FAILED(res))
2971 res = S_FALSE;
2972 goto done;
2974 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2976 res = S_FALSE;
2977 goto done;
2979 res = CLSIDFromString(szClsidNew,clsidNew);
2980 if (FAILED(res))
2981 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2982 done:
2983 if (hkey) RegCloseKey(hkey);
2984 return res;
2987 /******************************************************************************
2988 * CoGetCurrentProcess [OLE32.@]
2990 * Gets the current process ID.
2992 * RETURNS
2993 * The current process ID.
2995 * NOTES
2996 * Is DWORD really the correct return type for this function?
2998 DWORD WINAPI CoGetCurrentProcess(void)
3000 return GetCurrentProcessId();
3003 /******************************************************************************
3004 * CoRegisterMessageFilter [OLE32.@]
3006 * Registers a message filter.
3008 * PARAMS
3009 * lpMessageFilter [I] Pointer to interface.
3010 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3012 * RETURNS
3013 * Success: S_OK.
3014 * Failure: HRESULT code.
3016 * NOTES
3017 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3018 * lpMessageFilter removes the message filter.
3020 * If lplpMessageFilter is not NULL the previous message filter will be
3021 * returned in the memory pointer to this parameter and the caller is
3022 * responsible for releasing the object.
3024 * The current thread be in an apartment otherwise the function will crash.
3026 HRESULT WINAPI CoRegisterMessageFilter(
3027 LPMESSAGEFILTER lpMessageFilter,
3028 LPMESSAGEFILTER *lplpMessageFilter)
3030 struct apartment *apt;
3031 IMessageFilter *lpOldMessageFilter;
3033 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3035 apt = COM_CurrentApt();
3037 /* can't set a message filter in a multi-threaded apartment */
3038 if (!apt || apt->multi_threaded)
3040 WARN("can't set message filter in MTA or uninitialized apt\n");
3041 return CO_E_NOT_SUPPORTED;
3044 if (lpMessageFilter)
3045 IMessageFilter_AddRef(lpMessageFilter);
3047 EnterCriticalSection(&apt->cs);
3049 lpOldMessageFilter = apt->filter;
3050 apt->filter = lpMessageFilter;
3052 LeaveCriticalSection(&apt->cs);
3054 if (lplpMessageFilter)
3055 *lplpMessageFilter = lpOldMessageFilter;
3056 else if (lpOldMessageFilter)
3057 IMessageFilter_Release(lpOldMessageFilter);
3059 return S_OK;
3062 /***********************************************************************
3063 * CoIsOle1Class [OLE32.@]
3065 * Determines whether the specified class an OLE v1 class.
3067 * PARAMS
3068 * clsid [I] Class to test.
3070 * RETURNS
3071 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3073 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3075 FIXME("%s\n", debugstr_guid(clsid));
3076 return FALSE;
3079 /***********************************************************************
3080 * IsEqualGUID [OLE32.@]
3082 * Compares two Unique Identifiers.
3084 * PARAMS
3085 * rguid1 [I] The first GUID to compare.
3086 * rguid2 [I] The other GUID to compare.
3088 * RETURNS
3089 * TRUE if equal
3091 #undef IsEqualGUID
3092 BOOL WINAPI IsEqualGUID(
3093 REFGUID rguid1,
3094 REFGUID rguid2)
3096 return !memcmp(rguid1,rguid2,sizeof(GUID));
3099 /***********************************************************************
3100 * CoInitializeSecurity [OLE32.@]
3102 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3103 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3104 void* pReserved1, DWORD dwAuthnLevel,
3105 DWORD dwImpLevel, void* pReserved2,
3106 DWORD dwCapabilities, void* pReserved3)
3108 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3109 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3110 dwCapabilities, pReserved3);
3111 return S_OK;
3114 /***********************************************************************
3115 * CoSuspendClassObjects [OLE32.@]
3117 * Suspends all registered class objects to prevent further requests coming in
3118 * for those objects.
3120 * RETURNS
3121 * Success: S_OK.
3122 * Failure: HRESULT code.
3124 HRESULT WINAPI CoSuspendClassObjects(void)
3126 FIXME("\n");
3127 return S_OK;
3130 /***********************************************************************
3131 * CoAddRefServerProcess [OLE32.@]
3133 * Helper function for incrementing the reference count of a local-server
3134 * process.
3136 * RETURNS
3137 * New reference count.
3139 * SEE ALSO
3140 * CoReleaseServerProcess().
3142 ULONG WINAPI CoAddRefServerProcess(void)
3144 ULONG refs;
3146 TRACE("\n");
3148 EnterCriticalSection(&csRegisteredClassList);
3149 refs = ++s_COMServerProcessReferences;
3150 LeaveCriticalSection(&csRegisteredClassList);
3152 TRACE("refs before: %d\n", refs - 1);
3154 return refs;
3157 /***********************************************************************
3158 * CoReleaseServerProcess [OLE32.@]
3160 * Helper function for decrementing the reference count of a local-server
3161 * process.
3163 * RETURNS
3164 * New reference count.
3166 * NOTES
3167 * When reference count reaches 0, this function suspends all registered
3168 * classes so no new connections are accepted.
3170 * SEE ALSO
3171 * CoAddRefServerProcess(), CoSuspendClassObjects().
3173 ULONG WINAPI CoReleaseServerProcess(void)
3175 ULONG refs;
3177 TRACE("\n");
3179 EnterCriticalSection(&csRegisteredClassList);
3181 refs = --s_COMServerProcessReferences;
3182 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3184 LeaveCriticalSection(&csRegisteredClassList);
3186 TRACE("refs after: %d\n", refs);
3188 return refs;
3191 /***********************************************************************
3192 * CoIsHandlerConnected [OLE32.@]
3194 * Determines whether a proxy is connected to a remote stub.
3196 * PARAMS
3197 * pUnk [I] Pointer to object that may or may not be connected.
3199 * RETURNS
3200 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3201 * FALSE otherwise.
3203 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3205 FIXME("%p\n", pUnk);
3207 return TRUE;
3210 /***********************************************************************
3211 * CoAllowSetForegroundWindow [OLE32.@]
3214 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3216 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3217 return S_OK;
3220 /***********************************************************************
3221 * CoQueryProxyBlanket [OLE32.@]
3223 * Retrieves the security settings being used by a proxy.
3225 * PARAMS
3226 * pProxy [I] Pointer to the proxy object.
3227 * pAuthnSvc [O] The type of authentication service.
3228 * pAuthzSvc [O] The type of authorization service.
3229 * ppServerPrincName [O] Optional. The server prinicple name.
3230 * pAuthnLevel [O] The authentication level.
3231 * pImpLevel [O] The impersonation level.
3232 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3233 * pCapabilities [O] Flags affecting the security behaviour.
3235 * RETURNS
3236 * Success: S_OK.
3237 * Failure: HRESULT code.
3239 * SEE ALSO
3240 * CoCopyProxy, CoSetProxyBlanket.
3242 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3243 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3244 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3246 IClientSecurity *pCliSec;
3247 HRESULT hr;
3249 TRACE("%p\n", pProxy);
3251 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3252 if (SUCCEEDED(hr))
3254 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3255 pAuthzSvc, ppServerPrincName,
3256 pAuthnLevel, pImpLevel, ppAuthInfo,
3257 pCapabilities);
3258 IClientSecurity_Release(pCliSec);
3261 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3262 return hr;
3265 /***********************************************************************
3266 * CoSetProxyBlanket [OLE32.@]
3268 * Sets the security settings for a proxy.
3270 * PARAMS
3271 * pProxy [I] Pointer to the proxy object.
3272 * AuthnSvc [I] The type of authentication service.
3273 * AuthzSvc [I] The type of authorization service.
3274 * pServerPrincName [I] The server prinicple name.
3275 * AuthnLevel [I] The authentication level.
3276 * ImpLevel [I] The impersonation level.
3277 * pAuthInfo [I] Information specific to the authorization/authentication service.
3278 * Capabilities [I] Flags affecting the security behaviour.
3280 * RETURNS
3281 * Success: S_OK.
3282 * Failure: HRESULT code.
3284 * SEE ALSO
3285 * CoQueryProxyBlanket, CoCopyProxy.
3287 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3288 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3289 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3291 IClientSecurity *pCliSec;
3292 HRESULT hr;
3294 TRACE("%p\n", pProxy);
3296 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3297 if (SUCCEEDED(hr))
3299 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3300 AuthzSvc, pServerPrincName,
3301 AuthnLevel, ImpLevel, pAuthInfo,
3302 Capabilities);
3303 IClientSecurity_Release(pCliSec);
3306 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3307 return hr;
3310 /***********************************************************************
3311 * CoCopyProxy [OLE32.@]
3313 * Copies a proxy.
3315 * PARAMS
3316 * pProxy [I] Pointer to the proxy object.
3317 * ppCopy [O] Copy of the proxy.
3319 * RETURNS
3320 * Success: S_OK.
3321 * Failure: HRESULT code.
3323 * SEE ALSO
3324 * CoQueryProxyBlanket, CoSetProxyBlanket.
3326 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3328 IClientSecurity *pCliSec;
3329 HRESULT hr;
3331 TRACE("%p\n", pProxy);
3333 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3334 if (SUCCEEDED(hr))
3336 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3337 IClientSecurity_Release(pCliSec);
3340 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3341 return hr;
3345 /***********************************************************************
3346 * CoGetCallContext [OLE32.@]
3348 * Gets the context of the currently executing server call in the current
3349 * thread.
3351 * PARAMS
3352 * riid [I] Context interface to return.
3353 * ppv [O] Pointer to memory that will receive the context on return.
3355 * RETURNS
3356 * Success: S_OK.
3357 * Failure: HRESULT code.
3359 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3361 struct oletls *info = COM_CurrentInfo();
3363 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3365 if (!info)
3366 return E_OUTOFMEMORY;
3368 if (!info->call_state)
3369 return RPC_E_CALL_COMPLETE;
3371 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3374 /***********************************************************************
3375 * CoSwitchCallContext [OLE32.@]
3377 * Switches the context of the currently executing server call in the current
3378 * thread.
3380 * PARAMS
3381 * pObject [I] Pointer to new context object
3382 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3384 * RETURNS
3385 * Success: S_OK.
3386 * Failure: HRESULT code.
3388 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3390 struct oletls *info = COM_CurrentInfo();
3392 TRACE("(%p, %p)\n", pObject, ppOldObject);
3394 if (!info)
3395 return E_OUTOFMEMORY;
3397 *ppOldObject = info->call_state;
3398 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3400 return S_OK;
3403 /***********************************************************************
3404 * CoQueryClientBlanket [OLE32.@]
3406 * Retrieves the authentication information about the client of the currently
3407 * executing server call in the current thread.
3409 * PARAMS
3410 * pAuthnSvc [O] Optional. The type of authentication service.
3411 * pAuthzSvc [O] Optional. The type of authorization service.
3412 * pServerPrincName [O] Optional. The server prinicple name.
3413 * pAuthnLevel [O] Optional. The authentication level.
3414 * pImpLevel [O] Optional. The impersonation level.
3415 * pPrivs [O] Optional. Information about the privileges of the client.
3416 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3418 * RETURNS
3419 * Success: S_OK.
3420 * Failure: HRESULT code.
3422 * SEE ALSO
3423 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3425 HRESULT WINAPI CoQueryClientBlanket(
3426 DWORD *pAuthnSvc,
3427 DWORD *pAuthzSvc,
3428 OLECHAR **pServerPrincName,
3429 DWORD *pAuthnLevel,
3430 DWORD *pImpLevel,
3431 RPC_AUTHZ_HANDLE *pPrivs,
3432 DWORD *pCapabilities)
3434 IServerSecurity *pSrvSec;
3435 HRESULT hr;
3437 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3438 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3439 pPrivs, pCapabilities);
3441 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3442 if (SUCCEEDED(hr))
3444 hr = IServerSecurity_QueryBlanket(
3445 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3446 pImpLevel, pPrivs, pCapabilities);
3447 IServerSecurity_Release(pSrvSec);
3450 return hr;
3453 /***********************************************************************
3454 * CoImpersonateClient [OLE32.@]
3456 * Impersonates the client of the currently executing server call in the
3457 * current thread.
3459 * PARAMS
3460 * None.
3462 * RETURNS
3463 * Success: S_OK.
3464 * Failure: HRESULT code.
3466 * NOTES
3467 * If this function fails then the current thread will not be impersonating
3468 * the client and all actions will take place on behalf of the server.
3469 * Therefore, it is important to check the return value from this function.
3471 * SEE ALSO
3472 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3474 HRESULT WINAPI CoImpersonateClient(void)
3476 IServerSecurity *pSrvSec;
3477 HRESULT hr;
3479 TRACE("\n");
3481 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3482 if (SUCCEEDED(hr))
3484 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3485 IServerSecurity_Release(pSrvSec);
3488 return hr;
3491 /***********************************************************************
3492 * CoRevertToSelf [OLE32.@]
3494 * Ends the impersonation of the client of the currently executing server
3495 * call in the current thread.
3497 * PARAMS
3498 * None.
3500 * RETURNS
3501 * Success: S_OK.
3502 * Failure: HRESULT code.
3504 * SEE ALSO
3505 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3507 HRESULT WINAPI CoRevertToSelf(void)
3509 IServerSecurity *pSrvSec;
3510 HRESULT hr;
3512 TRACE("\n");
3514 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3515 if (SUCCEEDED(hr))
3517 hr = IServerSecurity_RevertToSelf(pSrvSec);
3518 IServerSecurity_Release(pSrvSec);
3521 return hr;
3524 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3526 /* first try to retrieve messages for incoming COM calls to the apartment window */
3527 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3528 /* next retrieve other messages necessary for the app to remain responsive */
3529 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3530 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3533 /***********************************************************************
3534 * CoWaitForMultipleHandles [OLE32.@]
3536 * Waits for one or more handles to become signaled.
3538 * PARAMS
3539 * dwFlags [I] Flags. See notes.
3540 * dwTimeout [I] Timeout in milliseconds.
3541 * cHandles [I] Number of handles pointed to by pHandles.
3542 * pHandles [I] Handles to wait for.
3543 * lpdwindex [O] Index of handle that was signaled.
3545 * RETURNS
3546 * Success: S_OK.
3547 * Failure: RPC_S_CALLPENDING on timeout.
3549 * NOTES
3551 * The dwFlags parameter can be zero or more of the following:
3552 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3553 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3555 * SEE ALSO
3556 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3558 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3559 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3561 HRESULT hr = S_OK;
3562 DWORD start_time = GetTickCount();
3563 APARTMENT *apt = COM_CurrentApt();
3564 BOOL message_loop = apt && !apt->multi_threaded;
3566 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3567 pHandles, lpdwindex);
3569 while (TRUE)
3571 DWORD now = GetTickCount();
3572 DWORD res;
3574 if (now - start_time > dwTimeout)
3576 hr = RPC_S_CALLPENDING;
3577 break;
3580 if (message_loop)
3582 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3583 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3585 TRACE("waiting for rpc completion or window message\n");
3587 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3588 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3589 QS_ALLINPUT, wait_flags);
3591 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3593 MSG msg;
3595 /* call message filter */
3597 if (COM_CurrentApt()->filter)
3599 PENDINGTYPE pendingtype =
3600 COM_CurrentInfo()->pending_call_count_server ?
3601 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3602 DWORD be_handled = IMessageFilter_MessagePending(
3603 COM_CurrentApt()->filter, 0 /* FIXME */,
3604 now - start_time, pendingtype);
3605 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3606 switch (be_handled)
3608 case PENDINGMSG_CANCELCALL:
3609 WARN("call canceled\n");
3610 hr = RPC_E_CALL_CANCELED;
3611 break;
3612 case PENDINGMSG_WAITNOPROCESS:
3613 case PENDINGMSG_WAITDEFPROCESS:
3614 default:
3615 /* FIXME: MSDN is very vague about the difference
3616 * between WAITNOPROCESS and WAITDEFPROCESS - there
3617 * appears to be none, so it is possibly a left-over
3618 * from the 16-bit world. */
3619 break;
3623 /* note: using "if" here instead of "while" might seem less
3624 * efficient, but only if we are optimising for quick delivery
3625 * of pending messages, rather than quick completion of the
3626 * COM call */
3627 if (COM_PeekMessage(apt, &msg))
3629 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3630 TranslateMessage(&msg);
3631 DispatchMessageW(&msg);
3632 if (msg.message == WM_QUIT)
3634 TRACE("resending WM_QUIT to outer message loop\n");
3635 PostQuitMessage(msg.wParam);
3636 /* no longer need to process messages */
3637 message_loop = FALSE;
3640 continue;
3643 else
3645 TRACE("waiting for rpc completion\n");
3647 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3648 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3649 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3650 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3653 if (res < WAIT_OBJECT_0 + cHandles)
3655 /* handle signaled, store index */
3656 *lpdwindex = (res - WAIT_OBJECT_0);
3657 break;
3659 else if (res == WAIT_TIMEOUT)
3661 hr = RPC_S_CALLPENDING;
3662 break;
3664 else
3666 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3667 hr = E_UNEXPECTED;
3668 break;
3671 TRACE("-- 0x%08x\n", hr);
3672 return hr;
3676 /***********************************************************************
3677 * CoGetObject [OLE32.@]
3679 * Gets the object named by converting the name to a moniker and binding to it.
3681 * PARAMS
3682 * pszName [I] String representing the object.
3683 * pBindOptions [I] Parameters affecting the binding to the named object.
3684 * riid [I] Interface to bind to on the objecct.
3685 * ppv [O] On output, the interface riid of the object represented
3686 * by pszName.
3688 * RETURNS
3689 * Success: S_OK.
3690 * Failure: HRESULT code.
3692 * SEE ALSO
3693 * MkParseDisplayName.
3695 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3696 REFIID riid, void **ppv)
3698 IBindCtx *pbc;
3699 HRESULT hr;
3701 *ppv = NULL;
3703 hr = CreateBindCtx(0, &pbc);
3704 if (SUCCEEDED(hr))
3706 if (pBindOptions)
3707 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3709 if (SUCCEEDED(hr))
3711 ULONG chEaten;
3712 IMoniker *pmk;
3714 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3715 if (SUCCEEDED(hr))
3717 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3718 IMoniker_Release(pmk);
3722 IBindCtx_Release(pbc);
3724 return hr;
3727 /***********************************************************************
3728 * CoRegisterChannelHook [OLE32.@]
3730 * Registers a process-wide hook that is called during ORPC calls.
3732 * PARAMS
3733 * guidExtension [I] GUID of the channel hook to register.
3734 * pChannelHook [I] Channel hook object to register.
3736 * RETURNS
3737 * Success: S_OK.
3738 * Failure: HRESULT code.
3740 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3742 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3744 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3747 typedef struct Context
3749 const IComThreadingInfoVtbl *lpVtbl;
3750 const IContextCallbackVtbl *lpCallbackVtbl;
3751 LONG refs;
3752 APTTYPE apttype;
3753 } Context;
3755 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3757 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpVtbl));
3760 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3762 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl));
3765 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3767 *ppv = NULL;
3769 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3770 IsEqualIID(riid, &IID_IUnknown))
3772 *ppv = &iface->lpVtbl;
3773 } else if (IsEqualIID(riid, &IID_IContextCallback))
3775 *ppv = &iface->lpCallbackVtbl;
3778 if (*ppv)
3780 IUnknown_AddRef((IUnknown*)*ppv);
3781 return S_OK;
3784 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3785 return E_NOINTERFACE;
3788 static ULONG Context_AddRef(Context *This)
3790 return InterlockedIncrement(&This->refs);
3793 static ULONG Context_Release(Context *This)
3795 ULONG refs = InterlockedDecrement(&This->refs);
3796 if (!refs)
3797 HeapFree(GetProcessHeap(), 0, This);
3798 return refs;
3801 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3803 Context *This = impl_from_IComThreadingInfo(iface);
3804 return Context_QueryInterface(This, riid, ppv);
3807 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3809 Context *This = impl_from_IComThreadingInfo(iface);
3810 return Context_AddRef(This);
3813 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3815 Context *This = impl_from_IComThreadingInfo(iface);
3816 return Context_Release(This);
3819 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3821 Context *This = impl_from_IComThreadingInfo(iface);
3823 TRACE("(%p)\n", apttype);
3825 *apttype = This->apttype;
3826 return S_OK;
3829 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3831 Context *This = impl_from_IComThreadingInfo(iface);
3833 TRACE("(%p)\n", thdtype);
3835 switch (This->apttype)
3837 case APTTYPE_STA:
3838 case APTTYPE_MAINSTA:
3839 *thdtype = THDTYPE_PROCESSMESSAGES;
3840 break;
3841 default:
3842 *thdtype = THDTYPE_BLOCKMESSAGES;
3843 break;
3845 return S_OK;
3848 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3850 FIXME("(%p): stub\n", logical_thread_id);
3851 return E_NOTIMPL;
3854 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3856 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3857 return E_NOTIMPL;
3860 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3862 Context_CTI_QueryInterface,
3863 Context_CTI_AddRef,
3864 Context_CTI_Release,
3865 Context_CTI_GetCurrentApartmentType,
3866 Context_CTI_GetCurrentThreadType,
3867 Context_CTI_GetCurrentLogicalThreadId,
3868 Context_CTI_SetCurrentLogicalThreadId
3871 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
3873 Context *This = impl_from_IContextCallback(iface);
3874 return Context_QueryInterface(This, riid, ppv);
3877 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
3879 Context *This = impl_from_IContextCallback(iface);
3880 return Context_AddRef(This);
3883 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
3885 Context *This = impl_from_IContextCallback(iface);
3886 return Context_Release(This);
3889 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
3890 ComCallData *param, REFIID riid, int method, IUnknown *punk)
3892 Context *This = impl_from_IContextCallback(iface);
3894 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
3895 return E_NOTIMPL;
3898 static const IContextCallbackVtbl Context_Callback_Vtbl =
3900 Context_CC_QueryInterface,
3901 Context_CC_AddRef,
3902 Context_CC_Release,
3903 Context_CC_ContextCallback
3907 /***********************************************************************
3908 * CoGetObjectContext [OLE32.@]
3910 * Retrieves an object associated with the current context (i.e. apartment).
3912 * PARAMS
3913 * riid [I] ID of the interface of the object to retrieve.
3914 * ppv [O] Address where object will be stored on return.
3916 * RETURNS
3917 * Success: S_OK.
3918 * Failure: HRESULT code.
3920 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
3922 APARTMENT *apt = COM_CurrentApt();
3923 Context *context;
3924 HRESULT hr;
3926 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3928 *ppv = NULL;
3929 if (!apt)
3931 ERR("apartment not initialised\n");
3932 return CO_E_NOTINITIALIZED;
3935 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
3936 if (!context)
3937 return E_OUTOFMEMORY;
3939 context->lpVtbl = &Context_Threading_Vtbl;
3940 context->lpCallbackVtbl = &Context_Callback_Vtbl;
3941 context->refs = 1;
3942 if (apt->multi_threaded)
3943 context->apttype = APTTYPE_MTA;
3944 else if (apt->main)
3945 context->apttype = APTTYPE_MAINSTA;
3946 else
3947 context->apttype = APTTYPE_STA;
3949 hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
3950 IUnknown_Release((IUnknown *)&context->lpVtbl);
3952 return hr;
3956 /***********************************************************************
3957 * CoGetContextToken [OLE32.@]
3959 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
3961 struct oletls *info = COM_CurrentInfo();
3962 static int calls;
3963 if(!(calls++)) FIXME( "stub\n" );
3964 if (!info)
3965 return E_OUTOFMEMORY;
3966 if (token) *token = info->context_token;
3967 return E_NOTIMPL;
3971 /***********************************************************************
3972 * DllMain (OLE32.@)
3974 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3976 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3978 switch(fdwReason) {
3979 case DLL_PROCESS_ATTACH:
3980 hProxyDll = hinstDLL;
3981 COMPOBJ_InitProcess();
3982 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3983 break;
3985 case DLL_PROCESS_DETACH:
3986 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3987 OLEDD_UnInitialize();
3988 COMPOBJ_UninitProcess();
3989 RPC_UnregisterAllChannelHooks();
3990 COMPOBJ_DllList_Free();
3991 break;
3993 case DLL_THREAD_DETACH:
3994 COM_TlsDestroy();
3995 break;
3997 return TRUE;
4000 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */