push ca931951dc5f3f050707cce013d2412130f45f11
[wine/hacks.git] / dlls / ole32 / compobj.c
blob7403b95492746d61a26fa6eba2a69a561dc5e9da
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 #define USE_COM_CONTEXT_DEF
56 #include "objbase.h"
57 #include "ole2.h"
58 #include "ole2ver.h"
59 #include "ctxtcall.h"
60 #include "dde.h"
62 #include "compobj_private.h"
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
69 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
71 /****************************************************************************
72 * This section defines variables internal to the COM module.
75 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
76 DWORD dwClsContext, LPUNKNOWN* ppUnk);
77 static void COM_RevokeAllClasses(const struct apartment *apt);
78 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv);
80 static APARTMENT *MTA; /* protected by csApartment */
81 static APARTMENT *MainApartment; /* the first STA apartment */
82 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
84 static CRITICAL_SECTION csApartment;
85 static CRITICAL_SECTION_DEBUG critsect_debug =
87 0, 0, &csApartment,
88 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
89 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
91 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
93 struct registered_psclsid
95 struct list entry;
96 IID iid;
97 CLSID clsid;
101 * This lock count counts the number of times CoInitialize is called. It is
102 * decreased every time CoUninitialize is called. When it hits 0, the COM
103 * libraries are freed
105 static LONG s_COMLockCount = 0;
106 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
107 static LONG s_COMServerProcessReferences = 0;
110 * This linked list contains the list of registered class objects. These
111 * are mostly used to register the factories for out-of-proc servers of OLE
112 * objects.
114 * TODO: Make this data structure aware of inter-process communication. This
115 * means that parts of this will be exported to rpcss.
117 typedef struct tagRegisteredClass
119 struct list entry;
120 CLSID classIdentifier;
121 OXID apartment_id;
122 LPUNKNOWN classObject;
123 DWORD runContext;
124 DWORD connectFlags;
125 DWORD dwCookie;
126 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
127 void *RpcRegistration;
128 } RegisteredClass;
130 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
132 static CRITICAL_SECTION csRegisteredClassList;
133 static CRITICAL_SECTION_DEBUG class_cs_debug =
135 0, 0, &csRegisteredClassList,
136 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
137 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
139 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
141 /*****************************************************************************
142 * This section contains OpenDllList definitions
144 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
145 * other functions that do LoadLibrary _without_ giving back a HMODULE.
146 * Without this list these handles would never be freed.
148 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
149 * next unload-call but not before 600 sec.
152 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
153 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
155 typedef struct tagOpenDll
157 LONG refs;
158 LPWSTR library_name;
159 HANDLE library;
160 DllGetClassObjectFunc DllGetClassObject;
161 DllCanUnloadNowFunc DllCanUnloadNow;
162 struct list entry;
163 } OpenDll;
165 static struct list openDllList = LIST_INIT(openDllList);
167 static CRITICAL_SECTION csOpenDllList;
168 static CRITICAL_SECTION_DEBUG dll_cs_debug =
170 0, 0, &csOpenDllList,
171 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
172 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
174 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
176 struct apartment_loaded_dll
178 struct list entry;
179 OpenDll *dll;
180 DWORD unload_time;
181 BOOL multi_threaded;
184 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',' ',
185 '0','x','#','#','#','#','#','#','#','#',' ',0};
186 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
187 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
188 BOOL apartment_threaded,
189 REFCLSID rclsid, REFIID riid, void **ppv);
190 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
192 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
193 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
194 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
196 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
198 static void COMPOBJ_InitProcess( void )
200 WNDCLASSW wclass;
202 /* Dispatching to the correct thread in an apartment is done through
203 * window messages rather than RPC transports. When an interface is
204 * marshalled into another apartment in the same process, a window of the
205 * following class is created. The *caller* of CoMarshalInterface (i.e., the
206 * application) is responsible for pumping the message loop in that thread.
207 * The WM_USER messages which point to the RPCs are then dispatched to
208 * apartment_wndproc by the user's code from the apartment in which the
209 * interface was unmarshalled.
211 memset(&wclass, 0, sizeof(wclass));
212 wclass.lpfnWndProc = apartment_wndproc;
213 wclass.hInstance = hProxyDll;
214 wclass.lpszClassName = wszAptWinClass;
215 RegisterClassW(&wclass);
218 static void COMPOBJ_UninitProcess( void )
220 UnregisterClassW(wszAptWinClass, hProxyDll);
223 static void COM_TlsDestroy(void)
225 struct oletls *info = NtCurrentTeb()->ReservedForOle;
226 if (info)
228 if (info->apt) apartment_release(info->apt);
229 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
230 if (info->state) IUnknown_Release(info->state);
231 if (info->spy) IUnknown_Release(info->spy);
232 if (info->context_token) IObjContext_Release(info->context_token);
233 HeapFree(GetProcessHeap(), 0, info);
234 NtCurrentTeb()->ReservedForOle = NULL;
238 /******************************************************************************
239 * Manage apartments.
242 /* allocates memory and fills in the necessary fields for a new apartment
243 * object. must be called inside apartment cs */
244 static APARTMENT *apartment_construct(DWORD model)
246 APARTMENT *apt;
248 TRACE("creating new apartment, model=%d\n", model);
250 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
251 apt->tid = GetCurrentThreadId();
253 list_init(&apt->proxies);
254 list_init(&apt->stubmgrs);
255 list_init(&apt->psclsids);
256 list_init(&apt->loaded_dlls);
257 apt->ipidc = 0;
258 apt->refs = 1;
259 apt->remunk_exported = FALSE;
260 apt->oidc = 1;
261 InitializeCriticalSection(&apt->cs);
262 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
264 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
266 if (apt->multi_threaded)
268 /* FIXME: should be randomly generated by in an RPC call to rpcss */
269 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
271 else
273 /* FIXME: should be randomly generated by in an RPC call to rpcss */
274 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
277 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
279 list_add_head(&apts, &apt->entry);
281 return apt;
284 /* gets and existing apartment if one exists or otherwise creates an apartment
285 * structure which stores OLE apartment-local information and stores a pointer
286 * to it in the thread-local storage */
287 static APARTMENT *apartment_get_or_create(DWORD model)
289 APARTMENT *apt = COM_CurrentApt();
291 if (!apt)
293 if (model & COINIT_APARTMENTTHREADED)
295 EnterCriticalSection(&csApartment);
297 apt = apartment_construct(model);
298 if (!MainApartment)
300 MainApartment = apt;
301 apt->main = TRUE;
302 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
305 LeaveCriticalSection(&csApartment);
307 if (apt->main)
308 apartment_createwindowifneeded(apt);
310 else
312 EnterCriticalSection(&csApartment);
314 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
315 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
316 * in a process */
317 if (MTA)
319 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
320 apartment_addref(MTA);
322 else
323 MTA = apartment_construct(model);
325 apt = MTA;
327 LeaveCriticalSection(&csApartment);
329 COM_CurrentInfo()->apt = apt;
332 return apt;
335 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
337 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
340 DWORD apartment_addref(struct apartment *apt)
342 DWORD refs = InterlockedIncrement(&apt->refs);
343 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
344 return refs;
347 DWORD apartment_release(struct apartment *apt)
349 DWORD ret;
351 EnterCriticalSection(&csApartment);
353 ret = InterlockedDecrement(&apt->refs);
354 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
355 /* destruction stuff that needs to happen under csApartment CS */
356 if (ret == 0)
358 if (apt == MTA) MTA = NULL;
359 else if (apt == MainApartment) MainApartment = NULL;
360 list_remove(&apt->entry);
363 LeaveCriticalSection(&csApartment);
365 if (ret == 0)
367 struct list *cursor, *cursor2;
369 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
371 /* Release the references to the registered class objects */
372 COM_RevokeAllClasses(apt);
374 /* no locking is needed for this apartment, because no other thread
375 * can access it at this point */
377 apartment_disconnectproxies(apt);
379 if (apt->win) DestroyWindow(apt->win);
380 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
382 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
384 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
385 /* release the implicit reference given by the fact that the
386 * stub has external references (it must do since it is in the
387 * stub manager list in the apartment and all non-apartment users
388 * must have a ref on the apartment and so it cannot be destroyed).
390 stub_manager_int_release(stubmgr);
393 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
395 struct registered_psclsid *registered_psclsid =
396 LIST_ENTRY(cursor, struct registered_psclsid, entry);
398 list_remove(&registered_psclsid->entry);
399 HeapFree(GetProcessHeap(), 0, registered_psclsid);
402 /* if this assert fires, then another thread took a reference to a
403 * stub manager without taking a reference to the containing
404 * apartment, which it must do. */
405 assert(list_empty(&apt->stubmgrs));
407 if (apt->filter) IUnknown_Release(apt->filter);
409 /* free as many unused libraries as possible... */
410 apartment_freeunusedlibraries(apt, 0);
412 /* ... and free the memory for the apartment loaded dll entry and
413 * release the dll list reference without freeing the library for the
414 * rest */
415 while ((cursor = list_head(&apt->loaded_dlls)))
417 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
418 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
419 list_remove(cursor);
420 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
423 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
424 DeleteCriticalSection(&apt->cs);
426 HeapFree(GetProcessHeap(), 0, apt);
429 return ret;
432 /* The given OXID must be local to this process:
434 * The ref parameter is here mostly to ensure people remember that
435 * they get one, you should normally take a ref for thread safety.
437 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
439 APARTMENT *result = NULL;
440 struct list *cursor;
442 EnterCriticalSection(&csApartment);
443 LIST_FOR_EACH( cursor, &apts )
445 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
446 if (apt->oxid == oxid)
448 result = apt;
449 if (ref) apartment_addref(result);
450 break;
453 LeaveCriticalSection(&csApartment);
455 return result;
458 /* gets the apartment which has a given creator thread ID. The caller must
459 * release the reference from the apartment as soon as the apartment pointer
460 * is no longer required. */
461 APARTMENT *apartment_findfromtid(DWORD tid)
463 APARTMENT *result = NULL;
464 struct list *cursor;
466 EnterCriticalSection(&csApartment);
467 LIST_FOR_EACH( cursor, &apts )
469 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
470 if (apt->tid == tid)
472 result = apt;
473 apartment_addref(result);
474 break;
477 LeaveCriticalSection(&csApartment);
479 return result;
482 /* gets the main apartment if it exists. The caller must
483 * release the reference from the apartment as soon as the apartment pointer
484 * is no longer required. */
485 static APARTMENT *apartment_findmain(void)
487 APARTMENT *result;
489 EnterCriticalSection(&csApartment);
491 result = MainApartment;
492 if (result) apartment_addref(result);
494 LeaveCriticalSection(&csApartment);
496 return result;
499 /* gets the multi-threaded apartment if it exists. The caller must
500 * release the reference from the apartment as soon as the apartment pointer
501 * is no longer required. */
502 static APARTMENT *apartment_find_multi_threaded(void)
504 APARTMENT *result = NULL;
505 struct list *cursor;
507 EnterCriticalSection(&csApartment);
509 LIST_FOR_EACH( cursor, &apts )
511 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
512 if (apt->multi_threaded)
514 result = apt;
515 apartment_addref(result);
516 break;
520 LeaveCriticalSection(&csApartment);
521 return result;
524 struct host_object_params
526 HKEY hkeydll;
527 CLSID clsid; /* clsid of object to marshal */
528 IID iid; /* interface to marshal */
529 HANDLE event; /* event signalling when ready for multi-threaded case */
530 HRESULT hr; /* result for multi-threaded case */
531 IStream *stream; /* stream that the object will be marshaled into */
532 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
535 static HRESULT apartment_hostobject(struct apartment *apt,
536 const struct host_object_params *params)
538 IUnknown *object;
539 HRESULT hr;
540 static const LARGE_INTEGER llZero;
541 WCHAR dllpath[MAX_PATH+1];
543 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
545 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
547 /* failure: CLSID is not found in registry */
548 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
549 return REGDB_E_CLASSNOTREG;
552 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
553 &params->clsid, &params->iid, (void **)&object);
554 if (FAILED(hr))
555 return hr;
557 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
558 if (FAILED(hr))
559 IUnknown_Release(object);
560 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
562 return hr;
565 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
567 switch (msg)
569 case DM_EXECUTERPC:
570 RPC_ExecuteCall((struct dispatch_params *)lParam);
571 return 0;
572 case DM_HOSTOBJECT:
573 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
574 default:
575 return DefWindowProcW(hWnd, msg, wParam, lParam);
579 struct host_thread_params
581 COINIT threading_model;
582 HANDLE ready_event;
583 HWND apartment_hwnd;
586 /* thread for hosting an object to allow an object to appear to be created in
587 * an apartment with an incompatible threading model */
588 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
590 struct host_thread_params *params = p;
591 MSG msg;
592 HRESULT hr;
593 struct apartment *apt;
595 TRACE("\n");
597 hr = CoInitializeEx(NULL, params->threading_model);
598 if (FAILED(hr)) return hr;
600 apt = COM_CurrentApt();
601 if (params->threading_model == COINIT_APARTMENTTHREADED)
603 apartment_createwindowifneeded(apt);
604 params->apartment_hwnd = apartment_getwindow(apt);
606 else
607 params->apartment_hwnd = NULL;
609 /* force the message queue to be created before signaling parent thread */
610 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
612 SetEvent(params->ready_event);
613 params = NULL; /* can't touch params after here as it may be invalid */
615 while (GetMessageW(&msg, NULL, 0, 0))
617 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
619 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
620 obj_params->hr = apartment_hostobject(apt, obj_params);
621 SetEvent(obj_params->event);
623 else
625 TranslateMessage(&msg);
626 DispatchMessageW(&msg);
630 TRACE("exiting\n");
632 CoUninitialize();
634 return S_OK;
637 /* finds or creates a host apartment, creates the object inside it and returns
638 * a proxy to it so that the object can be used in the apartment of the
639 * caller of this function */
640 static HRESULT apartment_hostobject_in_hostapt(
641 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
642 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
644 struct host_object_params params;
645 HWND apartment_hwnd = NULL;
646 DWORD apartment_tid = 0;
647 HRESULT hr;
649 if (!multi_threaded && main_apartment)
651 APARTMENT *host_apt = apartment_findmain();
652 if (host_apt)
654 apartment_hwnd = apartment_getwindow(host_apt);
655 apartment_release(host_apt);
659 if (!apartment_hwnd)
661 EnterCriticalSection(&apt->cs);
663 if (!apt->host_apt_tid)
665 struct host_thread_params thread_params;
666 HANDLE handles[2];
667 DWORD wait_value;
669 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
670 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
671 thread_params.apartment_hwnd = NULL;
672 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
673 if (!handles[1])
675 CloseHandle(handles[0]);
676 LeaveCriticalSection(&apt->cs);
677 return E_OUTOFMEMORY;
679 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
680 CloseHandle(handles[0]);
681 CloseHandle(handles[1]);
682 if (wait_value == WAIT_OBJECT_0)
683 apt->host_apt_hwnd = thread_params.apartment_hwnd;
684 else
686 LeaveCriticalSection(&apt->cs);
687 return E_OUTOFMEMORY;
691 if (multi_threaded || !main_apartment)
693 apartment_hwnd = apt->host_apt_hwnd;
694 apartment_tid = apt->host_apt_tid;
697 LeaveCriticalSection(&apt->cs);
700 /* another thread may have become the main apartment in the time it took
701 * us to create the thread for the host apartment */
702 if (!apartment_hwnd && !multi_threaded && main_apartment)
704 APARTMENT *host_apt = apartment_findmain();
705 if (host_apt)
707 apartment_hwnd = apartment_getwindow(host_apt);
708 apartment_release(host_apt);
712 params.hkeydll = hkeydll;
713 params.clsid = *rclsid;
714 params.iid = *riid;
715 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
716 if (FAILED(hr))
717 return hr;
718 params.apartment_threaded = !multi_threaded;
719 if (multi_threaded)
721 params.hr = S_OK;
722 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
723 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
724 hr = E_OUTOFMEMORY;
725 else
727 WaitForSingleObject(params.event, INFINITE);
728 hr = params.hr;
730 CloseHandle(params.event);
732 else
734 if (!apartment_hwnd)
736 ERR("host apartment didn't create window\n");
737 hr = E_OUTOFMEMORY;
739 else
740 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
742 if (SUCCEEDED(hr))
743 hr = CoUnmarshalInterface(params.stream, riid, ppv);
744 IStream_Release(params.stream);
745 return hr;
748 /* create a window for the apartment or return the current one if one has
749 * already been created */
750 HRESULT apartment_createwindowifneeded(struct apartment *apt)
752 if (apt->multi_threaded)
753 return S_OK;
755 if (!apt->win)
757 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
758 0, 0, 0, 0,
759 HWND_MESSAGE, 0, hProxyDll, NULL);
760 if (!hwnd)
762 ERR("CreateWindow failed with error %d\n", GetLastError());
763 return HRESULT_FROM_WIN32(GetLastError());
765 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
766 /* someone beat us to it */
767 DestroyWindow(hwnd);
770 return S_OK;
773 /* retrieves the window for the main- or apartment-threaded apartment */
774 HWND apartment_getwindow(const struct apartment *apt)
776 assert(!apt->multi_threaded);
777 return apt->win;
780 void apartment_joinmta(void)
782 apartment_addref(MTA);
783 COM_CurrentInfo()->apt = MTA;
786 /* gets the specified class object by loading the appropriate DLL, if
787 * necessary and calls the DllGetClassObject function for the DLL */
788 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
789 BOOL apartment_threaded,
790 REFCLSID rclsid, REFIID riid, void **ppv)
792 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
793 HRESULT hr = S_OK;
794 BOOL found = FALSE;
795 struct apartment_loaded_dll *apartment_loaded_dll;
797 if (!strcmpiW(dllpath, wszOle32))
799 /* we don't need to control the lifetime of this dll, so use the local
800 * implementation of DllGetClassObject directly */
801 TRACE("calling ole32!DllGetClassObject\n");
802 hr = DllGetClassObject(rclsid, riid, ppv);
804 if (hr != S_OK)
805 ERR("DllGetClassObject returned error 0x%08x\n", hr);
807 return hr;
810 EnterCriticalSection(&apt->cs);
812 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
813 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
815 TRACE("found %s already loaded\n", debugstr_w(dllpath));
816 found = TRUE;
817 break;
820 if (!found)
822 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
823 if (!apartment_loaded_dll)
824 hr = E_OUTOFMEMORY;
825 if (SUCCEEDED(hr))
827 apartment_loaded_dll->unload_time = 0;
828 apartment_loaded_dll->multi_threaded = FALSE;
829 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
830 if (FAILED(hr))
831 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
833 if (SUCCEEDED(hr))
835 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
836 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
840 LeaveCriticalSection(&apt->cs);
842 if (SUCCEEDED(hr))
844 /* one component being multi-threaded overrides any number of
845 * apartment-threaded components */
846 if (!apartment_threaded)
847 apartment_loaded_dll->multi_threaded = TRUE;
849 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
850 /* OK: get the ClassObject */
851 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
853 if (hr != S_OK)
854 ERR("DllGetClassObject returned error 0x%08x\n", hr);
857 return hr;
860 /* frees unused libraries loaded by apartment_getclassobject by calling the
861 * DLL's DllCanUnloadNow entry point */
862 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
864 struct apartment_loaded_dll *entry, *next;
865 EnterCriticalSection(&apt->cs);
866 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
868 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
870 DWORD real_delay = delay;
872 if (real_delay == INFINITE)
874 /* DLLs that return multi-threaded objects aren't unloaded
875 * straight away to cope for programs that have races between
876 * last object destruction and threads in the DLLs that haven't
877 * finished, despite DllCanUnloadNow returning S_OK */
878 if (entry->multi_threaded)
879 real_delay = 10 * 60 * 1000; /* 10 minutes */
880 else
881 real_delay = 0;
884 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
886 list_remove(&entry->entry);
887 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
888 HeapFree(GetProcessHeap(), 0, entry);
890 else
891 entry->unload_time = GetTickCount() + real_delay;
893 else if (entry->unload_time)
894 entry->unload_time = 0;
896 LeaveCriticalSection(&apt->cs);
899 /*****************************************************************************
900 * This section contains OpenDllList implementation
903 /* caller must ensure that library_name is not already in the open dll list */
904 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
906 OpenDll *entry;
907 int len;
908 HRESULT hr = S_OK;
909 HANDLE hLibrary;
910 DllCanUnloadNowFunc DllCanUnloadNow;
911 DllGetClassObjectFunc DllGetClassObject;
913 TRACE("\n");
915 *ret = COMPOBJ_DllList_Get(library_name);
916 if (*ret) return S_OK;
918 /* do this outside the csOpenDllList to avoid creating a lock dependency on
919 * the loader lock */
920 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
921 if (!hLibrary)
923 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
924 /* failure: DLL could not be loaded */
925 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
928 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
929 /* Note: failing to find DllCanUnloadNow is not a failure */
930 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
931 if (!DllGetClassObject)
933 /* failure: the dll did not export DllGetClassObject */
934 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
935 FreeLibrary(hLibrary);
936 return CO_E_DLLNOTFOUND;
939 EnterCriticalSection( &csOpenDllList );
941 *ret = COMPOBJ_DllList_Get(library_name);
942 if (*ret)
944 /* another caller to this function already added the dll while we
945 * weren't in the critical section */
946 FreeLibrary(hLibrary);
948 else
950 len = strlenW(library_name);
951 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
952 if (entry)
953 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
954 if (entry && entry->library_name)
956 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
957 entry->library = hLibrary;
958 entry->refs = 1;
959 entry->DllCanUnloadNow = DllCanUnloadNow;
960 entry->DllGetClassObject = DllGetClassObject;
961 list_add_tail(&openDllList, &entry->entry);
963 else
965 HeapFree(GetProcessHeap(), 0, entry);
966 hr = E_OUTOFMEMORY;
967 FreeLibrary(hLibrary);
969 *ret = entry;
972 LeaveCriticalSection( &csOpenDllList );
974 return hr;
977 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
979 OpenDll *ptr;
980 OpenDll *ret = NULL;
981 EnterCriticalSection(&csOpenDllList);
982 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
984 if (!strcmpiW(library_name, ptr->library_name) &&
985 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
987 ret = ptr;
988 break;
991 LeaveCriticalSection(&csOpenDllList);
992 return ret;
995 /* pass FALSE for free_entry to release a reference without destroying the
996 * entry if it reaches zero or TRUE otherwise */
997 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
999 if (!InterlockedDecrement(&entry->refs) && free_entry)
1001 EnterCriticalSection(&csOpenDllList);
1002 list_remove(&entry->entry);
1003 LeaveCriticalSection(&csOpenDllList);
1005 TRACE("freeing %p\n", entry->library);
1006 FreeLibrary(entry->library);
1008 HeapFree(GetProcessHeap(), 0, entry->library_name);
1009 HeapFree(GetProcessHeap(), 0, entry);
1013 /* frees memory associated with active dll list */
1014 static void COMPOBJ_DllList_Free(void)
1016 OpenDll *entry, *cursor2;
1017 EnterCriticalSection(&csOpenDllList);
1018 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
1020 list_remove(&entry->entry);
1022 HeapFree(GetProcessHeap(), 0, entry->library_name);
1023 HeapFree(GetProcessHeap(), 0, entry);
1025 LeaveCriticalSection(&csOpenDllList);
1028 /******************************************************************************
1029 * CoBuildVersion [OLE32.@]
1031 * Gets the build version of the DLL.
1033 * PARAMS
1035 * RETURNS
1036 * Current build version, hiword is majornumber, loword is minornumber
1038 DWORD WINAPI CoBuildVersion(void)
1040 TRACE("Returning version %d, build %d.\n", rmm, rup);
1041 return (rmm<<16)+rup;
1044 /******************************************************************************
1045 * CoRegisterInitializeSpy [OLE32.@]
1047 * Add a Spy that watches CoInitializeEx calls
1049 * PARAMS
1050 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1051 * cookie [II] cookie receiver
1053 * RETURNS
1054 * Success: S_OK if not already initialized, S_FALSE otherwise.
1055 * Failure: HRESULT code.
1057 * SEE ALSO
1058 * CoInitializeEx
1060 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1062 struct oletls *info = COM_CurrentInfo();
1063 HRESULT hr;
1065 TRACE("(%p, %p)\n", spy, cookie);
1067 if (!spy || !cookie || !info)
1069 if (!info)
1070 WARN("Could not allocate tls\n");
1071 return E_INVALIDARG;
1074 if (info->spy)
1076 FIXME("Already registered?\n");
1077 return E_UNEXPECTED;
1080 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1081 if (SUCCEEDED(hr))
1083 cookie->QuadPart = (DWORD_PTR)spy;
1084 return S_OK;
1086 return hr;
1089 /******************************************************************************
1090 * CoRevokeInitializeSpy [OLE32.@]
1092 * Remove a spy that previously watched CoInitializeEx calls
1094 * PARAMS
1095 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1097 * RETURNS
1098 * Success: S_OK if a spy is removed
1099 * Failure: E_INVALIDARG
1101 * SEE ALSO
1102 * CoInitializeEx
1104 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1106 struct oletls *info = COM_CurrentInfo();
1107 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1109 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1110 return E_INVALIDARG;
1112 IUnknown_Release(info->spy);
1113 info->spy = NULL;
1114 return S_OK;
1118 /******************************************************************************
1119 * CoInitialize [OLE32.@]
1121 * Initializes the COM libraries by calling CoInitializeEx with
1122 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1124 * PARAMS
1125 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1127 * RETURNS
1128 * Success: S_OK if not already initialized, S_FALSE otherwise.
1129 * Failure: HRESULT code.
1131 * SEE ALSO
1132 * CoInitializeEx
1134 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1137 * Just delegate to the newer method.
1139 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1142 /******************************************************************************
1143 * CoInitializeEx [OLE32.@]
1145 * Initializes the COM libraries.
1147 * PARAMS
1148 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1149 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1151 * RETURNS
1152 * S_OK if successful,
1153 * S_FALSE if this function was called already.
1154 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1155 * threading model.
1157 * NOTES
1159 * The behavior used to set the IMalloc used for memory management is
1160 * obsolete.
1161 * The dwCoInit parameter must specify one of the following apartment
1162 * threading models:
1163 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1164 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1165 * The parameter may also specify zero or more of the following flags:
1166 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1167 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1169 * SEE ALSO
1170 * CoUninitialize
1172 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1174 struct oletls *info = COM_CurrentInfo();
1175 HRESULT hr = S_OK;
1176 APARTMENT *apt;
1178 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1180 if (lpReserved!=NULL)
1182 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1186 * Check the lock count. If this is the first time going through the initialize
1187 * process, we have to initialize the libraries.
1189 * And crank-up that lock count.
1191 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1194 * Initialize the various COM libraries and data structures.
1196 TRACE("() - Initializing the COM libraries\n");
1198 /* we may need to defer this until after apartment initialisation */
1199 RunningObjectTableImpl_Initialize();
1202 if (info->spy)
1203 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1205 if (!(apt = info->apt))
1207 apt = apartment_get_or_create(dwCoInit);
1208 if (!apt) return E_OUTOFMEMORY;
1210 else if (!apartment_is_model(apt, dwCoInit))
1212 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1213 code then we are probably using the wrong threading model to implement that API. */
1214 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1215 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1216 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1217 return RPC_E_CHANGED_MODE;
1219 else
1220 hr = S_FALSE;
1222 info->inits++;
1224 if (info->spy)
1225 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1227 return hr;
1230 /***********************************************************************
1231 * CoUninitialize [OLE32.@]
1233 * This method will decrement the refcount on the current apartment, freeing
1234 * the resources associated with it if it is the last thread in the apartment.
1235 * If the last apartment is freed, the function will additionally release
1236 * any COM resources associated with the process.
1238 * PARAMS
1240 * RETURNS
1241 * Nothing.
1243 * SEE ALSO
1244 * CoInitializeEx
1246 void WINAPI CoUninitialize(void)
1248 struct oletls * info = COM_CurrentInfo();
1249 LONG lCOMRefCnt;
1251 TRACE("()\n");
1253 /* will only happen on OOM */
1254 if (!info) return;
1256 if (info->spy)
1257 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1259 /* sanity check */
1260 if (!info->inits)
1262 ERR("Mismatched CoUninitialize\n");
1264 if (info->spy)
1265 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1266 return;
1269 if (!--info->inits)
1271 apartment_release(info->apt);
1272 info->apt = NULL;
1276 * Decrease the reference count.
1277 * If we are back to 0 locks on the COM library, make sure we free
1278 * all the associated data structures.
1280 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1281 if (lCOMRefCnt==1)
1283 TRACE("() - Releasing the COM libraries\n");
1285 RunningObjectTableImpl_UnInitialize();
1287 else if (lCOMRefCnt<1) {
1288 ERR( "CoUninitialize() - not CoInitialized.\n" );
1289 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1291 if (info->spy)
1292 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1295 /******************************************************************************
1296 * CoDisconnectObject [OLE32.@]
1298 * Disconnects all connections to this object from remote processes. Dispatches
1299 * pending RPCs while blocking new RPCs from occurring, and then calls
1300 * IMarshal::DisconnectObject on the given object.
1302 * Typically called when the object server is forced to shut down, for instance by
1303 * the user.
1305 * PARAMS
1306 * lpUnk [I] The object whose stub should be disconnected.
1307 * reserved [I] Reserved. Should be set to 0.
1309 * RETURNS
1310 * Success: S_OK.
1311 * Failure: HRESULT code.
1313 * SEE ALSO
1314 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1316 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1318 HRESULT hr;
1319 IMarshal *marshal;
1320 APARTMENT *apt;
1322 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1324 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1325 if (hr == S_OK)
1327 hr = IMarshal_DisconnectObject(marshal, reserved);
1328 IMarshal_Release(marshal);
1329 return hr;
1332 apt = COM_CurrentApt();
1333 if (!apt)
1334 return CO_E_NOTINITIALIZED;
1336 apartment_disconnectobject(apt, lpUnk);
1338 /* Note: native is pretty broken here because it just silently
1339 * fails, without returning an appropriate error code if the object was
1340 * not found, making apps think that the object was disconnected, when
1341 * it actually wasn't */
1343 return S_OK;
1346 /******************************************************************************
1347 * CoCreateGuid [OLE32.@]
1349 * Simply forwards to UuidCreate in RPCRT4.
1351 * PARAMS
1352 * pguid [O] Points to the GUID to initialize.
1354 * RETURNS
1355 * Success: S_OK.
1356 * Failure: HRESULT code.
1358 * SEE ALSO
1359 * UuidCreate
1361 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1363 DWORD status = UuidCreate(pguid);
1364 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1365 return HRESULT_FROM_WIN32( status );
1368 /******************************************************************************
1369 * CLSIDFromString [OLE32.@]
1370 * IIDFromString [OLE32.@]
1372 * Converts a unique identifier from its string representation into
1373 * the GUID struct.
1375 * PARAMS
1376 * idstr [I] The string representation of the GUID.
1377 * id [O] GUID converted from the string.
1379 * RETURNS
1380 * S_OK on success
1381 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1383 * SEE ALSO
1384 * StringFromCLSID
1386 static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1388 int i;
1389 BYTE table[256];
1391 if (!s) {
1392 memset( id, 0, sizeof (CLSID) );
1393 return S_OK;
1396 /* validate the CLSID string */
1397 if (strlenW(s) != 38)
1398 return CO_E_CLASSSTRING;
1400 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1401 return CO_E_CLASSSTRING;
1403 for (i=1; i<37; i++) {
1404 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1405 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1406 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1407 ((s[i] >= 'A') && (s[i] <= 'F'))))
1408 return CO_E_CLASSSTRING;
1411 TRACE("%s -> %p\n", debugstr_w(s), id);
1413 /* quick lookup table */
1414 memset(table, 0, 256);
1416 for (i = 0; i < 10; i++) {
1417 table['0' + i] = i;
1419 for (i = 0; i < 6; i++) {
1420 table['A' + i] = i+10;
1421 table['a' + i] = i+10;
1424 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1426 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1427 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1428 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1429 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1431 /* these are just sequential bytes */
1432 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1433 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1434 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1435 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1436 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1437 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1438 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1439 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1441 return S_OK;
1444 /*****************************************************************************/
1446 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1448 HRESULT ret;
1450 if (!id)
1451 return E_INVALIDARG;
1453 ret = __CLSIDFromString(idstr, id);
1454 if(ret != S_OK) { /* It appears a ProgID is also valid */
1455 ret = CLSIDFromProgID(idstr, id);
1457 return ret;
1461 /******************************************************************************
1462 * StringFromCLSID [OLE32.@]
1463 * StringFromIID [OLE32.@]
1465 * Converts a GUID into the respective string representation.
1466 * The target string is allocated using the OLE IMalloc.
1468 * PARAMS
1469 * id [I] the GUID to be converted.
1470 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1472 * RETURNS
1473 * S_OK
1474 * E_FAIL
1476 * SEE ALSO
1477 * StringFromGUID2, CLSIDFromString
1479 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1481 HRESULT ret;
1482 LPMALLOC mllc;
1484 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1485 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1486 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1487 return S_OK;
1490 /******************************************************************************
1491 * StringFromGUID2 [OLE32.@]
1493 * Modified version of StringFromCLSID that allows you to specify max
1494 * buffer size.
1496 * PARAMS
1497 * id [I] GUID to convert to string.
1498 * str [O] Buffer where the result will be stored.
1499 * cmax [I] Size of the buffer in characters.
1501 * RETURNS
1502 * Success: The length of the resulting string in characters.
1503 * Failure: 0.
1505 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1507 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1508 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1509 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1510 '%','0','2','X','%','0','2','X','}',0 };
1511 if (cmax < CHARS_IN_GUID) return 0;
1512 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1513 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1514 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1515 return CHARS_IN_GUID;
1518 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1519 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1521 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1522 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1523 LONG res;
1524 HKEY key;
1526 strcpyW(path, wszCLSIDSlash);
1527 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1528 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1529 if (res == ERROR_FILE_NOT_FOUND)
1530 return REGDB_E_CLASSNOTREG;
1531 else if (res != ERROR_SUCCESS)
1532 return REGDB_E_READREGDB;
1534 if (!keyname)
1536 *subkey = key;
1537 return S_OK;
1540 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1541 RegCloseKey(key);
1542 if (res == ERROR_FILE_NOT_FOUND)
1543 return REGDB_E_KEYMISSING;
1544 else if (res != ERROR_SUCCESS)
1545 return REGDB_E_READREGDB;
1547 return S_OK;
1550 /* open HKCR\\AppId\\{string form of appid clsid} key */
1551 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1553 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1554 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1555 DWORD res;
1556 WCHAR buf[CHARS_IN_GUID];
1557 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1558 DWORD size;
1559 HKEY hkey;
1560 DWORD type;
1561 HRESULT hr;
1563 /* read the AppID value under the class's key */
1564 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1565 if (FAILED(hr))
1566 return hr;
1568 size = sizeof(buf);
1569 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1570 RegCloseKey(hkey);
1571 if (res == ERROR_FILE_NOT_FOUND)
1572 return REGDB_E_KEYMISSING;
1573 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1574 return REGDB_E_READREGDB;
1576 strcpyW(keyname, szAppIdKey);
1577 strcatW(keyname, buf);
1578 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1579 if (res == ERROR_FILE_NOT_FOUND)
1580 return REGDB_E_KEYMISSING;
1581 else if (res != ERROR_SUCCESS)
1582 return REGDB_E_READREGDB;
1584 return S_OK;
1587 /******************************************************************************
1588 * ProgIDFromCLSID [OLE32.@]
1590 * Converts a class id into the respective program ID.
1592 * PARAMS
1593 * clsid [I] Class ID, as found in registry.
1594 * ppszProgID [O] Associated ProgID.
1596 * RETURNS
1597 * S_OK
1598 * E_OUTOFMEMORY
1599 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1601 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1603 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1604 HKEY hkey;
1605 HRESULT ret;
1606 LONG progidlen = 0;
1608 if (!ppszProgID)
1610 ERR("ppszProgId isn't optional\n");
1611 return E_INVALIDARG;
1614 *ppszProgID = NULL;
1615 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1616 if (FAILED(ret))
1617 return ret;
1619 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1620 ret = REGDB_E_CLASSNOTREG;
1622 if (ret == S_OK)
1624 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1625 if (*ppszProgID)
1627 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1628 ret = REGDB_E_CLASSNOTREG;
1630 else
1631 ret = E_OUTOFMEMORY;
1634 RegCloseKey(hkey);
1635 return ret;
1638 /******************************************************************************
1639 * CLSIDFromProgID [OLE32.@]
1641 * Converts a program id into the respective GUID.
1643 * PARAMS
1644 * progid [I] Unicode program ID, as found in registry.
1645 * clsid [O] Associated CLSID.
1647 * RETURNS
1648 * Success: S_OK
1649 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1651 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1653 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1654 WCHAR buf2[CHARS_IN_GUID];
1655 LONG buf2len = sizeof(buf2);
1656 HKEY xhkey;
1657 WCHAR *buf;
1659 if (!progid || !clsid)
1661 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1662 return E_INVALIDARG;
1665 /* initialise clsid in case of failure */
1666 memset(clsid, 0, sizeof(*clsid));
1668 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1669 strcpyW( buf, progid );
1670 strcatW( buf, clsidW );
1671 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1673 HeapFree(GetProcessHeap(),0,buf);
1674 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1675 return CO_E_CLASSSTRING;
1677 HeapFree(GetProcessHeap(),0,buf);
1679 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1681 RegCloseKey(xhkey);
1682 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1683 return CO_E_CLASSSTRING;
1685 RegCloseKey(xhkey);
1686 return __CLSIDFromString(buf2,clsid);
1690 /*****************************************************************************
1691 * CoGetPSClsid [OLE32.@]
1693 * Retrieves the CLSID of the proxy/stub factory that implements
1694 * IPSFactoryBuffer for the specified interface.
1696 * PARAMS
1697 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1698 * pclsid [O] Where to store returned proxy/stub CLSID.
1700 * RETURNS
1701 * S_OK
1702 * E_OUTOFMEMORY
1703 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1705 * NOTES
1707 * The standard marshaller activates the object with the CLSID
1708 * returned and uses the CreateProxy and CreateStub methods on its
1709 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1710 * given object.
1712 * CoGetPSClsid determines this CLSID by searching the
1713 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1714 * in the registry and any interface id registered by
1715 * CoRegisterPSClsid within the current process.
1717 * BUGS
1719 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1720 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1721 * considered a bug in native unless an application depends on this (unlikely).
1723 * SEE ALSO
1724 * CoRegisterPSClsid.
1726 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1728 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1729 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1730 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1731 WCHAR value[CHARS_IN_GUID];
1732 LONG len;
1733 HKEY hkey;
1734 APARTMENT *apt = COM_CurrentApt();
1735 struct registered_psclsid *registered_psclsid;
1737 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1739 if (!apt)
1741 ERR("apartment not initialised\n");
1742 return CO_E_NOTINITIALIZED;
1745 if (!pclsid)
1747 ERR("pclsid isn't optional\n");
1748 return E_INVALIDARG;
1751 EnterCriticalSection(&apt->cs);
1753 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1754 if (IsEqualIID(&registered_psclsid->iid, riid))
1756 *pclsid = registered_psclsid->clsid;
1757 LeaveCriticalSection(&apt->cs);
1758 return S_OK;
1761 LeaveCriticalSection(&apt->cs);
1763 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1764 strcpyW(path, wszInterface);
1765 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1766 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1768 /* Open the key.. */
1769 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1771 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1772 return REGDB_E_IIDNOTREG;
1775 /* ... Once we have the key, query the registry to get the
1776 value of CLSID as a string, and convert it into a
1777 proper CLSID structure to be passed back to the app */
1778 len = sizeof(value);
1779 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1781 RegCloseKey(hkey);
1782 return REGDB_E_IIDNOTREG;
1784 RegCloseKey(hkey);
1786 /* We have the CLSID we want back from the registry as a string, so
1787 let's convert it into a CLSID structure */
1788 if (CLSIDFromString(value, pclsid) != NOERROR)
1789 return REGDB_E_IIDNOTREG;
1791 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1792 return S_OK;
1795 /*****************************************************************************
1796 * CoRegisterPSClsid [OLE32.@]
1798 * Register a proxy/stub CLSID for the given interface in the current process
1799 * only.
1801 * PARAMS
1802 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1803 * rclsid [I] CLSID of the proxy/stub.
1805 * RETURNS
1806 * Success: S_OK
1807 * Failure: E_OUTOFMEMORY
1809 * NOTES
1811 * This function does not add anything to the registry and the effects are
1812 * limited to the lifetime of the current process.
1814 * SEE ALSO
1815 * CoGetPSClsid.
1817 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1819 APARTMENT *apt = COM_CurrentApt();
1820 struct registered_psclsid *registered_psclsid;
1822 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1824 if (!apt)
1826 ERR("apartment not initialised\n");
1827 return CO_E_NOTINITIALIZED;
1830 EnterCriticalSection(&apt->cs);
1832 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1833 if (IsEqualIID(&registered_psclsid->iid, riid))
1835 registered_psclsid->clsid = *rclsid;
1836 LeaveCriticalSection(&apt->cs);
1837 return S_OK;
1840 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1841 if (!registered_psclsid)
1843 LeaveCriticalSection(&apt->cs);
1844 return E_OUTOFMEMORY;
1847 registered_psclsid->iid = *riid;
1848 registered_psclsid->clsid = *rclsid;
1849 list_add_head(&apt->psclsids, &registered_psclsid->entry);
1851 LeaveCriticalSection(&apt->cs);
1853 return S_OK;
1857 /***
1858 * COM_GetRegisteredClassObject
1860 * This internal method is used to scan the registered class list to
1861 * find a class object.
1863 * Params:
1864 * rclsid Class ID of the class to find.
1865 * dwClsContext Class context to match.
1866 * ppv [out] returns a pointer to the class object. Complying
1867 * to normal COM usage, this method will increase the
1868 * reference count on this object.
1870 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1871 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1873 HRESULT hr = S_FALSE;
1874 RegisteredClass *curClass;
1876 EnterCriticalSection( &csRegisteredClassList );
1878 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1881 * Check if we have a match on the class ID and context.
1883 if ((apt->oxid == curClass->apartment_id) &&
1884 (dwClsContext & curClass->runContext) &&
1885 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1888 * We have a match, return the pointer to the class object.
1890 *ppUnk = curClass->classObject;
1892 IUnknown_AddRef(curClass->classObject);
1894 hr = S_OK;
1895 break;
1899 LeaveCriticalSection( &csRegisteredClassList );
1901 return hr;
1904 /******************************************************************************
1905 * CoRegisterClassObject [OLE32.@]
1907 * Registers the class object for a given class ID. Servers housed in EXE
1908 * files use this method instead of exporting DllGetClassObject to allow
1909 * other code to connect to their objects.
1911 * PARAMS
1912 * rclsid [I] CLSID of the object to register.
1913 * pUnk [I] IUnknown of the object.
1914 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1915 * flags [I] REGCLS flags indicating how connections are made.
1916 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1918 * RETURNS
1919 * S_OK on success,
1920 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1921 * CO_E_OBJISREG if the object is already registered. We should not return this.
1923 * SEE ALSO
1924 * CoRevokeClassObject, CoGetClassObject
1926 * NOTES
1927 * In-process objects are only registered for the current apartment.
1928 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1929 * in other apartments.
1931 * BUGS
1932 * MSDN claims that multiple interface registrations are legal, but we
1933 * can't do that with our current implementation.
1935 HRESULT WINAPI CoRegisterClassObject(
1936 REFCLSID rclsid,
1937 LPUNKNOWN pUnk,
1938 DWORD dwClsContext,
1939 DWORD flags,
1940 LPDWORD lpdwRegister)
1942 RegisteredClass* newClass;
1943 LPUNKNOWN foundObject;
1944 HRESULT hr;
1945 APARTMENT *apt;
1947 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1948 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1950 if ( (lpdwRegister==0) || (pUnk==0) )
1951 return E_INVALIDARG;
1953 apt = COM_CurrentApt();
1954 if (!apt)
1956 ERR("COM was not initialized\n");
1957 return CO_E_NOTINITIALIZED;
1960 *lpdwRegister = 0;
1962 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1963 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1964 if (flags & REGCLS_MULTIPLEUSE)
1965 dwClsContext |= CLSCTX_INPROC_SERVER;
1968 * First, check if the class is already registered.
1969 * If it is, this should cause an error.
1971 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1972 if (hr == S_OK) {
1973 if (flags & REGCLS_MULTIPLEUSE) {
1974 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1975 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1976 IUnknown_Release(foundObject);
1977 return hr;
1979 IUnknown_Release(foundObject);
1980 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1981 return CO_E_OBJISREG;
1984 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1985 if ( newClass == NULL )
1986 return E_OUTOFMEMORY;
1988 newClass->classIdentifier = *rclsid;
1989 newClass->apartment_id = apt->oxid;
1990 newClass->runContext = dwClsContext;
1991 newClass->connectFlags = flags;
1992 newClass->pMarshaledData = NULL;
1993 newClass->RpcRegistration = NULL;
1996 * Use the address of the chain node as the cookie since we are sure it's
1997 * unique. FIXME: not on 64-bit platforms.
1999 newClass->dwCookie = (DWORD)newClass;
2002 * Since we're making a copy of the object pointer, we have to increase its
2003 * reference count.
2005 newClass->classObject = pUnk;
2006 IUnknown_AddRef(newClass->classObject);
2008 EnterCriticalSection( &csRegisteredClassList );
2009 list_add_tail(&RegisteredClassList, &newClass->entry);
2010 LeaveCriticalSection( &csRegisteredClassList );
2012 *lpdwRegister = newClass->dwCookie;
2014 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2015 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2016 if (hr) {
2017 FIXME("Failed to create stream on hglobal, %x\n", hr);
2018 return hr;
2020 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
2021 newClass->classObject, MSHCTX_LOCAL, NULL,
2022 MSHLFLAGS_TABLESTRONG);
2023 if (hr) {
2024 FIXME("CoMarshalInterface failed, %x!\n",hr);
2025 return hr;
2028 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2029 newClass->pMarshaledData,
2030 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2031 &newClass->RpcRegistration);
2033 return S_OK;
2036 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
2038 list_remove(&curClass->entry);
2040 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
2041 RPC_StopLocalServer(curClass->RpcRegistration);
2044 * Release the reference to the class object.
2046 IUnknown_Release(curClass->classObject);
2048 if (curClass->pMarshaledData)
2050 LARGE_INTEGER zero;
2051 memset(&zero, 0, sizeof(zero));
2052 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
2053 CoReleaseMarshalData(curClass->pMarshaledData);
2054 IStream_Release(curClass->pMarshaledData);
2057 HeapFree(GetProcessHeap(), 0, curClass);
2060 static void COM_RevokeAllClasses(const struct apartment *apt)
2062 RegisteredClass *curClass, *cursor;
2064 EnterCriticalSection( &csRegisteredClassList );
2066 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
2068 if (curClass->apartment_id == apt->oxid)
2069 COM_RevokeRegisteredClassObject(curClass);
2072 LeaveCriticalSection( &csRegisteredClassList );
2075 /***********************************************************************
2076 * CoRevokeClassObject [OLE32.@]
2078 * Removes a class object from the class registry.
2080 * PARAMS
2081 * dwRegister [I] Cookie returned from CoRegisterClassObject().
2083 * RETURNS
2084 * Success: S_OK.
2085 * Failure: HRESULT code.
2087 * NOTES
2088 * Must be called from the same apartment that called CoRegisterClassObject(),
2089 * otherwise it will fail with RPC_E_WRONG_THREAD.
2091 * SEE ALSO
2092 * CoRegisterClassObject
2094 HRESULT WINAPI CoRevokeClassObject(
2095 DWORD dwRegister)
2097 HRESULT hr = E_INVALIDARG;
2098 RegisteredClass *curClass;
2099 APARTMENT *apt;
2101 TRACE("(%08x)\n",dwRegister);
2103 apt = COM_CurrentApt();
2104 if (!apt)
2106 ERR("COM was not initialized\n");
2107 return CO_E_NOTINITIALIZED;
2110 EnterCriticalSection( &csRegisteredClassList );
2112 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2115 * Check if we have a match on the cookie.
2117 if (curClass->dwCookie == dwRegister)
2119 if (curClass->apartment_id == apt->oxid)
2121 COM_RevokeRegisteredClassObject(curClass);
2122 hr = S_OK;
2124 else
2126 ERR("called from wrong apartment, should be called from %s\n",
2127 wine_dbgstr_longlong(curClass->apartment_id));
2128 hr = RPC_E_WRONG_THREAD;
2130 break;
2134 LeaveCriticalSection( &csRegisteredClassList );
2136 return hr;
2139 /***********************************************************************
2140 * COM_RegReadPath [internal]
2142 * Reads a registry value and expands it when necessary
2144 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2146 DWORD ret;
2147 HKEY key;
2148 DWORD keytype;
2149 WCHAR src[MAX_PATH];
2150 DWORD dwLength = dstlen * sizeof(WCHAR);
2152 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
2153 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2154 if (keytype == REG_EXPAND_SZ) {
2155 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2156 } else {
2157 lstrcpynW(dst, src, dstlen);
2160 RegCloseKey (key);
2162 return ret;
2165 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2167 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2168 DWORD keytype;
2169 DWORD ret;
2170 DWORD dwLength = len * sizeof(WCHAR);
2172 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2173 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2174 value[0] = '\0';
2177 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2178 REFCLSID rclsid, REFIID riid,
2179 BOOL hostifnecessary, void **ppv)
2181 WCHAR dllpath[MAX_PATH+1];
2182 BOOL apartment_threaded;
2184 if (hostifnecessary)
2186 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2187 static const WCHAR wszFree[] = {'F','r','e','e',0};
2188 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2189 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2191 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2192 /* "Apartment" */
2193 if (!strcmpiW(threading_model, wszApartment))
2195 apartment_threaded = TRUE;
2196 if (apt->multi_threaded)
2197 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2199 /* "Free" */
2200 else if (!strcmpiW(threading_model, wszFree))
2202 apartment_threaded = FALSE;
2203 if (!apt->multi_threaded)
2204 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2206 /* everything except "Apartment", "Free" and "Both" */
2207 else if (strcmpiW(threading_model, wszBoth))
2209 apartment_threaded = TRUE;
2210 /* everything else is main-threaded */
2211 if (threading_model[0])
2212 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2213 debugstr_w(threading_model), debugstr_guid(rclsid));
2215 if (apt->multi_threaded || !apt->main)
2216 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2218 else
2219 apartment_threaded = FALSE;
2221 else
2222 apartment_threaded = !apt->multi_threaded;
2224 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2226 /* failure: CLSID is not found in registry */
2227 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2228 return REGDB_E_CLASSNOTREG;
2231 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2232 rclsid, riid, ppv);
2235 /***********************************************************************
2236 * CoGetClassObject [OLE32.@]
2238 * Creates an object of the specified class.
2240 * PARAMS
2241 * rclsid [I] Class ID to create an instance of.
2242 * dwClsContext [I] Flags to restrict the location of the created instance.
2243 * pServerInfo [I] Optional. Details for connecting to a remote server.
2244 * iid [I] The ID of the interface of the instance to return.
2245 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2247 * RETURNS
2248 * Success: S_OK
2249 * Failure: HRESULT code.
2251 * NOTES
2252 * The dwClsContext parameter can be one or more of the following:
2253 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2254 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2255 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2256 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2258 * SEE ALSO
2259 * CoCreateInstance()
2261 HRESULT WINAPI CoGetClassObject(
2262 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2263 REFIID iid, LPVOID *ppv)
2265 LPUNKNOWN regClassObject;
2266 HRESULT hres = E_UNEXPECTED;
2267 APARTMENT *apt;
2268 BOOL release_apt = FALSE;
2270 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2272 if (!ppv)
2273 return E_INVALIDARG;
2275 *ppv = NULL;
2277 if (!(apt = COM_CurrentApt()))
2279 if (!(apt = apartment_find_multi_threaded()))
2281 ERR("apartment not initialised\n");
2282 return CO_E_NOTINITIALIZED;
2284 release_apt = TRUE;
2287 if (pServerInfo) {
2288 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2289 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2293 * First, try and see if we can't match the class ID with one of the
2294 * registered classes.
2296 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2297 &regClassObject))
2299 /* Get the required interface from the retrieved pointer. */
2300 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2303 * Since QI got another reference on the pointer, we want to release the
2304 * one we already have. If QI was unsuccessful, this will release the object. This
2305 * is good since we are not returning it in the "out" parameter.
2307 IUnknown_Release(regClassObject);
2308 if (release_apt) apartment_release(apt);
2309 return hres;
2312 /* First try in-process server */
2313 if (CLSCTX_INPROC_SERVER & dwClsContext)
2315 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2316 HKEY hkey;
2318 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2320 if (release_apt) apartment_release(apt);
2321 return FTMarshalCF_Create(iid, ppv);
2324 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2325 if (FAILED(hres))
2327 if (hres == REGDB_E_CLASSNOTREG)
2328 ERR("class %s not registered\n", debugstr_guid(rclsid));
2329 else if (hres == REGDB_E_KEYMISSING)
2331 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2332 hres = REGDB_E_CLASSNOTREG;
2336 if (SUCCEEDED(hres))
2338 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2339 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2340 RegCloseKey(hkey);
2343 /* return if we got a class, otherwise fall through to one of the
2344 * other types */
2345 if (SUCCEEDED(hres))
2347 if (release_apt) apartment_release(apt);
2348 return hres;
2352 /* Next try in-process handler */
2353 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2355 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2356 HKEY hkey;
2358 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2359 if (FAILED(hres))
2361 if (hres == REGDB_E_CLASSNOTREG)
2362 ERR("class %s not registered\n", debugstr_guid(rclsid));
2363 else if (hres == REGDB_E_KEYMISSING)
2365 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2366 hres = REGDB_E_CLASSNOTREG;
2370 if (SUCCEEDED(hres))
2372 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2373 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2374 RegCloseKey(hkey);
2377 /* return if we got a class, otherwise fall through to one of the
2378 * other types */
2379 if (SUCCEEDED(hres))
2381 if (release_apt) apartment_release(apt);
2382 return hres;
2385 if (release_apt) apartment_release(apt);
2387 /* Next try out of process */
2388 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2390 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2391 if (SUCCEEDED(hres))
2392 return hres;
2395 /* Finally try remote: this requires networked DCOM (a lot of work) */
2396 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2398 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2399 hres = E_NOINTERFACE;
2402 if (FAILED(hres))
2403 ERR("no class object %s could be created for context 0x%x\n",
2404 debugstr_guid(rclsid), dwClsContext);
2405 return hres;
2408 /***********************************************************************
2409 * CoResumeClassObjects (OLE32.@)
2411 * Resumes all class objects registered with REGCLS_SUSPENDED.
2413 * RETURNS
2414 * Success: S_OK.
2415 * Failure: HRESULT code.
2417 HRESULT WINAPI CoResumeClassObjects(void)
2419 FIXME("stub\n");
2420 return S_OK;
2423 /***********************************************************************
2424 * CoCreateInstance [OLE32.@]
2426 * Creates an instance of the specified class.
2428 * PARAMS
2429 * rclsid [I] Class ID to create an instance of.
2430 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2431 * dwClsContext [I] Flags to restrict the location of the created instance.
2432 * iid [I] The ID of the interface of the instance to return.
2433 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2435 * RETURNS
2436 * Success: S_OK
2437 * Failure: HRESULT code.
2439 * NOTES
2440 * The dwClsContext parameter can be one or more of the following:
2441 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2442 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2443 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2444 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2446 * Aggregation is the concept of deferring the IUnknown of an object to another
2447 * object. This allows a separate object to behave as though it was part of
2448 * the object and to allow this the pUnkOuter parameter can be set. Note that
2449 * not all objects support having an outer of unknown.
2451 * SEE ALSO
2452 * CoGetClassObject()
2454 HRESULT WINAPI CoCreateInstance(
2455 REFCLSID rclsid,
2456 LPUNKNOWN pUnkOuter,
2457 DWORD dwClsContext,
2458 REFIID iid,
2459 LPVOID *ppv)
2461 HRESULT hres;
2462 LPCLASSFACTORY lpclf = 0;
2463 APARTMENT *apt;
2465 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2466 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2469 * Sanity check
2471 if (ppv==0)
2472 return E_POINTER;
2475 * Initialize the "out" parameter
2477 *ppv = 0;
2479 if (!(apt = COM_CurrentApt()))
2481 if (!(apt = apartment_find_multi_threaded()))
2483 ERR("apartment not initialised\n");
2484 return CO_E_NOTINITIALIZED;
2486 apartment_release(apt);
2490 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2491 * Rather than create a class factory, we can just check for it here
2493 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2494 if (StdGlobalInterfaceTableInstance == NULL)
2495 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2496 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2497 if (hres) return hres;
2499 TRACE("Retrieved GIT (%p)\n", *ppv);
2500 return S_OK;
2504 * Get a class factory to construct the object we want.
2506 hres = CoGetClassObject(rclsid,
2507 dwClsContext,
2508 NULL,
2509 &IID_IClassFactory,
2510 (LPVOID)&lpclf);
2512 if (FAILED(hres))
2513 return hres;
2516 * Create the object and don't forget to release the factory
2518 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2519 IClassFactory_Release(lpclf);
2520 if(FAILED(hres))
2522 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2523 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2524 else
2525 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2528 return hres;
2531 /***********************************************************************
2532 * CoCreateInstanceEx [OLE32.@]
2534 HRESULT WINAPI CoCreateInstanceEx(
2535 REFCLSID rclsid,
2536 LPUNKNOWN pUnkOuter,
2537 DWORD dwClsContext,
2538 COSERVERINFO* pServerInfo,
2539 ULONG cmq,
2540 MULTI_QI* pResults)
2542 IUnknown* pUnk = NULL;
2543 HRESULT hr;
2544 ULONG index;
2545 ULONG successCount = 0;
2548 * Sanity check
2550 if ( (cmq==0) || (pResults==NULL))
2551 return E_INVALIDARG;
2553 if (pServerInfo!=NULL)
2554 FIXME("() non-NULL pServerInfo not supported!\n");
2557 * Initialize all the "out" parameters.
2559 for (index = 0; index < cmq; index++)
2561 pResults[index].pItf = NULL;
2562 pResults[index].hr = E_NOINTERFACE;
2566 * Get the object and get its IUnknown pointer.
2568 hr = CoCreateInstance(rclsid,
2569 pUnkOuter,
2570 dwClsContext,
2571 &IID_IUnknown,
2572 (VOID**)&pUnk);
2574 if (hr)
2575 return hr;
2578 * Then, query for all the interfaces requested.
2580 for (index = 0; index < cmq; index++)
2582 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2583 pResults[index].pIID,
2584 (VOID**)&(pResults[index].pItf));
2586 if (pResults[index].hr == S_OK)
2587 successCount++;
2591 * Release our temporary unknown pointer.
2593 IUnknown_Release(pUnk);
2595 if (successCount == 0)
2596 return E_NOINTERFACE;
2598 if (successCount!=cmq)
2599 return CO_S_NOTALLINTERFACES;
2601 return S_OK;
2604 /***********************************************************************
2605 * CoLoadLibrary (OLE32.@)
2607 * Loads a library.
2609 * PARAMS
2610 * lpszLibName [I] Path to library.
2611 * bAutoFree [I] Whether the library should automatically be freed.
2613 * RETURNS
2614 * Success: Handle to loaded library.
2615 * Failure: NULL.
2617 * SEE ALSO
2618 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2620 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2622 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2624 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2627 /***********************************************************************
2628 * CoFreeLibrary [OLE32.@]
2630 * Unloads a library from memory.
2632 * PARAMS
2633 * hLibrary [I] Handle to library to unload.
2635 * RETURNS
2636 * Nothing
2638 * SEE ALSO
2639 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2641 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2643 FreeLibrary(hLibrary);
2647 /***********************************************************************
2648 * CoFreeAllLibraries [OLE32.@]
2650 * Function for backwards compatibility only. Does nothing.
2652 * RETURNS
2653 * Nothing.
2655 * SEE ALSO
2656 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2658 void WINAPI CoFreeAllLibraries(void)
2660 /* NOP */
2663 /***********************************************************************
2664 * CoFreeUnusedLibrariesEx [OLE32.@]
2666 * Frees any previously unused libraries whose delay has expired and marks
2667 * currently unused libraries for unloading. Unused are identified as those that
2668 * return S_OK from their DllCanUnloadNow function.
2670 * PARAMS
2671 * dwUnloadDelay [I] Unload delay in milliseconds.
2672 * dwReserved [I] Reserved. Set to 0.
2674 * RETURNS
2675 * Nothing.
2677 * SEE ALSO
2678 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2680 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2682 struct apartment *apt = COM_CurrentApt();
2683 if (!apt)
2685 ERR("apartment not initialised\n");
2686 return;
2689 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2692 /***********************************************************************
2693 * CoFreeUnusedLibraries [OLE32.@]
2695 * Frees any unused libraries. Unused are identified as those that return
2696 * S_OK from their DllCanUnloadNow function.
2698 * RETURNS
2699 * Nothing.
2701 * SEE ALSO
2702 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2704 void WINAPI CoFreeUnusedLibraries(void)
2706 CoFreeUnusedLibrariesEx(INFINITE, 0);
2709 /***********************************************************************
2710 * CoFileTimeNow [OLE32.@]
2712 * Retrieves the current time in FILETIME format.
2714 * PARAMS
2715 * lpFileTime [O] The current time.
2717 * RETURNS
2718 * S_OK.
2720 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2722 GetSystemTimeAsFileTime( lpFileTime );
2723 return S_OK;
2726 /******************************************************************************
2727 * CoLockObjectExternal [OLE32.@]
2729 * Increments or decrements the external reference count of a stub object.
2731 * PARAMS
2732 * pUnk [I] Stub object.
2733 * fLock [I] If TRUE then increments the external ref-count,
2734 * otherwise decrements.
2735 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2736 * calling CoDisconnectObject.
2738 * RETURNS
2739 * Success: S_OK.
2740 * Failure: HRESULT code.
2742 * NOTES
2743 * If fLock is TRUE and an object is passed in that doesn't have a stub
2744 * manager then a new stub manager is created for the object.
2746 HRESULT WINAPI CoLockObjectExternal(
2747 LPUNKNOWN pUnk,
2748 BOOL fLock,
2749 BOOL fLastUnlockReleases)
2751 struct stub_manager *stubmgr;
2752 struct apartment *apt;
2754 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2755 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2757 apt = COM_CurrentApt();
2758 if (!apt) return CO_E_NOTINITIALIZED;
2760 stubmgr = get_stub_manager_from_object(apt, pUnk);
2762 if (stubmgr)
2764 if (fLock)
2765 stub_manager_ext_addref(stubmgr, 1, FALSE);
2766 else
2767 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2769 stub_manager_int_release(stubmgr);
2771 return S_OK;
2773 else if (fLock)
2775 stubmgr = new_stub_manager(apt, pUnk);
2777 if (stubmgr)
2779 stub_manager_ext_addref(stubmgr, 1, FALSE);
2780 stub_manager_int_release(stubmgr);
2783 return S_OK;
2785 else
2787 WARN("stub object not found %p\n", pUnk);
2788 /* Note: native is pretty broken here because it just silently
2789 * fails, without returning an appropriate error code, making apps
2790 * think that the object was disconnected, when it actually wasn't */
2791 return S_OK;
2795 /***********************************************************************
2796 * CoInitializeWOW (OLE32.@)
2798 * WOW equivalent of CoInitialize?
2800 * PARAMS
2801 * x [I] Unknown.
2802 * y [I] Unknown.
2804 * RETURNS
2805 * Unknown.
2807 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2809 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2810 return 0;
2813 /***********************************************************************
2814 * CoGetState [OLE32.@]
2816 * Retrieves the thread state object previously stored by CoSetState().
2818 * PARAMS
2819 * ppv [I] Address where pointer to object will be stored.
2821 * RETURNS
2822 * Success: S_OK.
2823 * Failure: E_OUTOFMEMORY.
2825 * NOTES
2826 * Crashes on all invalid ppv addresses, including NULL.
2827 * If the function returns a non-NULL object then the caller must release its
2828 * reference on the object when the object is no longer required.
2830 * SEE ALSO
2831 * CoSetState().
2833 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2835 struct oletls *info = COM_CurrentInfo();
2836 if (!info) return E_OUTOFMEMORY;
2838 *ppv = NULL;
2840 if (info->state)
2842 IUnknown_AddRef(info->state);
2843 *ppv = info->state;
2844 TRACE("apt->state=%p\n", info->state);
2847 return S_OK;
2850 /***********************************************************************
2851 * CoSetState [OLE32.@]
2853 * Sets the thread state object.
2855 * PARAMS
2856 * pv [I] Pointer to state object to be stored.
2858 * NOTES
2859 * The system keeps a reference on the object while the object stored.
2861 * RETURNS
2862 * Success: S_OK.
2863 * Failure: E_OUTOFMEMORY.
2865 HRESULT WINAPI CoSetState(IUnknown * pv)
2867 struct oletls *info = COM_CurrentInfo();
2868 if (!info) return E_OUTOFMEMORY;
2870 if (pv) IUnknown_AddRef(pv);
2872 if (info->state)
2874 TRACE("-- release %p now\n", info->state);
2875 IUnknown_Release(info->state);
2878 info->state = pv;
2880 return S_OK;
2884 /******************************************************************************
2885 * CoTreatAsClass [OLE32.@]
2887 * Sets the TreatAs value of a class.
2889 * PARAMS
2890 * clsidOld [I] Class to set TreatAs value on.
2891 * clsidNew [I] The class the clsidOld should be treated as.
2893 * RETURNS
2894 * Success: S_OK.
2895 * Failure: HRESULT code.
2897 * SEE ALSO
2898 * CoGetTreatAsClass
2900 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2902 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2903 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2904 HKEY hkey = NULL;
2905 WCHAR szClsidNew[CHARS_IN_GUID];
2906 HRESULT res = S_OK;
2907 WCHAR auto_treat_as[CHARS_IN_GUID];
2908 LONG auto_treat_as_size = sizeof(auto_treat_as);
2909 CLSID id;
2911 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2912 if (FAILED(res))
2913 goto done;
2914 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2916 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2917 CLSIDFromString(auto_treat_as, &id) == S_OK)
2919 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2921 res = REGDB_E_WRITEREGDB;
2922 goto done;
2925 else
2927 RegDeleteKeyW(hkey, wszTreatAs);
2928 goto done;
2931 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2932 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2934 res = REGDB_E_WRITEREGDB;
2935 goto done;
2938 done:
2939 if (hkey) RegCloseKey(hkey);
2940 return res;
2943 /******************************************************************************
2944 * CoGetTreatAsClass [OLE32.@]
2946 * Gets the TreatAs value of a class.
2948 * PARAMS
2949 * clsidOld [I] Class to get the TreatAs value of.
2950 * clsidNew [I] The class the clsidOld should be treated as.
2952 * RETURNS
2953 * Success: S_OK.
2954 * Failure: HRESULT code.
2956 * SEE ALSO
2957 * CoSetTreatAsClass
2959 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2961 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2962 HKEY hkey = NULL;
2963 WCHAR szClsidNew[CHARS_IN_GUID];
2964 HRESULT res = S_OK;
2965 LONG len = sizeof(szClsidNew);
2967 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2968 *clsidNew = *clsidOld; /* copy over old value */
2970 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2971 if (FAILED(res))
2973 res = S_FALSE;
2974 goto done;
2976 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2978 res = S_FALSE;
2979 goto done;
2981 res = CLSIDFromString(szClsidNew,clsidNew);
2982 if (FAILED(res))
2983 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2984 done:
2985 if (hkey) RegCloseKey(hkey);
2986 return res;
2989 /******************************************************************************
2990 * CoGetCurrentProcess [OLE32.@]
2992 * Gets the current process ID.
2994 * RETURNS
2995 * The current process ID.
2997 * NOTES
2998 * Is DWORD really the correct return type for this function?
3000 DWORD WINAPI CoGetCurrentProcess(void)
3002 return GetCurrentProcessId();
3005 /******************************************************************************
3006 * CoRegisterMessageFilter [OLE32.@]
3008 * Registers a message filter.
3010 * PARAMS
3011 * lpMessageFilter [I] Pointer to interface.
3012 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3014 * RETURNS
3015 * Success: S_OK.
3016 * Failure: HRESULT code.
3018 * NOTES
3019 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3020 * lpMessageFilter removes the message filter.
3022 * If lplpMessageFilter is not NULL the previous message filter will be
3023 * returned in the memory pointer to this parameter and the caller is
3024 * responsible for releasing the object.
3026 * The current thread be in an apartment otherwise the function will crash.
3028 HRESULT WINAPI CoRegisterMessageFilter(
3029 LPMESSAGEFILTER lpMessageFilter,
3030 LPMESSAGEFILTER *lplpMessageFilter)
3032 struct apartment *apt;
3033 IMessageFilter *lpOldMessageFilter;
3035 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3037 apt = COM_CurrentApt();
3039 /* can't set a message filter in a multi-threaded apartment */
3040 if (!apt || apt->multi_threaded)
3042 WARN("can't set message filter in MTA or uninitialized apt\n");
3043 return CO_E_NOT_SUPPORTED;
3046 if (lpMessageFilter)
3047 IMessageFilter_AddRef(lpMessageFilter);
3049 EnterCriticalSection(&apt->cs);
3051 lpOldMessageFilter = apt->filter;
3052 apt->filter = lpMessageFilter;
3054 LeaveCriticalSection(&apt->cs);
3056 if (lplpMessageFilter)
3057 *lplpMessageFilter = lpOldMessageFilter;
3058 else if (lpOldMessageFilter)
3059 IMessageFilter_Release(lpOldMessageFilter);
3061 return S_OK;
3064 /***********************************************************************
3065 * CoIsOle1Class [OLE32.@]
3067 * Determines whether the specified class an OLE v1 class.
3069 * PARAMS
3070 * clsid [I] Class to test.
3072 * RETURNS
3073 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3075 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3077 FIXME("%s\n", debugstr_guid(clsid));
3078 return FALSE;
3081 /***********************************************************************
3082 * IsEqualGUID [OLE32.@]
3084 * Compares two Unique Identifiers.
3086 * PARAMS
3087 * rguid1 [I] The first GUID to compare.
3088 * rguid2 [I] The other GUID to compare.
3090 * RETURNS
3091 * TRUE if equal
3093 #undef IsEqualGUID
3094 BOOL WINAPI IsEqualGUID(
3095 REFGUID rguid1,
3096 REFGUID rguid2)
3098 return !memcmp(rguid1,rguid2,sizeof(GUID));
3101 /***********************************************************************
3102 * CoInitializeSecurity [OLE32.@]
3104 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3105 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3106 void* pReserved1, DWORD dwAuthnLevel,
3107 DWORD dwImpLevel, void* pReserved2,
3108 DWORD dwCapabilities, void* pReserved3)
3110 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3111 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3112 dwCapabilities, pReserved3);
3113 return S_OK;
3116 /***********************************************************************
3117 * CoSuspendClassObjects [OLE32.@]
3119 * Suspends all registered class objects to prevent further requests coming in
3120 * for those objects.
3122 * RETURNS
3123 * Success: S_OK.
3124 * Failure: HRESULT code.
3126 HRESULT WINAPI CoSuspendClassObjects(void)
3128 FIXME("\n");
3129 return S_OK;
3132 /***********************************************************************
3133 * CoAddRefServerProcess [OLE32.@]
3135 * Helper function for incrementing the reference count of a local-server
3136 * process.
3138 * RETURNS
3139 * New reference count.
3141 * SEE ALSO
3142 * CoReleaseServerProcess().
3144 ULONG WINAPI CoAddRefServerProcess(void)
3146 ULONG refs;
3148 TRACE("\n");
3150 EnterCriticalSection(&csRegisteredClassList);
3151 refs = ++s_COMServerProcessReferences;
3152 LeaveCriticalSection(&csRegisteredClassList);
3154 TRACE("refs before: %d\n", refs - 1);
3156 return refs;
3159 /***********************************************************************
3160 * CoReleaseServerProcess [OLE32.@]
3162 * Helper function for decrementing the reference count of a local-server
3163 * process.
3165 * RETURNS
3166 * New reference count.
3168 * NOTES
3169 * When reference count reaches 0, this function suspends all registered
3170 * classes so no new connections are accepted.
3172 * SEE ALSO
3173 * CoAddRefServerProcess(), CoSuspendClassObjects().
3175 ULONG WINAPI CoReleaseServerProcess(void)
3177 ULONG refs;
3179 TRACE("\n");
3181 EnterCriticalSection(&csRegisteredClassList);
3183 refs = --s_COMServerProcessReferences;
3184 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3186 LeaveCriticalSection(&csRegisteredClassList);
3188 TRACE("refs after: %d\n", refs);
3190 return refs;
3193 /***********************************************************************
3194 * CoIsHandlerConnected [OLE32.@]
3196 * Determines whether a proxy is connected to a remote stub.
3198 * PARAMS
3199 * pUnk [I] Pointer to object that may or may not be connected.
3201 * RETURNS
3202 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3203 * FALSE otherwise.
3205 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3207 FIXME("%p\n", pUnk);
3209 return TRUE;
3212 /***********************************************************************
3213 * CoAllowSetForegroundWindow [OLE32.@]
3216 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3218 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3219 return S_OK;
3222 /***********************************************************************
3223 * CoQueryProxyBlanket [OLE32.@]
3225 * Retrieves the security settings being used by a proxy.
3227 * PARAMS
3228 * pProxy [I] Pointer to the proxy object.
3229 * pAuthnSvc [O] The type of authentication service.
3230 * pAuthzSvc [O] The type of authorization service.
3231 * ppServerPrincName [O] Optional. The server prinicple name.
3232 * pAuthnLevel [O] The authentication level.
3233 * pImpLevel [O] The impersonation level.
3234 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3235 * pCapabilities [O] Flags affecting the security behaviour.
3237 * RETURNS
3238 * Success: S_OK.
3239 * Failure: HRESULT code.
3241 * SEE ALSO
3242 * CoCopyProxy, CoSetProxyBlanket.
3244 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3245 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3246 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3248 IClientSecurity *pCliSec;
3249 HRESULT hr;
3251 TRACE("%p\n", pProxy);
3253 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3254 if (SUCCEEDED(hr))
3256 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3257 pAuthzSvc, ppServerPrincName,
3258 pAuthnLevel, pImpLevel, ppAuthInfo,
3259 pCapabilities);
3260 IClientSecurity_Release(pCliSec);
3263 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3264 return hr;
3267 /***********************************************************************
3268 * CoSetProxyBlanket [OLE32.@]
3270 * Sets the security settings for a proxy.
3272 * PARAMS
3273 * pProxy [I] Pointer to the proxy object.
3274 * AuthnSvc [I] The type of authentication service.
3275 * AuthzSvc [I] The type of authorization service.
3276 * pServerPrincName [I] The server prinicple name.
3277 * AuthnLevel [I] The authentication level.
3278 * ImpLevel [I] The impersonation level.
3279 * pAuthInfo [I] Information specific to the authorization/authentication service.
3280 * Capabilities [I] Flags affecting the security behaviour.
3282 * RETURNS
3283 * Success: S_OK.
3284 * Failure: HRESULT code.
3286 * SEE ALSO
3287 * CoQueryProxyBlanket, CoCopyProxy.
3289 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3290 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3291 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3293 IClientSecurity *pCliSec;
3294 HRESULT hr;
3296 TRACE("%p\n", pProxy);
3298 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3299 if (SUCCEEDED(hr))
3301 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3302 AuthzSvc, pServerPrincName,
3303 AuthnLevel, ImpLevel, pAuthInfo,
3304 Capabilities);
3305 IClientSecurity_Release(pCliSec);
3308 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3309 return hr;
3312 /***********************************************************************
3313 * CoCopyProxy [OLE32.@]
3315 * Copies a proxy.
3317 * PARAMS
3318 * pProxy [I] Pointer to the proxy object.
3319 * ppCopy [O] Copy of the proxy.
3321 * RETURNS
3322 * Success: S_OK.
3323 * Failure: HRESULT code.
3325 * SEE ALSO
3326 * CoQueryProxyBlanket, CoSetProxyBlanket.
3328 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3330 IClientSecurity *pCliSec;
3331 HRESULT hr;
3333 TRACE("%p\n", pProxy);
3335 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3336 if (SUCCEEDED(hr))
3338 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3339 IClientSecurity_Release(pCliSec);
3342 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3343 return hr;
3347 /***********************************************************************
3348 * CoGetCallContext [OLE32.@]
3350 * Gets the context of the currently executing server call in the current
3351 * thread.
3353 * PARAMS
3354 * riid [I] Context interface to return.
3355 * ppv [O] Pointer to memory that will receive the context on return.
3357 * RETURNS
3358 * Success: S_OK.
3359 * Failure: HRESULT code.
3361 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3363 struct oletls *info = COM_CurrentInfo();
3365 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3367 if (!info)
3368 return E_OUTOFMEMORY;
3370 if (!info->call_state)
3371 return RPC_E_CALL_COMPLETE;
3373 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3376 /***********************************************************************
3377 * CoSwitchCallContext [OLE32.@]
3379 * Switches the context of the currently executing server call in the current
3380 * thread.
3382 * PARAMS
3383 * pObject [I] Pointer to new context object
3384 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3386 * RETURNS
3387 * Success: S_OK.
3388 * Failure: HRESULT code.
3390 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3392 struct oletls *info = COM_CurrentInfo();
3394 TRACE("(%p, %p)\n", pObject, ppOldObject);
3396 if (!info)
3397 return E_OUTOFMEMORY;
3399 *ppOldObject = info->call_state;
3400 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3402 return S_OK;
3405 /***********************************************************************
3406 * CoQueryClientBlanket [OLE32.@]
3408 * Retrieves the authentication information about the client of the currently
3409 * executing server call in the current thread.
3411 * PARAMS
3412 * pAuthnSvc [O] Optional. The type of authentication service.
3413 * pAuthzSvc [O] Optional. The type of authorization service.
3414 * pServerPrincName [O] Optional. The server prinicple name.
3415 * pAuthnLevel [O] Optional. The authentication level.
3416 * pImpLevel [O] Optional. The impersonation level.
3417 * pPrivs [O] Optional. Information about the privileges of the client.
3418 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3420 * RETURNS
3421 * Success: S_OK.
3422 * Failure: HRESULT code.
3424 * SEE ALSO
3425 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3427 HRESULT WINAPI CoQueryClientBlanket(
3428 DWORD *pAuthnSvc,
3429 DWORD *pAuthzSvc,
3430 OLECHAR **pServerPrincName,
3431 DWORD *pAuthnLevel,
3432 DWORD *pImpLevel,
3433 RPC_AUTHZ_HANDLE *pPrivs,
3434 DWORD *pCapabilities)
3436 IServerSecurity *pSrvSec;
3437 HRESULT hr;
3439 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3440 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3441 pPrivs, pCapabilities);
3443 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3444 if (SUCCEEDED(hr))
3446 hr = IServerSecurity_QueryBlanket(
3447 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3448 pImpLevel, pPrivs, pCapabilities);
3449 IServerSecurity_Release(pSrvSec);
3452 return hr;
3455 /***********************************************************************
3456 * CoImpersonateClient [OLE32.@]
3458 * Impersonates the client of the currently executing server call in the
3459 * current thread.
3461 * PARAMS
3462 * None.
3464 * RETURNS
3465 * Success: S_OK.
3466 * Failure: HRESULT code.
3468 * NOTES
3469 * If this function fails then the current thread will not be impersonating
3470 * the client and all actions will take place on behalf of the server.
3471 * Therefore, it is important to check the return value from this function.
3473 * SEE ALSO
3474 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3476 HRESULT WINAPI CoImpersonateClient(void)
3478 IServerSecurity *pSrvSec;
3479 HRESULT hr;
3481 TRACE("\n");
3483 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3484 if (SUCCEEDED(hr))
3486 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3487 IServerSecurity_Release(pSrvSec);
3490 return hr;
3493 /***********************************************************************
3494 * CoRevertToSelf [OLE32.@]
3496 * Ends the impersonation of the client of the currently executing server
3497 * call in the current thread.
3499 * PARAMS
3500 * None.
3502 * RETURNS
3503 * Success: S_OK.
3504 * Failure: HRESULT code.
3506 * SEE ALSO
3507 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3509 HRESULT WINAPI CoRevertToSelf(void)
3511 IServerSecurity *pSrvSec;
3512 HRESULT hr;
3514 TRACE("\n");
3516 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3517 if (SUCCEEDED(hr))
3519 hr = IServerSecurity_RevertToSelf(pSrvSec);
3520 IServerSecurity_Release(pSrvSec);
3523 return hr;
3526 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3528 /* first try to retrieve messages for incoming COM calls to the apartment window */
3529 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3530 /* next retrieve other messages necessary for the app to remain responsive */
3531 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3532 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3535 /***********************************************************************
3536 * CoWaitForMultipleHandles [OLE32.@]
3538 * Waits for one or more handles to become signaled.
3540 * PARAMS
3541 * dwFlags [I] Flags. See notes.
3542 * dwTimeout [I] Timeout in milliseconds.
3543 * cHandles [I] Number of handles pointed to by pHandles.
3544 * pHandles [I] Handles to wait for.
3545 * lpdwindex [O] Index of handle that was signaled.
3547 * RETURNS
3548 * Success: S_OK.
3549 * Failure: RPC_S_CALLPENDING on timeout.
3551 * NOTES
3553 * The dwFlags parameter can be zero or more of the following:
3554 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3555 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3557 * SEE ALSO
3558 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3560 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3561 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3563 HRESULT hr = S_OK;
3564 DWORD start_time = GetTickCount();
3565 APARTMENT *apt = COM_CurrentApt();
3566 BOOL message_loop = apt && !apt->multi_threaded;
3568 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3569 pHandles, lpdwindex);
3571 while (TRUE)
3573 DWORD now = GetTickCount();
3574 DWORD res;
3576 if (now - start_time > dwTimeout)
3578 hr = RPC_S_CALLPENDING;
3579 break;
3582 if (message_loop)
3584 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3585 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3587 TRACE("waiting for rpc completion or window message\n");
3589 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3590 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3591 QS_ALLINPUT, wait_flags);
3593 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3595 MSG msg;
3597 /* call message filter */
3599 if (COM_CurrentApt()->filter)
3601 PENDINGTYPE pendingtype =
3602 COM_CurrentInfo()->pending_call_count_server ?
3603 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3604 DWORD be_handled = IMessageFilter_MessagePending(
3605 COM_CurrentApt()->filter, 0 /* FIXME */,
3606 now - start_time, pendingtype);
3607 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3608 switch (be_handled)
3610 case PENDINGMSG_CANCELCALL:
3611 WARN("call canceled\n");
3612 hr = RPC_E_CALL_CANCELED;
3613 break;
3614 case PENDINGMSG_WAITNOPROCESS:
3615 case PENDINGMSG_WAITDEFPROCESS:
3616 default:
3617 /* FIXME: MSDN is very vague about the difference
3618 * between WAITNOPROCESS and WAITDEFPROCESS - there
3619 * appears to be none, so it is possibly a left-over
3620 * from the 16-bit world. */
3621 break;
3625 /* note: using "if" here instead of "while" might seem less
3626 * efficient, but only if we are optimising for quick delivery
3627 * of pending messages, rather than quick completion of the
3628 * COM call */
3629 if (COM_PeekMessage(apt, &msg))
3631 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3632 TranslateMessage(&msg);
3633 DispatchMessageW(&msg);
3634 if (msg.message == WM_QUIT)
3636 TRACE("resending WM_QUIT to outer message loop\n");
3637 PostQuitMessage(msg.wParam);
3638 /* no longer need to process messages */
3639 message_loop = FALSE;
3642 continue;
3645 else
3647 TRACE("waiting for rpc completion\n");
3649 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3650 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3651 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3652 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3655 if (res < WAIT_OBJECT_0 + cHandles)
3657 /* handle signaled, store index */
3658 *lpdwindex = (res - WAIT_OBJECT_0);
3659 break;
3661 else if (res == WAIT_TIMEOUT)
3663 hr = RPC_S_CALLPENDING;
3664 break;
3666 else
3668 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3669 hr = E_UNEXPECTED;
3670 break;
3673 TRACE("-- 0x%08x\n", hr);
3674 return hr;
3678 /***********************************************************************
3679 * CoGetObject [OLE32.@]
3681 * Gets the object named by converting the name to a moniker and binding to it.
3683 * PARAMS
3684 * pszName [I] String representing the object.
3685 * pBindOptions [I] Parameters affecting the binding to the named object.
3686 * riid [I] Interface to bind to on the objecct.
3687 * ppv [O] On output, the interface riid of the object represented
3688 * by pszName.
3690 * RETURNS
3691 * Success: S_OK.
3692 * Failure: HRESULT code.
3694 * SEE ALSO
3695 * MkParseDisplayName.
3697 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3698 REFIID riid, void **ppv)
3700 IBindCtx *pbc;
3701 HRESULT hr;
3703 *ppv = NULL;
3705 hr = CreateBindCtx(0, &pbc);
3706 if (SUCCEEDED(hr))
3708 if (pBindOptions)
3709 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3711 if (SUCCEEDED(hr))
3713 ULONG chEaten;
3714 IMoniker *pmk;
3716 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3717 if (SUCCEEDED(hr))
3719 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3720 IMoniker_Release(pmk);
3724 IBindCtx_Release(pbc);
3726 return hr;
3729 /***********************************************************************
3730 * CoRegisterChannelHook [OLE32.@]
3732 * Registers a process-wide hook that is called during ORPC calls.
3734 * PARAMS
3735 * guidExtension [I] GUID of the channel hook to register.
3736 * pChannelHook [I] Channel hook object to register.
3738 * RETURNS
3739 * Success: S_OK.
3740 * Failure: HRESULT code.
3742 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3744 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3746 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3749 typedef struct Context
3751 const IComThreadingInfoVtbl *lpVtbl;
3752 const IContextCallbackVtbl *lpCallbackVtbl;
3753 const IObjContextVtbl *lpContextVtbl;
3754 LONG refs;
3755 APTTYPE apttype;
3756 } Context;
3758 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3760 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpVtbl));
3763 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3765 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl));
3768 static inline Context *impl_from_IObjContext( IObjContext *iface )
3770 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpContextVtbl));
3773 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3775 *ppv = NULL;
3777 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3778 IsEqualIID(riid, &IID_IUnknown))
3780 *ppv = &iface->lpVtbl;
3782 else if (IsEqualIID(riid, &IID_IContextCallback))
3784 *ppv = &iface->lpCallbackVtbl;
3786 else if (IsEqualIID(riid, &IID_IObjContext))
3788 *ppv = &iface->lpContextVtbl;
3791 if (*ppv)
3793 IUnknown_AddRef((IUnknown*)*ppv);
3794 return S_OK;
3797 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3798 return E_NOINTERFACE;
3801 static ULONG Context_AddRef(Context *This)
3803 return InterlockedIncrement(&This->refs);
3806 static ULONG Context_Release(Context *This)
3808 ULONG refs = InterlockedDecrement(&This->refs);
3809 if (!refs)
3810 HeapFree(GetProcessHeap(), 0, This);
3811 return refs;
3814 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3816 Context *This = impl_from_IComThreadingInfo(iface);
3817 return Context_QueryInterface(This, riid, ppv);
3820 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3822 Context *This = impl_from_IComThreadingInfo(iface);
3823 return Context_AddRef(This);
3826 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3828 Context *This = impl_from_IComThreadingInfo(iface);
3829 return Context_Release(This);
3832 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3834 Context *This = impl_from_IComThreadingInfo(iface);
3836 TRACE("(%p)\n", apttype);
3838 *apttype = This->apttype;
3839 return S_OK;
3842 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3844 Context *This = impl_from_IComThreadingInfo(iface);
3846 TRACE("(%p)\n", thdtype);
3848 switch (This->apttype)
3850 case APTTYPE_STA:
3851 case APTTYPE_MAINSTA:
3852 *thdtype = THDTYPE_PROCESSMESSAGES;
3853 break;
3854 default:
3855 *thdtype = THDTYPE_BLOCKMESSAGES;
3856 break;
3858 return S_OK;
3861 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3863 FIXME("(%p): stub\n", logical_thread_id);
3864 return E_NOTIMPL;
3867 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3869 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3870 return E_NOTIMPL;
3873 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3875 Context_CTI_QueryInterface,
3876 Context_CTI_AddRef,
3877 Context_CTI_Release,
3878 Context_CTI_GetCurrentApartmentType,
3879 Context_CTI_GetCurrentThreadType,
3880 Context_CTI_GetCurrentLogicalThreadId,
3881 Context_CTI_SetCurrentLogicalThreadId
3884 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
3886 Context *This = impl_from_IContextCallback(iface);
3887 return Context_QueryInterface(This, riid, ppv);
3890 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
3892 Context *This = impl_from_IContextCallback(iface);
3893 return Context_AddRef(This);
3896 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
3898 Context *This = impl_from_IContextCallback(iface);
3899 return Context_Release(This);
3902 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
3903 ComCallData *param, REFIID riid, int method, IUnknown *punk)
3905 Context *This = impl_from_IContextCallback(iface);
3907 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
3908 return E_NOTIMPL;
3911 static const IContextCallbackVtbl Context_Callback_Vtbl =
3913 Context_CC_QueryInterface,
3914 Context_CC_AddRef,
3915 Context_CC_Release,
3916 Context_CC_ContextCallback
3919 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
3921 Context *This = impl_from_IObjContext(iface);
3922 return Context_QueryInterface(This, riid, ppv);
3925 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
3927 Context *This = impl_from_IObjContext(iface);
3928 return Context_AddRef(This);
3931 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
3933 Context *This = impl_from_IObjContext(iface);
3934 return Context_Release(This);
3937 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
3939 Context *This = impl_from_IObjContext(iface);
3941 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3942 return E_NOTIMPL;
3945 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
3947 Context *This = impl_from_IObjContext(iface);
3949 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
3950 return E_NOTIMPL;
3953 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
3955 Context *This = impl_from_IObjContext(iface);
3957 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3958 return E_NOTIMPL;
3961 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
3963 Context *This = impl_from_IObjContext(iface);
3965 FIXME("(%p/%p)->(%p)\n", This, iface, props);
3966 return E_NOTIMPL;
3969 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
3971 Context *This = impl_from_IObjContext(iface);
3972 FIXME("(%p/%p)\n", This, iface);
3975 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
3977 Context *This = impl_from_IObjContext(iface);
3978 FIXME("(%p/%p)\n", This, iface);
3981 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
3983 Context *This = impl_from_IObjContext(iface);
3984 FIXME("(%p/%p)\n", This, iface);
3987 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
3989 Context *This = impl_from_IObjContext(iface);
3990 FIXME("(%p/%p)\n", This, iface);
3993 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
3995 Context *This = impl_from_IObjContext(iface);
3996 FIXME("(%p/%p)\n", This, iface);
3999 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4001 Context *This = impl_from_IObjContext(iface);
4002 FIXME("(%p/%p)\n", This, iface);
4005 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4007 Context *This = impl_from_IObjContext(iface);
4008 FIXME("(%p/%p)\n", This, iface);
4011 static const IObjContextVtbl Context_Object_Vtbl =
4013 Context_OC_QueryInterface,
4014 Context_OC_AddRef,
4015 Context_OC_Release,
4016 Context_OC_SetProperty,
4017 Context_OC_RemoveProperty,
4018 Context_OC_GetProperty,
4019 Context_OC_EnumContextProps,
4020 Context_OC_Reserved1,
4021 Context_OC_Reserved2,
4022 Context_OC_Reserved3,
4023 Context_OC_Reserved4,
4024 Context_OC_Reserved5,
4025 Context_OC_Reserved6,
4026 Context_OC_Reserved7
4029 /***********************************************************************
4030 * CoGetObjectContext [OLE32.@]
4032 * Retrieves an object associated with the current context (i.e. apartment).
4034 * PARAMS
4035 * riid [I] ID of the interface of the object to retrieve.
4036 * ppv [O] Address where object will be stored on return.
4038 * RETURNS
4039 * Success: S_OK.
4040 * Failure: HRESULT code.
4042 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4044 APARTMENT *apt = COM_CurrentApt();
4045 Context *context;
4046 HRESULT hr;
4048 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4050 *ppv = NULL;
4051 if (!apt)
4053 if (!(apt = apartment_find_multi_threaded()))
4055 ERR("apartment not initialised\n");
4056 return CO_E_NOTINITIALIZED;
4058 apartment_release(apt);
4061 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4062 if (!context)
4063 return E_OUTOFMEMORY;
4065 context->lpVtbl = &Context_Threading_Vtbl;
4066 context->lpCallbackVtbl = &Context_Callback_Vtbl;
4067 context->lpContextVtbl = &Context_Object_Vtbl;
4068 context->refs = 1;
4069 if (apt->multi_threaded)
4070 context->apttype = APTTYPE_MTA;
4071 else if (apt->main)
4072 context->apttype = APTTYPE_MAINSTA;
4073 else
4074 context->apttype = APTTYPE_STA;
4076 hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
4077 IUnknown_Release((IUnknown *)&context->lpVtbl);
4079 return hr;
4083 /***********************************************************************
4084 * CoGetContextToken [OLE32.@]
4086 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4088 struct oletls *info = COM_CurrentInfo();
4090 TRACE("(%p)\n", token);
4092 if (!info)
4093 return E_OUTOFMEMORY;
4095 if (!info->apt)
4097 APARTMENT *apt;
4098 if (!(apt = apartment_find_multi_threaded()))
4100 ERR("apartment not initialised\n");
4101 return CO_E_NOTINITIALIZED;
4103 apartment_release(apt);
4106 if (!token)
4107 return E_POINTER;
4109 if (!info->context_token)
4111 HRESULT hr;
4112 IObjContext *ctx;
4114 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4115 if (FAILED(hr)) return hr;
4116 info->context_token = ctx;
4119 *token = (ULONG_PTR)info->context_token;
4120 TRACE("apt->context_token=%p\n", info->context_token);
4122 return S_OK;
4126 /***********************************************************************
4127 * DllMain (OLE32.@)
4129 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4131 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4133 switch(fdwReason) {
4134 case DLL_PROCESS_ATTACH:
4135 hProxyDll = hinstDLL;
4136 COMPOBJ_InitProcess();
4137 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
4138 break;
4140 case DLL_PROCESS_DETACH:
4141 if (TRACE_ON(ole)) CoRevokeMallocSpy();
4142 OLEDD_UnInitialize();
4143 COMPOBJ_UninitProcess();
4144 RPC_UnregisterAllChannelHooks();
4145 COMPOBJ_DllList_Free();
4146 break;
4148 case DLL_THREAD_DETACH:
4149 COM_TlsDestroy();
4150 break;
4152 return TRUE;
4155 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */