push 8079c4124d1355f652d7dbd6f1862eb95d83e2de
[wine/hacks.git] / dlls / ole32 / compobj.c
blob711f341e278d41d8a5c225ec1408ecb1a7bc4291
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #include "objbase.h"
56 #include "ole2.h"
57 #include "ole2ver.h"
58 #include "ctxtcall.h"
60 #include "compobj_private.h"
62 #include "wine/unicode.h"
63 #include "wine/debug.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(ole);
67 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
69 /****************************************************************************
70 * This section defines variables internal to the COM module.
73 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
74 DWORD dwClsContext, LPUNKNOWN* ppUnk);
75 static void COM_RevokeAllClasses(const struct apartment *apt);
76 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv);
78 static APARTMENT *MTA; /* protected by csApartment */
79 static APARTMENT *MainApartment; /* the first STA apartment */
80 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
82 static CRITICAL_SECTION csApartment;
83 static CRITICAL_SECTION_DEBUG critsect_debug =
85 0, 0, &csApartment,
86 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
87 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
89 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
91 struct registered_psclsid
93 struct list entry;
94 IID iid;
95 CLSID clsid;
99 * This lock count counts the number of times CoInitialize is called. It is
100 * decreased every time CoUninitialize is called. When it hits 0, the COM
101 * libraries are freed
103 static LONG s_COMLockCount = 0;
104 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
105 static LONG s_COMServerProcessReferences = 0;
108 * This linked list contains the list of registered class objects. These
109 * are mostly used to register the factories for out-of-proc servers of OLE
110 * objects.
112 * TODO: Make this data structure aware of inter-process communication. This
113 * means that parts of this will be exported to rpcss.
115 typedef struct tagRegisteredClass
117 struct list entry;
118 CLSID classIdentifier;
119 OXID apartment_id;
120 LPUNKNOWN classObject;
121 DWORD runContext;
122 DWORD connectFlags;
123 DWORD dwCookie;
124 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
125 void *RpcRegistration;
126 } RegisteredClass;
128 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
130 static CRITICAL_SECTION csRegisteredClassList;
131 static CRITICAL_SECTION_DEBUG class_cs_debug =
133 0, 0, &csRegisteredClassList,
134 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
135 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
137 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
139 /*****************************************************************************
140 * This section contains OpenDllList definitions
142 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
143 * other functions that do LoadLibrary _without_ giving back a HMODULE.
144 * Without this list these handles would never be freed.
146 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
147 * next unload-call but not before 600 sec.
150 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
151 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
153 typedef struct tagOpenDll
155 LONG refs;
156 LPWSTR library_name;
157 HANDLE library;
158 DllGetClassObjectFunc DllGetClassObject;
159 DllCanUnloadNowFunc DllCanUnloadNow;
160 struct list entry;
161 } OpenDll;
163 static struct list openDllList = LIST_INIT(openDllList);
165 static CRITICAL_SECTION csOpenDllList;
166 static CRITICAL_SECTION_DEBUG dll_cs_debug =
168 0, 0, &csOpenDllList,
169 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
170 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
172 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
174 struct apartment_loaded_dll
176 struct list entry;
177 OpenDll *dll;
178 DWORD unload_time;
179 BOOL multi_threaded;
182 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',' ',
183 '0','x','#','#','#','#','#','#','#','#',' ',0};
184 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
185 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
186 BOOL apartment_threaded,
187 REFCLSID rclsid, REFIID riid, void **ppv);
188 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
190 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
191 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
192 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
194 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
196 static void COMPOBJ_InitProcess( void )
198 WNDCLASSW wclass;
200 /* Dispatching to the correct thread in an apartment is done through
201 * window messages rather than RPC transports. When an interface is
202 * marshalled into another apartment in the same process, a window of the
203 * following class is created. The *caller* of CoMarshalInterface (i.e., the
204 * application) is responsible for pumping the message loop in that thread.
205 * The WM_USER messages which point to the RPCs are then dispatched to
206 * apartment_wndproc by the user's code from the apartment in which the
207 * interface was unmarshalled.
209 memset(&wclass, 0, sizeof(wclass));
210 wclass.lpfnWndProc = apartment_wndproc;
211 wclass.hInstance = hProxyDll;
212 wclass.lpszClassName = wszAptWinClass;
213 RegisterClassW(&wclass);
216 static void COMPOBJ_UninitProcess( void )
218 UnregisterClassW(wszAptWinClass, hProxyDll);
221 static void COM_TlsDestroy(void)
223 struct oletls *info = NtCurrentTeb()->ReservedForOle;
224 if (info)
226 if (info->apt) apartment_release(info->apt);
227 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
228 if (info->state) IUnknown_Release(info->state);
229 if (info->spy) IUnknown_Release(info->spy);
230 HeapFree(GetProcessHeap(), 0, info);
231 NtCurrentTeb()->ReservedForOle = NULL;
235 /******************************************************************************
236 * Manage apartments.
239 /* allocates memory and fills in the necessary fields for a new apartment
240 * object. must be called inside apartment cs */
241 static APARTMENT *apartment_construct(DWORD model)
243 APARTMENT *apt;
245 TRACE("creating new apartment, model=%d\n", model);
247 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
248 apt->tid = GetCurrentThreadId();
250 list_init(&apt->proxies);
251 list_init(&apt->stubmgrs);
252 list_init(&apt->psclsids);
253 list_init(&apt->loaded_dlls);
254 apt->ipidc = 0;
255 apt->refs = 1;
256 apt->remunk_exported = FALSE;
257 apt->oidc = 1;
258 InitializeCriticalSection(&apt->cs);
259 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
261 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
263 if (apt->multi_threaded)
265 /* FIXME: should be randomly generated by in an RPC call to rpcss */
266 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
268 else
270 /* FIXME: should be randomly generated by in an RPC call to rpcss */
271 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
274 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
276 list_add_head(&apts, &apt->entry);
278 return apt;
281 /* gets and existing apartment if one exists or otherwise creates an apartment
282 * structure which stores OLE apartment-local information and stores a pointer
283 * to it in the thread-local storage */
284 static APARTMENT *apartment_get_or_create(DWORD model)
286 APARTMENT *apt = COM_CurrentApt();
288 if (!apt)
290 if (model & COINIT_APARTMENTTHREADED)
292 EnterCriticalSection(&csApartment);
294 apt = apartment_construct(model);
295 if (!MainApartment)
297 MainApartment = apt;
298 apt->main = TRUE;
299 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
302 LeaveCriticalSection(&csApartment);
304 if (apt->main)
305 apartment_createwindowifneeded(apt);
307 else
309 EnterCriticalSection(&csApartment);
311 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
312 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
313 * in a process */
314 if (MTA)
316 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
317 apartment_addref(MTA);
319 else
320 MTA = apartment_construct(model);
322 apt = MTA;
324 LeaveCriticalSection(&csApartment);
326 COM_CurrentInfo()->apt = apt;
329 return apt;
332 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
334 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
337 DWORD apartment_addref(struct apartment *apt)
339 DWORD refs = InterlockedIncrement(&apt->refs);
340 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
341 return refs;
344 DWORD apartment_release(struct apartment *apt)
346 DWORD ret;
348 EnterCriticalSection(&csApartment);
350 ret = InterlockedDecrement(&apt->refs);
351 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
352 /* destruction stuff that needs to happen under csApartment CS */
353 if (ret == 0)
355 if (apt == MTA) MTA = NULL;
356 else if (apt == MainApartment) MainApartment = NULL;
357 list_remove(&apt->entry);
360 LeaveCriticalSection(&csApartment);
362 if (ret == 0)
364 struct list *cursor, *cursor2;
366 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
368 /* Release the references to the registered class objects */
369 COM_RevokeAllClasses(apt);
371 /* no locking is needed for this apartment, because no other thread
372 * can access it at this point */
374 apartment_disconnectproxies(apt);
376 if (apt->win) DestroyWindow(apt->win);
377 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
379 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
381 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
382 /* release the implicit reference given by the fact that the
383 * stub has external references (it must do since it is in the
384 * stub manager list in the apartment and all non-apartment users
385 * must have a ref on the apartment and so it cannot be destroyed).
387 stub_manager_int_release(stubmgr);
390 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
392 struct registered_psclsid *registered_psclsid =
393 LIST_ENTRY(cursor, struct registered_psclsid, entry);
395 list_remove(&registered_psclsid->entry);
396 HeapFree(GetProcessHeap(), 0, registered_psclsid);
399 /* if this assert fires, then another thread took a reference to a
400 * stub manager without taking a reference to the containing
401 * apartment, which it must do. */
402 assert(list_empty(&apt->stubmgrs));
404 if (apt->filter) IUnknown_Release(apt->filter);
406 /* free as many unused libraries as possible... */
407 apartment_freeunusedlibraries(apt, 0);
409 /* ... and free the memory for the apartment loaded dll entry and
410 * release the dll list reference without freeing the library for the
411 * rest */
412 while ((cursor = list_head(&apt->loaded_dlls)))
414 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
415 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
416 list_remove(cursor);
417 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
420 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
421 DeleteCriticalSection(&apt->cs);
423 HeapFree(GetProcessHeap(), 0, apt);
426 return ret;
429 /* The given OXID must be local to this process:
431 * The ref parameter is here mostly to ensure people remember that
432 * they get one, you should normally take a ref for thread safety.
434 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
436 APARTMENT *result = NULL;
437 struct list *cursor;
439 EnterCriticalSection(&csApartment);
440 LIST_FOR_EACH( cursor, &apts )
442 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
443 if (apt->oxid == oxid)
445 result = apt;
446 if (ref) apartment_addref(result);
447 break;
450 LeaveCriticalSection(&csApartment);
452 return result;
455 /* gets the apartment which has a given creator thread ID. The caller must
456 * release the reference from the apartment as soon as the apartment pointer
457 * is no longer required. */
458 APARTMENT *apartment_findfromtid(DWORD tid)
460 APARTMENT *result = NULL;
461 struct list *cursor;
463 EnterCriticalSection(&csApartment);
464 LIST_FOR_EACH( cursor, &apts )
466 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
467 if (apt->tid == tid)
469 result = apt;
470 apartment_addref(result);
471 break;
474 LeaveCriticalSection(&csApartment);
476 return result;
479 /* gets the main apartment if it exists. The caller must
480 * release the reference from the apartment as soon as the apartment pointer
481 * is no longer required. */
482 static APARTMENT *apartment_findmain(void)
484 APARTMENT *result;
486 EnterCriticalSection(&csApartment);
488 result = MainApartment;
489 if (result) apartment_addref(result);
491 LeaveCriticalSection(&csApartment);
493 return result;
496 struct host_object_params
498 HKEY hkeydll;
499 CLSID clsid; /* clsid of object to marshal */
500 IID iid; /* interface to marshal */
501 HANDLE event; /* event signalling when ready for multi-threaded case */
502 HRESULT hr; /* result for multi-threaded case */
503 IStream *stream; /* stream that the object will be marshaled into */
504 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
507 static HRESULT apartment_hostobject(struct apartment *apt,
508 const struct host_object_params *params)
510 IUnknown *object;
511 HRESULT hr;
512 static const LARGE_INTEGER llZero;
513 WCHAR dllpath[MAX_PATH+1];
515 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
517 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
519 /* failure: CLSID is not found in registry */
520 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
521 return REGDB_E_CLASSNOTREG;
524 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
525 &params->clsid, &params->iid, (void **)&object);
526 if (FAILED(hr))
527 return hr;
529 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
530 if (FAILED(hr))
531 IUnknown_Release(object);
532 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
534 return hr;
537 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
539 switch (msg)
541 case DM_EXECUTERPC:
542 RPC_ExecuteCall((struct dispatch_params *)lParam);
543 return 0;
544 case DM_HOSTOBJECT:
545 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
546 default:
547 return DefWindowProcW(hWnd, msg, wParam, lParam);
551 struct host_thread_params
553 COINIT threading_model;
554 HANDLE ready_event;
555 HWND apartment_hwnd;
558 /* thread for hosting an object to allow an object to appear to be created in
559 * an apartment with an incompatible threading model */
560 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
562 struct host_thread_params *params = p;
563 MSG msg;
564 HRESULT hr;
565 struct apartment *apt;
567 TRACE("\n");
569 hr = CoInitializeEx(NULL, params->threading_model);
570 if (FAILED(hr)) return hr;
572 apt = COM_CurrentApt();
573 if (params->threading_model == COINIT_APARTMENTTHREADED)
575 apartment_createwindowifneeded(apt);
576 params->apartment_hwnd = apartment_getwindow(apt);
578 else
579 params->apartment_hwnd = NULL;
581 /* force the message queue to be created before signaling parent thread */
582 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
584 SetEvent(params->ready_event);
585 params = NULL; /* can't touch params after here as it may be invalid */
587 while (GetMessageW(&msg, NULL, 0, 0))
589 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
591 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
592 obj_params->hr = apartment_hostobject(apt, obj_params);
593 SetEvent(obj_params->event);
595 else
597 TranslateMessage(&msg);
598 DispatchMessageW(&msg);
602 TRACE("exiting\n");
604 CoUninitialize();
606 return S_OK;
609 /* finds or creates a host apartment, creates the object inside it and returns
610 * a proxy to it so that the object can be used in the apartment of the
611 * caller of this function */
612 static HRESULT apartment_hostobject_in_hostapt(
613 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
614 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
616 struct host_object_params params;
617 HWND apartment_hwnd = NULL;
618 DWORD apartment_tid = 0;
619 HRESULT hr;
621 if (!multi_threaded && main_apartment)
623 APARTMENT *host_apt = apartment_findmain();
624 if (host_apt)
626 apartment_hwnd = apartment_getwindow(host_apt);
627 apartment_release(host_apt);
631 if (!apartment_hwnd)
633 EnterCriticalSection(&apt->cs);
635 if (!apt->host_apt_tid)
637 struct host_thread_params thread_params;
638 HANDLE handles[2];
639 DWORD wait_value;
641 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
642 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
643 thread_params.apartment_hwnd = NULL;
644 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
645 if (!handles[1])
647 CloseHandle(handles[0]);
648 LeaveCriticalSection(&apt->cs);
649 return E_OUTOFMEMORY;
651 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
652 CloseHandle(handles[0]);
653 CloseHandle(handles[1]);
654 if (wait_value == WAIT_OBJECT_0)
655 apt->host_apt_hwnd = thread_params.apartment_hwnd;
656 else
658 LeaveCriticalSection(&apt->cs);
659 return E_OUTOFMEMORY;
663 if (multi_threaded || !main_apartment)
665 apartment_hwnd = apt->host_apt_hwnd;
666 apartment_tid = apt->host_apt_tid;
669 LeaveCriticalSection(&apt->cs);
672 /* another thread may have become the main apartment in the time it took
673 * us to create the thread for the host apartment */
674 if (!apartment_hwnd && !multi_threaded && main_apartment)
676 APARTMENT *host_apt = apartment_findmain();
677 if (host_apt)
679 apartment_hwnd = apartment_getwindow(host_apt);
680 apartment_release(host_apt);
684 params.hkeydll = hkeydll;
685 params.clsid = *rclsid;
686 params.iid = *riid;
687 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
688 if (FAILED(hr))
689 return hr;
690 params.apartment_threaded = !multi_threaded;
691 if (multi_threaded)
693 params.hr = S_OK;
694 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
695 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
696 hr = E_OUTOFMEMORY;
697 else
699 WaitForSingleObject(params.event, INFINITE);
700 hr = params.hr;
702 CloseHandle(params.event);
704 else
706 if (!apartment_hwnd)
708 ERR("host apartment didn't create window\n");
709 hr = E_OUTOFMEMORY;
711 else
712 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
714 if (SUCCEEDED(hr))
715 hr = CoUnmarshalInterface(params.stream, riid, ppv);
716 IStream_Release(params.stream);
717 return hr;
720 /* create a window for the apartment or return the current one if one has
721 * already been created */
722 HRESULT apartment_createwindowifneeded(struct apartment *apt)
724 if (apt->multi_threaded)
725 return S_OK;
727 if (!apt->win)
729 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
730 0, 0, 0, 0,
731 HWND_MESSAGE, 0, hProxyDll, NULL);
732 if (!hwnd)
734 ERR("CreateWindow failed with error %d\n", GetLastError());
735 return HRESULT_FROM_WIN32(GetLastError());
737 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
738 /* someone beat us to it */
739 DestroyWindow(hwnd);
742 return S_OK;
745 /* retrieves the window for the main- or apartment-threaded apartment */
746 HWND apartment_getwindow(const struct apartment *apt)
748 assert(!apt->multi_threaded);
749 return apt->win;
752 void apartment_joinmta(void)
754 apartment_addref(MTA);
755 COM_CurrentInfo()->apt = MTA;
758 /* gets the specified class object by loading the appropriate DLL, if
759 * necessary and calls the DllGetClassObject function for the DLL */
760 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
761 BOOL apartment_threaded,
762 REFCLSID rclsid, REFIID riid, void **ppv)
764 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
765 HRESULT hr = S_OK;
766 BOOL found = FALSE;
767 struct apartment_loaded_dll *apartment_loaded_dll;
769 if (!strcmpiW(dllpath, wszOle32))
771 /* we don't need to control the lifetime of this dll, so use the local
772 * implementation of DllGetClassObject directly */
773 TRACE("calling ole32!DllGetClassObject\n");
774 hr = DllGetClassObject(rclsid, riid, ppv);
776 if (hr != S_OK)
777 ERR("DllGetClassObject returned error 0x%08x\n", hr);
779 return hr;
782 EnterCriticalSection(&apt->cs);
784 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
785 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
787 TRACE("found %s already loaded\n", debugstr_w(dllpath));
788 found = TRUE;
789 break;
792 if (!found)
794 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
795 if (!apartment_loaded_dll)
796 hr = E_OUTOFMEMORY;
797 if (SUCCEEDED(hr))
799 apartment_loaded_dll->unload_time = 0;
800 apartment_loaded_dll->multi_threaded = FALSE;
801 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
802 if (FAILED(hr))
803 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
805 if (SUCCEEDED(hr))
807 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
808 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
812 LeaveCriticalSection(&apt->cs);
814 if (SUCCEEDED(hr))
816 /* one component being multi-threaded overrides any number of
817 * apartment-threaded components */
818 if (!apartment_threaded)
819 apartment_loaded_dll->multi_threaded = TRUE;
821 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
822 /* OK: get the ClassObject */
823 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
825 if (hr != S_OK)
826 ERR("DllGetClassObject returned error 0x%08x\n", hr);
829 return hr;
832 /* frees unused libraries loaded by apartment_getclassobject by calling the
833 * DLL's DllCanUnloadNow entry point */
834 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
836 struct apartment_loaded_dll *entry, *next;
837 EnterCriticalSection(&apt->cs);
838 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
840 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
842 DWORD real_delay = delay;
844 if (real_delay == INFINITE)
846 /* DLLs that return multi-threaded objects aren't unloaded
847 * straight away to cope for programs that have races between
848 * last object destruction and threads in the DLLs that haven't
849 * finished, despite DllCanUnloadNow returning S_OK */
850 if (entry->multi_threaded)
851 real_delay = 10 * 60 * 1000; /* 10 minutes */
852 else
853 real_delay = 0;
856 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
858 list_remove(&entry->entry);
859 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
860 HeapFree(GetProcessHeap(), 0, entry);
862 else
863 entry->unload_time = GetTickCount() + real_delay;
865 else if (entry->unload_time)
866 entry->unload_time = 0;
868 LeaveCriticalSection(&apt->cs);
871 /*****************************************************************************
872 * This section contains OpenDllList implementation
875 /* caller must ensure that library_name is not already in the open dll list */
876 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
878 OpenDll *entry;
879 int len;
880 HRESULT hr = S_OK;
881 HANDLE hLibrary;
882 DllCanUnloadNowFunc DllCanUnloadNow;
883 DllGetClassObjectFunc DllGetClassObject;
885 TRACE("\n");
887 *ret = COMPOBJ_DllList_Get(library_name);
888 if (*ret) return S_OK;
890 /* do this outside the csOpenDllList to avoid creating a lock dependency on
891 * the loader lock */
892 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
893 if (!hLibrary)
895 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
896 /* failure: DLL could not be loaded */
897 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
900 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
901 /* Note: failing to find DllCanUnloadNow is not a failure */
902 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
903 if (!DllGetClassObject)
905 /* failure: the dll did not export DllGetClassObject */
906 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
907 FreeLibrary(hLibrary);
908 return CO_E_DLLNOTFOUND;
911 EnterCriticalSection( &csOpenDllList );
913 *ret = COMPOBJ_DllList_Get(library_name);
914 if (*ret)
916 /* another caller to this function already added the dll while we
917 * weren't in the critical section */
918 FreeLibrary(hLibrary);
920 else
922 len = strlenW(library_name);
923 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
924 if (entry)
925 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
926 if (entry && entry->library_name)
928 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
929 entry->library = hLibrary;
930 entry->refs = 1;
931 entry->DllCanUnloadNow = DllCanUnloadNow;
932 entry->DllGetClassObject = DllGetClassObject;
933 list_add_tail(&openDllList, &entry->entry);
935 else
937 HeapFree(GetProcessHeap(), 0, entry);
938 hr = E_OUTOFMEMORY;
939 FreeLibrary(hLibrary);
941 *ret = entry;
944 LeaveCriticalSection( &csOpenDllList );
946 return hr;
949 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
951 OpenDll *ptr;
952 OpenDll *ret = NULL;
953 EnterCriticalSection(&csOpenDllList);
954 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
956 if (!strcmpiW(library_name, ptr->library_name) &&
957 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
959 ret = ptr;
960 break;
963 LeaveCriticalSection(&csOpenDllList);
964 return ret;
967 /* pass FALSE for free_entry to release a reference without destroying the
968 * entry if it reaches zero or TRUE otherwise */
969 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
971 if (!InterlockedDecrement(&entry->refs) && free_entry)
973 EnterCriticalSection(&csOpenDllList);
974 list_remove(&entry->entry);
975 LeaveCriticalSection(&csOpenDllList);
977 TRACE("freeing %p\n", entry->library);
978 FreeLibrary(entry->library);
980 HeapFree(GetProcessHeap(), 0, entry->library_name);
981 HeapFree(GetProcessHeap(), 0, entry);
985 /* frees memory associated with active dll list */
986 static void COMPOBJ_DllList_Free(void)
988 OpenDll *entry, *cursor2;
989 EnterCriticalSection(&csOpenDllList);
990 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
992 list_remove(&entry->entry);
994 HeapFree(GetProcessHeap(), 0, entry->library_name);
995 HeapFree(GetProcessHeap(), 0, entry);
997 LeaveCriticalSection(&csOpenDllList);
1000 /******************************************************************************
1001 * CoBuildVersion [OLE32.@]
1002 * CoBuildVersion [COMPOBJ.1]
1004 * Gets the build version of the DLL.
1006 * PARAMS
1008 * RETURNS
1009 * Current build version, hiword is majornumber, loword is minornumber
1011 DWORD WINAPI CoBuildVersion(void)
1013 TRACE("Returning version %d, build %d.\n", rmm, rup);
1014 return (rmm<<16)+rup;
1017 /******************************************************************************
1018 * CoRegisterInitializeSpy [OLE32.@]
1020 * Add a Spy that watches CoInitializeEx calls
1022 * PARAMS
1023 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1024 * cookie [II] cookie receiver
1026 * RETURNS
1027 * Success: S_OK if not already initialized, S_FALSE otherwise.
1028 * Failure: HRESULT code.
1030 * SEE ALSO
1031 * CoInitializeEx
1033 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1035 struct oletls *info = COM_CurrentInfo();
1036 HRESULT hr;
1038 TRACE("(%p, %p)\n", spy, cookie);
1040 if (!spy || !cookie || !info)
1042 if (!info)
1043 WARN("Could not allocate tls\n");
1044 return E_INVALIDARG;
1047 if (info->spy)
1049 FIXME("Already registered?\n");
1050 return E_UNEXPECTED;
1053 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1054 if (SUCCEEDED(hr))
1056 cookie->QuadPart = (DWORD_PTR)spy;
1057 return S_OK;
1059 return hr;
1062 /******************************************************************************
1063 * CoRevokeInitializeSpy [OLE32.@]
1065 * Remove a spy that previously watched CoInitializeEx calls
1067 * PARAMS
1068 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1070 * RETURNS
1071 * Success: S_OK if a spy is removed
1072 * Failure: E_INVALIDARG
1074 * SEE ALSO
1075 * CoInitializeEx
1077 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1079 struct oletls *info = COM_CurrentInfo();
1080 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1082 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1083 return E_INVALIDARG;
1085 IUnknown_Release(info->spy);
1086 info->spy = NULL;
1087 return S_OK;
1091 /******************************************************************************
1092 * CoInitialize [OLE32.@]
1094 * Initializes the COM libraries by calling CoInitializeEx with
1095 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1097 * PARAMS
1098 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1100 * RETURNS
1101 * Success: S_OK if not already initialized, S_FALSE otherwise.
1102 * Failure: HRESULT code.
1104 * SEE ALSO
1105 * CoInitializeEx
1107 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1110 * Just delegate to the newer method.
1112 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1115 /******************************************************************************
1116 * CoInitializeEx [OLE32.@]
1118 * Initializes the COM libraries.
1120 * PARAMS
1121 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1122 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1124 * RETURNS
1125 * S_OK if successful,
1126 * S_FALSE if this function was called already.
1127 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1128 * threading model.
1130 * NOTES
1132 * The behavior used to set the IMalloc used for memory management is
1133 * obsolete.
1134 * The dwCoInit parameter must specify one of the following apartment
1135 * threading models:
1136 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1137 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1138 * The parameter may also specify zero or more of the following flags:
1139 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1140 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1142 * SEE ALSO
1143 * CoUninitialize
1145 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1147 struct oletls *info = COM_CurrentInfo();
1148 HRESULT hr = S_OK;
1149 APARTMENT *apt;
1151 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1153 if (lpReserved!=NULL)
1155 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1159 * Check the lock count. If this is the first time going through the initialize
1160 * process, we have to initialize the libraries.
1162 * And crank-up that lock count.
1164 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1167 * Initialize the various COM libraries and data structures.
1169 TRACE("() - Initializing the COM libraries\n");
1171 /* we may need to defer this until after apartment initialisation */
1172 RunningObjectTableImpl_Initialize();
1175 if (info->spy)
1176 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1178 if (!(apt = info->apt))
1180 apt = apartment_get_or_create(dwCoInit);
1181 if (!apt) return E_OUTOFMEMORY;
1183 else if (!apartment_is_model(apt, dwCoInit))
1185 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1186 code then we are probably using the wrong threading model to implement that API. */
1187 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1188 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1189 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1190 return RPC_E_CHANGED_MODE;
1192 else
1193 hr = S_FALSE;
1195 info->inits++;
1197 if (info->spy)
1198 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1200 return hr;
1203 /***********************************************************************
1204 * CoUninitialize [OLE32.@]
1206 * This method will decrement the refcount on the current apartment, freeing
1207 * the resources associated with it if it is the last thread in the apartment.
1208 * If the last apartment is freed, the function will additionally release
1209 * any COM resources associated with the process.
1211 * PARAMS
1213 * RETURNS
1214 * Nothing.
1216 * SEE ALSO
1217 * CoInitializeEx
1219 void WINAPI CoUninitialize(void)
1221 struct oletls * info = COM_CurrentInfo();
1222 LONG lCOMRefCnt;
1224 TRACE("()\n");
1226 /* will only happen on OOM */
1227 if (!info) return;
1229 if (info->spy)
1230 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1232 /* sanity check */
1233 if (!info->inits)
1235 ERR("Mismatched CoUninitialize\n");
1237 if (info->spy)
1238 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1239 return;
1242 if (!--info->inits)
1244 apartment_release(info->apt);
1245 info->apt = NULL;
1249 * Decrease the reference count.
1250 * If we are back to 0 locks on the COM library, make sure we free
1251 * all the associated data structures.
1253 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1254 if (lCOMRefCnt==1)
1256 TRACE("() - Releasing the COM libraries\n");
1258 RunningObjectTableImpl_UnInitialize();
1260 else if (lCOMRefCnt<1) {
1261 ERR( "CoUninitialize() - not CoInitialized.\n" );
1262 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1264 if (info->spy)
1265 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1268 /******************************************************************************
1269 * CoDisconnectObject [OLE32.@]
1271 * Disconnects all connections to this object from remote processes. Dispatches
1272 * pending RPCs while blocking new RPCs from occurring, and then calls
1273 * IMarshal::DisconnectObject on the given object.
1275 * Typically called when the object server is forced to shut down, for instance by
1276 * the user.
1278 * PARAMS
1279 * lpUnk [I] The object whose stub should be disconnected.
1280 * reserved [I] Reserved. Should be set to 0.
1282 * RETURNS
1283 * Success: S_OK.
1284 * Failure: HRESULT code.
1286 * SEE ALSO
1287 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1289 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1291 HRESULT hr;
1292 IMarshal *marshal;
1293 APARTMENT *apt;
1295 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1297 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1298 if (hr == S_OK)
1300 hr = IMarshal_DisconnectObject(marshal, reserved);
1301 IMarshal_Release(marshal);
1302 return hr;
1305 apt = COM_CurrentApt();
1306 if (!apt)
1307 return CO_E_NOTINITIALIZED;
1309 apartment_disconnectobject(apt, lpUnk);
1311 /* Note: native is pretty broken here because it just silently
1312 * fails, without returning an appropriate error code if the object was
1313 * not found, making apps think that the object was disconnected, when
1314 * it actually wasn't */
1316 return S_OK;
1319 /******************************************************************************
1320 * CoCreateGuid [OLE32.@]
1321 * CoCreateGuid [COMPOBJ.73]
1323 * Simply forwards to UuidCreate in RPCRT4.
1325 * PARAMS
1326 * pguid [O] Points to the GUID to initialize.
1328 * RETURNS
1329 * Success: S_OK.
1330 * Failure: HRESULT code.
1332 * SEE ALSO
1333 * UuidCreate
1335 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1337 DWORD status = UuidCreate(pguid);
1338 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1339 return HRESULT_FROM_WIN32( status );
1342 /******************************************************************************
1343 * CLSIDFromString [OLE32.@]
1344 * IIDFromString [OLE32.@]
1346 * Converts a unique identifier from its string representation into
1347 * the GUID struct.
1349 * PARAMS
1350 * idstr [I] The string representation of the GUID.
1351 * id [O] GUID converted from the string.
1353 * RETURNS
1354 * S_OK on success
1355 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1357 * SEE ALSO
1358 * StringFromCLSID
1360 static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1362 int i;
1363 BYTE table[256];
1365 if (!s) {
1366 memset( id, 0, sizeof (CLSID) );
1367 return S_OK;
1370 /* validate the CLSID string */
1371 if (strlenW(s) != 38)
1372 return CO_E_CLASSSTRING;
1374 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1375 return CO_E_CLASSSTRING;
1377 for (i=1; i<37; i++) {
1378 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1379 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1380 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1381 ((s[i] >= 'A') && (s[i] <= 'F'))))
1382 return CO_E_CLASSSTRING;
1385 TRACE("%s -> %p\n", debugstr_w(s), id);
1387 /* quick lookup table */
1388 memset(table, 0, 256);
1390 for (i = 0; i < 10; i++) {
1391 table['0' + i] = i;
1393 for (i = 0; i < 6; i++) {
1394 table['A' + i] = i+10;
1395 table['a' + i] = i+10;
1398 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1400 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1401 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1402 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1403 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1405 /* these are just sequential bytes */
1406 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1407 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1408 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1409 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1410 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1411 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1412 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1413 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1415 return S_OK;
1418 /*****************************************************************************/
1420 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1422 HRESULT ret;
1424 if (!id)
1425 return E_INVALIDARG;
1427 ret = __CLSIDFromString(idstr, id);
1428 if(ret != S_OK) { /* It appears a ProgID is also valid */
1429 ret = CLSIDFromProgID(idstr, id);
1431 return ret;
1434 /* Converts a GUID into the respective string representation. */
1435 HRESULT WINE_StringFromCLSID(
1436 const CLSID *id, /* [in] GUID to be converted */
1437 LPSTR idstr /* [out] pointer to buffer to contain converted guid */
1439 static const char hex[] = "0123456789ABCDEF";
1440 char *s;
1441 int i;
1443 if (!id)
1444 { ERR("called with id=Null\n");
1445 *idstr = 0x00;
1446 return E_FAIL;
1449 sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1450 id->Data1, id->Data2, id->Data3,
1451 id->Data4[0], id->Data4[1]);
1452 s = &idstr[25];
1454 /* 6 hex bytes */
1455 for (i = 2; i < 8; i++) {
1456 *s++ = hex[id->Data4[i]>>4];
1457 *s++ = hex[id->Data4[i] & 0xf];
1460 *s++ = '}';
1461 *s++ = '\0';
1463 TRACE("%p->%s\n", id, idstr);
1465 return S_OK;
1469 /******************************************************************************
1470 * StringFromCLSID [OLE32.@]
1471 * StringFromIID [OLE32.@]
1473 * Converts a GUID into the respective string representation.
1474 * The target string is allocated using the OLE IMalloc.
1476 * PARAMS
1477 * id [I] the GUID to be converted.
1478 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1480 * RETURNS
1481 * S_OK
1482 * E_FAIL
1484 * SEE ALSO
1485 * StringFromGUID2, CLSIDFromString
1487 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1489 char buf[80];
1490 HRESULT ret;
1491 LPMALLOC mllc;
1493 if ((ret = CoGetMalloc(0,&mllc)))
1494 return ret;
1496 ret=WINE_StringFromCLSID(id,buf);
1497 if (ret == S_OK) {
1498 DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1499 *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1500 MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1502 return ret;
1505 /******************************************************************************
1506 * StringFromGUID2 [OLE32.@]
1507 * StringFromGUID2 [COMPOBJ.76]
1509 * Modified version of StringFromCLSID that allows you to specify max
1510 * buffer size.
1512 * PARAMS
1513 * id [I] GUID to convert to string.
1514 * str [O] Buffer where the result will be stored.
1515 * cmax [I] Size of the buffer in characters.
1517 * RETURNS
1518 * Success: The length of the resulting string in characters.
1519 * Failure: 0.
1521 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1523 char xguid[80];
1525 if (WINE_StringFromCLSID(id,xguid))
1526 return 0;
1527 return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1530 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1531 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1533 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1534 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1535 LONG res;
1536 HKEY key;
1538 strcpyW(path, wszCLSIDSlash);
1539 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1540 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1541 if (res == ERROR_FILE_NOT_FOUND)
1542 return REGDB_E_CLASSNOTREG;
1543 else if (res != ERROR_SUCCESS)
1544 return REGDB_E_READREGDB;
1546 if (!keyname)
1548 *subkey = key;
1549 return S_OK;
1552 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1553 RegCloseKey(key);
1554 if (res == ERROR_FILE_NOT_FOUND)
1555 return REGDB_E_KEYMISSING;
1556 else if (res != ERROR_SUCCESS)
1557 return REGDB_E_READREGDB;
1559 return S_OK;
1562 /* open HKCR\\AppId\\{string form of appid clsid} key */
1563 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1565 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1566 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1567 DWORD res;
1568 WCHAR buf[CHARS_IN_GUID];
1569 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1570 DWORD size;
1571 HKEY hkey;
1572 DWORD type;
1573 HRESULT hr;
1575 /* read the AppID value under the class's key */
1576 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1577 if (FAILED(hr))
1578 return hr;
1580 size = sizeof(buf);
1581 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1582 RegCloseKey(hkey);
1583 if (res == ERROR_FILE_NOT_FOUND)
1584 return REGDB_E_KEYMISSING;
1585 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1586 return REGDB_E_READREGDB;
1588 strcpyW(keyname, szAppIdKey);
1589 strcatW(keyname, buf);
1590 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1591 if (res == ERROR_FILE_NOT_FOUND)
1592 return REGDB_E_KEYMISSING;
1593 else if (res != ERROR_SUCCESS)
1594 return REGDB_E_READREGDB;
1596 return S_OK;
1599 /******************************************************************************
1600 * ProgIDFromCLSID [OLE32.@]
1602 * Converts a class id into the respective program ID.
1604 * PARAMS
1605 * clsid [I] Class ID, as found in registry.
1606 * ppszProgID [O] Associated ProgID.
1608 * RETURNS
1609 * S_OK
1610 * E_OUTOFMEMORY
1611 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1613 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1615 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1616 HKEY hkey;
1617 HRESULT ret;
1618 LONG progidlen = 0;
1620 if (!ppszProgID)
1622 ERR("ppszProgId isn't optional\n");
1623 return E_INVALIDARG;
1626 *ppszProgID = NULL;
1627 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1628 if (FAILED(ret))
1629 return ret;
1631 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1632 ret = REGDB_E_CLASSNOTREG;
1634 if (ret == S_OK)
1636 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1637 if (*ppszProgID)
1639 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1640 ret = REGDB_E_CLASSNOTREG;
1642 else
1643 ret = E_OUTOFMEMORY;
1646 RegCloseKey(hkey);
1647 return ret;
1650 /******************************************************************************
1651 * CLSIDFromProgID [OLE32.@]
1653 * Converts a program id into the respective GUID.
1655 * PARAMS
1656 * progid [I] Unicode program ID, as found in registry.
1657 * clsid [O] Associated CLSID.
1659 * RETURNS
1660 * Success: S_OK
1661 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1663 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1665 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1666 WCHAR buf2[CHARS_IN_GUID];
1667 LONG buf2len = sizeof(buf2);
1668 HKEY xhkey;
1669 WCHAR *buf;
1671 if (!progid || !clsid)
1673 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1674 return E_INVALIDARG;
1677 /* initialise clsid in case of failure */
1678 memset(clsid, 0, sizeof(*clsid));
1680 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1681 strcpyW( buf, progid );
1682 strcatW( buf, clsidW );
1683 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1685 HeapFree(GetProcessHeap(),0,buf);
1686 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1687 return CO_E_CLASSSTRING;
1689 HeapFree(GetProcessHeap(),0,buf);
1691 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1693 RegCloseKey(xhkey);
1694 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1695 return CO_E_CLASSSTRING;
1697 RegCloseKey(xhkey);
1698 return __CLSIDFromString(buf2,clsid);
1702 /*****************************************************************************
1703 * CoGetPSClsid [OLE32.@]
1705 * Retrieves the CLSID of the proxy/stub factory that implements
1706 * IPSFactoryBuffer for the specified interface.
1708 * PARAMS
1709 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1710 * pclsid [O] Where to store returned proxy/stub CLSID.
1712 * RETURNS
1713 * S_OK
1714 * E_OUTOFMEMORY
1715 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1717 * NOTES
1719 * The standard marshaller activates the object with the CLSID
1720 * returned and uses the CreateProxy and CreateStub methods on its
1721 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1722 * given object.
1724 * CoGetPSClsid determines this CLSID by searching the
1725 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1726 * in the registry and any interface id registered by
1727 * CoRegisterPSClsid within the current process.
1729 * BUGS
1731 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1732 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1733 * considered a bug in native unless an application depends on this (unlikely).
1735 * SEE ALSO
1736 * CoRegisterPSClsid.
1738 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1740 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1741 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1742 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1743 WCHAR value[CHARS_IN_GUID];
1744 LONG len;
1745 HKEY hkey;
1746 APARTMENT *apt = COM_CurrentApt();
1747 struct registered_psclsid *registered_psclsid;
1749 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1751 if (!apt)
1753 ERR("apartment not initialised\n");
1754 return CO_E_NOTINITIALIZED;
1757 if (!pclsid)
1759 ERR("pclsid isn't optional\n");
1760 return E_INVALIDARG;
1763 EnterCriticalSection(&apt->cs);
1765 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1766 if (IsEqualIID(&registered_psclsid->iid, riid))
1768 *pclsid = registered_psclsid->clsid;
1769 LeaveCriticalSection(&apt->cs);
1770 return S_OK;
1773 LeaveCriticalSection(&apt->cs);
1775 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1776 strcpyW(path, wszInterface);
1777 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1778 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1780 /* Open the key.. */
1781 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1783 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1784 return REGDB_E_IIDNOTREG;
1787 /* ... Once we have the key, query the registry to get the
1788 value of CLSID as a string, and convert it into a
1789 proper CLSID structure to be passed back to the app */
1790 len = sizeof(value);
1791 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1793 RegCloseKey(hkey);
1794 return REGDB_E_IIDNOTREG;
1796 RegCloseKey(hkey);
1798 /* We have the CLSID we want back from the registry as a string, so
1799 let's convert it into a CLSID structure */
1800 if (CLSIDFromString(value, pclsid) != NOERROR)
1801 return REGDB_E_IIDNOTREG;
1803 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1804 return S_OK;
1807 /*****************************************************************************
1808 * CoRegisterPSClsid [OLE32.@]
1810 * Register a proxy/stub CLSID for the given interface in the current process
1811 * only.
1813 * PARAMS
1814 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1815 * rclsid [I] CLSID of the proxy/stub.
1817 * RETURNS
1818 * Success: S_OK
1819 * Failure: E_OUTOFMEMORY
1821 * NOTES
1823 * This function does not add anything to the registry and the effects are
1824 * limited to the lifetime of the current process.
1826 * SEE ALSO
1827 * CoGetPSClsid.
1829 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1831 APARTMENT *apt = COM_CurrentApt();
1832 struct registered_psclsid *registered_psclsid;
1834 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1836 if (!apt)
1838 ERR("apartment not initialised\n");
1839 return CO_E_NOTINITIALIZED;
1842 EnterCriticalSection(&apt->cs);
1844 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1845 if (IsEqualIID(&registered_psclsid->iid, riid))
1847 registered_psclsid->clsid = *rclsid;
1848 LeaveCriticalSection(&apt->cs);
1849 return S_OK;
1852 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1853 if (!registered_psclsid)
1855 LeaveCriticalSection(&apt->cs);
1856 return E_OUTOFMEMORY;
1859 registered_psclsid->iid = *riid;
1860 registered_psclsid->clsid = *rclsid;
1861 list_add_head(&apt->psclsids, &registered_psclsid->entry);
1863 LeaveCriticalSection(&apt->cs);
1865 return S_OK;
1869 /***
1870 * COM_GetRegisteredClassObject
1872 * This internal method is used to scan the registered class list to
1873 * find a class object.
1875 * Params:
1876 * rclsid Class ID of the class to find.
1877 * dwClsContext Class context to match.
1878 * ppv [out] returns a pointer to the class object. Complying
1879 * to normal COM usage, this method will increase the
1880 * reference count on this object.
1882 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1883 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1885 HRESULT hr = S_FALSE;
1886 RegisteredClass *curClass;
1888 EnterCriticalSection( &csRegisteredClassList );
1890 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1893 * Check if we have a match on the class ID and context.
1895 if ((apt->oxid == curClass->apartment_id) &&
1896 (dwClsContext & curClass->runContext) &&
1897 IsEqualGUID(&(curClass->classIdentifier), rclsid))
1900 * We have a match, return the pointer to the class object.
1902 *ppUnk = curClass->classObject;
1904 IUnknown_AddRef(curClass->classObject);
1906 hr = S_OK;
1907 break;
1911 LeaveCriticalSection( &csRegisteredClassList );
1913 return hr;
1916 /******************************************************************************
1917 * CoRegisterClassObject [OLE32.@]
1919 * Registers the class object for a given class ID. Servers housed in EXE
1920 * files use this method instead of exporting DllGetClassObject to allow
1921 * other code to connect to their objects.
1923 * PARAMS
1924 * rclsid [I] CLSID of the object to register.
1925 * pUnk [I] IUnknown of the object.
1926 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1927 * flags [I] REGCLS flags indicating how connections are made.
1928 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1930 * RETURNS
1931 * S_OK on success,
1932 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
1933 * CO_E_OBJISREG if the object is already registered. We should not return this.
1935 * SEE ALSO
1936 * CoRevokeClassObject, CoGetClassObject
1938 * NOTES
1939 * In-process objects are only registered for the current apartment.
1940 * CoGetClassObject() and CoCreateInstance() will not return objects registered
1941 * in other apartments.
1943 * BUGS
1944 * MSDN claims that multiple interface registrations are legal, but we
1945 * can't do that with our current implementation.
1947 HRESULT WINAPI CoRegisterClassObject(
1948 REFCLSID rclsid,
1949 LPUNKNOWN pUnk,
1950 DWORD dwClsContext,
1951 DWORD flags,
1952 LPDWORD lpdwRegister)
1954 RegisteredClass* newClass;
1955 LPUNKNOWN foundObject;
1956 HRESULT hr;
1957 APARTMENT *apt;
1959 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1960 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1962 if ( (lpdwRegister==0) || (pUnk==0) )
1963 return E_INVALIDARG;
1965 apt = COM_CurrentApt();
1966 if (!apt)
1968 ERR("COM was not initialized\n");
1969 return CO_E_NOTINITIALIZED;
1972 *lpdwRegister = 0;
1974 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1975 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1976 if (flags & REGCLS_MULTIPLEUSE)
1977 dwClsContext |= CLSCTX_INPROC_SERVER;
1980 * First, check if the class is already registered.
1981 * If it is, this should cause an error.
1983 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1984 if (hr == S_OK) {
1985 if (flags & REGCLS_MULTIPLEUSE) {
1986 if (dwClsContext & CLSCTX_LOCAL_SERVER)
1987 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1988 IUnknown_Release(foundObject);
1989 return hr;
1991 IUnknown_Release(foundObject);
1992 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1993 return CO_E_OBJISREG;
1996 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1997 if ( newClass == NULL )
1998 return E_OUTOFMEMORY;
2000 newClass->classIdentifier = *rclsid;
2001 newClass->apartment_id = apt->oxid;
2002 newClass->runContext = dwClsContext;
2003 newClass->connectFlags = flags;
2004 newClass->pMarshaledData = NULL;
2005 newClass->RpcRegistration = NULL;
2008 * Use the address of the chain node as the cookie since we are sure it's
2009 * unique. FIXME: not on 64-bit platforms.
2011 newClass->dwCookie = (DWORD)newClass;
2014 * Since we're making a copy of the object pointer, we have to increase its
2015 * reference count.
2017 newClass->classObject = pUnk;
2018 IUnknown_AddRef(newClass->classObject);
2020 EnterCriticalSection( &csRegisteredClassList );
2021 list_add_tail(&RegisteredClassList, &newClass->entry);
2022 LeaveCriticalSection( &csRegisteredClassList );
2024 *lpdwRegister = newClass->dwCookie;
2026 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2027 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2028 if (hr) {
2029 FIXME("Failed to create stream on hglobal, %x\n", hr);
2030 return hr;
2032 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
2033 newClass->classObject, MSHCTX_LOCAL, NULL,
2034 MSHLFLAGS_TABLESTRONG);
2035 if (hr) {
2036 FIXME("CoMarshalInterface failed, %x!\n",hr);
2037 return hr;
2040 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2041 newClass->pMarshaledData,
2042 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2043 &newClass->RpcRegistration);
2045 return S_OK;
2048 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
2050 list_remove(&curClass->entry);
2052 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
2053 RPC_StopLocalServer(curClass->RpcRegistration);
2056 * Release the reference to the class object.
2058 IUnknown_Release(curClass->classObject);
2060 if (curClass->pMarshaledData)
2062 LARGE_INTEGER zero;
2063 memset(&zero, 0, sizeof(zero));
2064 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
2065 CoReleaseMarshalData(curClass->pMarshaledData);
2066 IStream_Release(curClass->pMarshaledData);
2069 HeapFree(GetProcessHeap(), 0, curClass);
2072 static void COM_RevokeAllClasses(const struct apartment *apt)
2074 RegisteredClass *curClass, *cursor;
2076 EnterCriticalSection( &csRegisteredClassList );
2078 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
2080 if (curClass->apartment_id == apt->oxid)
2081 COM_RevokeRegisteredClassObject(curClass);
2084 LeaveCriticalSection( &csRegisteredClassList );
2087 /***********************************************************************
2088 * CoRevokeClassObject [OLE32.@]
2090 * Removes a class object from the class registry.
2092 * PARAMS
2093 * dwRegister [I] Cookie returned from CoRegisterClassObject().
2095 * RETURNS
2096 * Success: S_OK.
2097 * Failure: HRESULT code.
2099 * NOTES
2100 * Must be called from the same apartment that called CoRegisterClassObject(),
2101 * otherwise it will fail with RPC_E_WRONG_THREAD.
2103 * SEE ALSO
2104 * CoRegisterClassObject
2106 HRESULT WINAPI CoRevokeClassObject(
2107 DWORD dwRegister)
2109 HRESULT hr = E_INVALIDARG;
2110 RegisteredClass *curClass;
2111 APARTMENT *apt;
2113 TRACE("(%08x)\n",dwRegister);
2115 apt = COM_CurrentApt();
2116 if (!apt)
2118 ERR("COM was not initialized\n");
2119 return CO_E_NOTINITIALIZED;
2122 EnterCriticalSection( &csRegisteredClassList );
2124 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2127 * Check if we have a match on the cookie.
2129 if (curClass->dwCookie == dwRegister)
2131 if (curClass->apartment_id == apt->oxid)
2133 COM_RevokeRegisteredClassObject(curClass);
2134 hr = S_OK;
2136 else
2138 ERR("called from wrong apartment, should be called from %s\n",
2139 wine_dbgstr_longlong(curClass->apartment_id));
2140 hr = RPC_E_WRONG_THREAD;
2142 break;
2146 LeaveCriticalSection( &csRegisteredClassList );
2148 return hr;
2151 /***********************************************************************
2152 * COM_RegReadPath [internal]
2154 * Reads a registry value and expands it when necessary
2156 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2158 DWORD ret;
2159 HKEY key;
2160 DWORD keytype;
2161 WCHAR src[MAX_PATH];
2162 DWORD dwLength = dstlen * sizeof(WCHAR);
2164 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
2165 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2166 if (keytype == REG_EXPAND_SZ) {
2167 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2168 } else {
2169 lstrcpynW(dst, src, dstlen);
2172 RegCloseKey (key);
2174 return ret;
2177 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2179 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2180 DWORD keytype;
2181 DWORD ret;
2182 DWORD dwLength = len * sizeof(WCHAR);
2184 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2185 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2186 value[0] = '\0';
2189 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2190 REFCLSID rclsid, REFIID riid,
2191 BOOL hostifnecessary, void **ppv)
2193 WCHAR dllpath[MAX_PATH+1];
2194 BOOL apartment_threaded;
2196 if (hostifnecessary)
2198 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2199 static const WCHAR wszFree[] = {'F','r','e','e',0};
2200 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2201 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2203 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2204 /* "Apartment" */
2205 if (!strcmpiW(threading_model, wszApartment))
2207 apartment_threaded = TRUE;
2208 if (apt->multi_threaded)
2209 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2211 /* "Free" */
2212 else if (!strcmpiW(threading_model, wszFree))
2214 apartment_threaded = FALSE;
2215 if (!apt->multi_threaded)
2216 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2218 /* everything except "Apartment", "Free" and "Both" */
2219 else if (strcmpiW(threading_model, wszBoth))
2221 apartment_threaded = TRUE;
2222 /* everything else is main-threaded */
2223 if (threading_model[0])
2224 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2225 debugstr_w(threading_model), debugstr_guid(rclsid));
2227 if (apt->multi_threaded || !apt->main)
2228 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2230 else
2231 apartment_threaded = FALSE;
2233 else
2234 apartment_threaded = !apt->multi_threaded;
2236 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2238 /* failure: CLSID is not found in registry */
2239 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2240 return REGDB_E_CLASSNOTREG;
2243 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2244 rclsid, riid, ppv);
2247 /***********************************************************************
2248 * CoGetClassObject [OLE32.@]
2250 * Creates an object of the specified class.
2252 * PARAMS
2253 * rclsid [I] Class ID to create an instance of.
2254 * dwClsContext [I] Flags to restrict the location of the created instance.
2255 * pServerInfo [I] Optional. Details for connecting to a remote server.
2256 * iid [I] The ID of the interface of the instance to return.
2257 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2259 * RETURNS
2260 * Success: S_OK
2261 * Failure: HRESULT code.
2263 * NOTES
2264 * The dwClsContext parameter can be one or more of the following:
2265 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2266 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2267 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2268 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2270 * SEE ALSO
2271 * CoCreateInstance()
2273 HRESULT WINAPI CoGetClassObject(
2274 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2275 REFIID iid, LPVOID *ppv)
2277 LPUNKNOWN regClassObject;
2278 HRESULT hres = E_UNEXPECTED;
2279 APARTMENT *apt;
2281 TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2283 if (!ppv)
2284 return E_INVALIDARG;
2286 *ppv = NULL;
2288 apt = COM_CurrentApt();
2289 if (!apt)
2291 ERR("apartment not initialised\n");
2292 return CO_E_NOTINITIALIZED;
2295 if (pServerInfo) {
2296 FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2297 FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2301 * First, try and see if we can't match the class ID with one of the
2302 * registered classes.
2304 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2305 &regClassObject))
2307 /* Get the required interface from the retrieved pointer. */
2308 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2311 * Since QI got another reference on the pointer, we want to release the
2312 * one we already have. If QI was unsuccessful, this will release the object. This
2313 * is good since we are not returning it in the "out" parameter.
2315 IUnknown_Release(regClassObject);
2317 return hres;
2320 /* First try in-process server */
2321 if (CLSCTX_INPROC_SERVER & dwClsContext)
2323 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2324 HKEY hkey;
2326 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2327 return FTMarshalCF_Create(iid, ppv);
2329 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2330 if (FAILED(hres))
2332 if (hres == REGDB_E_CLASSNOTREG)
2333 ERR("class %s not registered\n", debugstr_guid(rclsid));
2334 else if (hres == REGDB_E_KEYMISSING)
2336 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2337 hres = REGDB_E_CLASSNOTREG;
2341 if (SUCCEEDED(hres))
2343 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2344 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2345 RegCloseKey(hkey);
2348 /* return if we got a class, otherwise fall through to one of the
2349 * other types */
2350 if (SUCCEEDED(hres))
2351 return hres;
2354 /* Next try in-process handler */
2355 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2357 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2358 HKEY hkey;
2360 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2361 if (FAILED(hres))
2363 if (hres == REGDB_E_CLASSNOTREG)
2364 ERR("class %s not registered\n", debugstr_guid(rclsid));
2365 else if (hres == REGDB_E_KEYMISSING)
2367 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2368 hres = REGDB_E_CLASSNOTREG;
2372 if (SUCCEEDED(hres))
2374 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2375 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2376 RegCloseKey(hkey);
2379 /* return if we got a class, otherwise fall through to one of the
2380 * other types */
2381 if (SUCCEEDED(hres))
2382 return hres;
2385 /* Next try out of process */
2386 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2388 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2389 if (SUCCEEDED(hres))
2390 return hres;
2393 /* Finally try remote: this requires networked DCOM (a lot of work) */
2394 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2396 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2397 hres = E_NOINTERFACE;
2400 if (FAILED(hres))
2401 ERR("no class object %s could be created for context 0x%x\n",
2402 debugstr_guid(rclsid), dwClsContext);
2403 return hres;
2406 /***********************************************************************
2407 * CoResumeClassObjects (OLE32.@)
2409 * Resumes all class objects registered with REGCLS_SUSPENDED.
2411 * RETURNS
2412 * Success: S_OK.
2413 * Failure: HRESULT code.
2415 HRESULT WINAPI CoResumeClassObjects(void)
2417 FIXME("stub\n");
2418 return S_OK;
2421 /***********************************************************************
2422 * CoCreateInstance [OLE32.@]
2424 * Creates an instance of the specified class.
2426 * PARAMS
2427 * rclsid [I] Class ID to create an instance of.
2428 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2429 * dwClsContext [I] Flags to restrict the location of the created instance.
2430 * iid [I] The ID of the interface of the instance to return.
2431 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2433 * RETURNS
2434 * Success: S_OK
2435 * Failure: HRESULT code.
2437 * NOTES
2438 * The dwClsContext parameter can be one or more of the following:
2439 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2440 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2441 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2442 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2444 * Aggregation is the concept of deferring the IUnknown of an object to another
2445 * object. This allows a separate object to behave as though it was part of
2446 * the object and to allow this the pUnkOuter parameter can be set. Note that
2447 * not all objects support having an outer of unknown.
2449 * SEE ALSO
2450 * CoGetClassObject()
2452 HRESULT WINAPI CoCreateInstance(
2453 REFCLSID rclsid,
2454 LPUNKNOWN pUnkOuter,
2455 DWORD dwClsContext,
2456 REFIID iid,
2457 LPVOID *ppv)
2459 HRESULT hres;
2460 LPCLASSFACTORY lpclf = 0;
2462 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2463 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2466 * Sanity check
2468 if (ppv==0)
2469 return E_POINTER;
2472 * Initialize the "out" parameter
2474 *ppv = 0;
2476 if (!COM_CurrentApt())
2478 ERR("apartment not initialised\n");
2479 return CO_E_NOTINITIALIZED;
2483 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2484 * Rather than create a class factory, we can just check for it here
2486 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2487 if (StdGlobalInterfaceTableInstance == NULL)
2488 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2489 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2490 if (hres) return hres;
2492 TRACE("Retrieved GIT (%p)\n", *ppv);
2493 return S_OK;
2497 * Get a class factory to construct the object we want.
2499 hres = CoGetClassObject(rclsid,
2500 dwClsContext,
2501 NULL,
2502 &IID_IClassFactory,
2503 (LPVOID)&lpclf);
2505 if (FAILED(hres))
2506 return hres;
2509 * Create the object and don't forget to release the factory
2511 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2512 IClassFactory_Release(lpclf);
2513 if(FAILED(hres))
2515 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2516 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2517 else
2518 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2521 return hres;
2524 /***********************************************************************
2525 * CoCreateInstanceEx [OLE32.@]
2527 HRESULT WINAPI CoCreateInstanceEx(
2528 REFCLSID rclsid,
2529 LPUNKNOWN pUnkOuter,
2530 DWORD dwClsContext,
2531 COSERVERINFO* pServerInfo,
2532 ULONG cmq,
2533 MULTI_QI* pResults)
2535 IUnknown* pUnk = NULL;
2536 HRESULT hr;
2537 ULONG index;
2538 ULONG successCount = 0;
2541 * Sanity check
2543 if ( (cmq==0) || (pResults==NULL))
2544 return E_INVALIDARG;
2546 if (pServerInfo!=NULL)
2547 FIXME("() non-NULL pServerInfo not supported!\n");
2550 * Initialize all the "out" parameters.
2552 for (index = 0; index < cmq; index++)
2554 pResults[index].pItf = NULL;
2555 pResults[index].hr = E_NOINTERFACE;
2559 * Get the object and get its IUnknown pointer.
2561 hr = CoCreateInstance(rclsid,
2562 pUnkOuter,
2563 dwClsContext,
2564 &IID_IUnknown,
2565 (VOID**)&pUnk);
2567 if (hr)
2568 return hr;
2571 * Then, query for all the interfaces requested.
2573 for (index = 0; index < cmq; index++)
2575 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2576 pResults[index].pIID,
2577 (VOID**)&(pResults[index].pItf));
2579 if (pResults[index].hr == S_OK)
2580 successCount++;
2584 * Release our temporary unknown pointer.
2586 IUnknown_Release(pUnk);
2588 if (successCount == 0)
2589 return E_NOINTERFACE;
2591 if (successCount!=cmq)
2592 return CO_S_NOTALLINTERFACES;
2594 return S_OK;
2597 /***********************************************************************
2598 * CoLoadLibrary (OLE32.@)
2600 * Loads a library.
2602 * PARAMS
2603 * lpszLibName [I] Path to library.
2604 * bAutoFree [I] Whether the library should automatically be freed.
2606 * RETURNS
2607 * Success: Handle to loaded library.
2608 * Failure: NULL.
2610 * SEE ALSO
2611 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2613 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2615 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2617 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2620 /***********************************************************************
2621 * CoFreeLibrary [OLE32.@]
2623 * Unloads a library from memory.
2625 * PARAMS
2626 * hLibrary [I] Handle to library to unload.
2628 * RETURNS
2629 * Nothing
2631 * SEE ALSO
2632 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2634 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2636 FreeLibrary(hLibrary);
2640 /***********************************************************************
2641 * CoFreeAllLibraries [OLE32.@]
2643 * Function for backwards compatibility only. Does nothing.
2645 * RETURNS
2646 * Nothing.
2648 * SEE ALSO
2649 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2651 void WINAPI CoFreeAllLibraries(void)
2653 /* NOP */
2656 /***********************************************************************
2657 * CoFreeUnusedLibrariesEx [OLE32.@]
2659 * Frees any previously unused libraries whose delay has expired and marks
2660 * currently unused libraries for unloading. Unused are identified as those that
2661 * return S_OK from their DllCanUnloadNow function.
2663 * PARAMS
2664 * dwUnloadDelay [I] Unload delay in milliseconds.
2665 * dwReserved [I] Reserved. Set to 0.
2667 * RETURNS
2668 * Nothing.
2670 * SEE ALSO
2671 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2673 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2675 struct apartment *apt = COM_CurrentApt();
2676 if (!apt)
2678 ERR("apartment not initialised\n");
2679 return;
2682 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2685 /***********************************************************************
2686 * CoFreeUnusedLibraries [OLE32.@]
2687 * CoFreeUnusedLibraries [COMPOBJ.17]
2689 * Frees any unused libraries. Unused are identified as those that return
2690 * S_OK from their DllCanUnloadNow function.
2692 * RETURNS
2693 * Nothing.
2695 * SEE ALSO
2696 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2698 void WINAPI CoFreeUnusedLibraries(void)
2700 CoFreeUnusedLibrariesEx(INFINITE, 0);
2703 /***********************************************************************
2704 * CoFileTimeNow [OLE32.@]
2705 * CoFileTimeNow [COMPOBJ.82]
2707 * Retrieves the current time in FILETIME format.
2709 * PARAMS
2710 * lpFileTime [O] The current time.
2712 * RETURNS
2713 * S_OK.
2715 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2717 GetSystemTimeAsFileTime( lpFileTime );
2718 return S_OK;
2721 /******************************************************************************
2722 * CoLockObjectExternal [OLE32.@]
2724 * Increments or decrements the external reference count of a stub object.
2726 * PARAMS
2727 * pUnk [I] Stub object.
2728 * fLock [I] If TRUE then increments the external ref-count,
2729 * otherwise decrements.
2730 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2731 * calling CoDisconnectObject.
2733 * RETURNS
2734 * Success: S_OK.
2735 * Failure: HRESULT code.
2737 * NOTES
2738 * If fLock is TRUE and an object is passed in that doesn't have a stub
2739 * manager then a new stub manager is created for the object.
2741 HRESULT WINAPI CoLockObjectExternal(
2742 LPUNKNOWN pUnk,
2743 BOOL fLock,
2744 BOOL fLastUnlockReleases)
2746 struct stub_manager *stubmgr;
2747 struct apartment *apt;
2749 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2750 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2752 apt = COM_CurrentApt();
2753 if (!apt) return CO_E_NOTINITIALIZED;
2755 stubmgr = get_stub_manager_from_object(apt, pUnk);
2757 if (stubmgr)
2759 if (fLock)
2760 stub_manager_ext_addref(stubmgr, 1, FALSE);
2761 else
2762 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2764 stub_manager_int_release(stubmgr);
2766 return S_OK;
2768 else if (fLock)
2770 stubmgr = new_stub_manager(apt, pUnk);
2772 if (stubmgr)
2774 stub_manager_ext_addref(stubmgr, 1, FALSE);
2775 stub_manager_int_release(stubmgr);
2778 return S_OK;
2780 else
2782 WARN("stub object not found %p\n", pUnk);
2783 /* Note: native is pretty broken here because it just silently
2784 * fails, without returning an appropriate error code, making apps
2785 * think that the object was disconnected, when it actually wasn't */
2786 return S_OK;
2790 /***********************************************************************
2791 * CoInitializeWOW (OLE32.@)
2793 * WOW equivalent of CoInitialize?
2795 * PARAMS
2796 * x [I] Unknown.
2797 * y [I] Unknown.
2799 * RETURNS
2800 * Unknown.
2802 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2804 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2805 return 0;
2808 /***********************************************************************
2809 * CoGetState [OLE32.@]
2811 * Retrieves the thread state object previously stored by CoSetState().
2813 * PARAMS
2814 * ppv [I] Address where pointer to object will be stored.
2816 * RETURNS
2817 * Success: S_OK.
2818 * Failure: E_OUTOFMEMORY.
2820 * NOTES
2821 * Crashes on all invalid ppv addresses, including NULL.
2822 * If the function returns a non-NULL object then the caller must release its
2823 * reference on the object when the object is no longer required.
2825 * SEE ALSO
2826 * CoSetState().
2828 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2830 struct oletls *info = COM_CurrentInfo();
2831 if (!info) return E_OUTOFMEMORY;
2833 *ppv = NULL;
2835 if (info->state)
2837 IUnknown_AddRef(info->state);
2838 *ppv = info->state;
2839 TRACE("apt->state=%p\n", info->state);
2842 return S_OK;
2845 /***********************************************************************
2846 * CoSetState [OLE32.@]
2848 * Sets the thread state object.
2850 * PARAMS
2851 * pv [I] Pointer to state object to be stored.
2853 * NOTES
2854 * The system keeps a reference on the object while the object stored.
2856 * RETURNS
2857 * Success: S_OK.
2858 * Failure: E_OUTOFMEMORY.
2860 HRESULT WINAPI CoSetState(IUnknown * pv)
2862 struct oletls *info = COM_CurrentInfo();
2863 if (!info) return E_OUTOFMEMORY;
2865 if (pv) IUnknown_AddRef(pv);
2867 if (info->state)
2869 TRACE("-- release %p now\n", info->state);
2870 IUnknown_Release(info->state);
2873 info->state = pv;
2875 return S_OK;
2879 /******************************************************************************
2880 * CoTreatAsClass [OLE32.@]
2882 * Sets the TreatAs value of a class.
2884 * PARAMS
2885 * clsidOld [I] Class to set TreatAs value on.
2886 * clsidNew [I] The class the clsidOld should be treated as.
2888 * RETURNS
2889 * Success: S_OK.
2890 * Failure: HRESULT code.
2892 * SEE ALSO
2893 * CoGetTreatAsClass
2895 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2897 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2898 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2899 HKEY hkey = NULL;
2900 WCHAR szClsidNew[CHARS_IN_GUID];
2901 HRESULT res = S_OK;
2902 WCHAR auto_treat_as[CHARS_IN_GUID];
2903 LONG auto_treat_as_size = sizeof(auto_treat_as);
2904 CLSID id;
2906 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2907 if (FAILED(res))
2908 goto done;
2909 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2911 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2912 CLSIDFromString(auto_treat_as, &id) == S_OK)
2914 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2916 res = REGDB_E_WRITEREGDB;
2917 goto done;
2920 else
2922 RegDeleteKeyW(hkey, wszTreatAs);
2923 goto done;
2926 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2927 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2929 res = REGDB_E_WRITEREGDB;
2930 goto done;
2933 done:
2934 if (hkey) RegCloseKey(hkey);
2935 return res;
2938 /******************************************************************************
2939 * CoGetTreatAsClass [OLE32.@]
2941 * Gets the TreatAs value of a class.
2943 * PARAMS
2944 * clsidOld [I] Class to get the TreatAs value of.
2945 * clsidNew [I] The class the clsidOld should be treated as.
2947 * RETURNS
2948 * Success: S_OK.
2949 * Failure: HRESULT code.
2951 * SEE ALSO
2952 * CoSetTreatAsClass
2954 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2956 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2957 HKEY hkey = NULL;
2958 WCHAR szClsidNew[CHARS_IN_GUID];
2959 HRESULT res = S_OK;
2960 LONG len = sizeof(szClsidNew);
2962 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2963 *clsidNew = *clsidOld; /* copy over old value */
2965 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2966 if (FAILED(res))
2967 goto done;
2968 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2970 res = S_FALSE;
2971 goto done;
2973 res = CLSIDFromString(szClsidNew,clsidNew);
2974 if (FAILED(res))
2975 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2976 done:
2977 if (hkey) RegCloseKey(hkey);
2978 return res;
2981 /******************************************************************************
2982 * CoGetCurrentProcess [OLE32.@]
2983 * CoGetCurrentProcess [COMPOBJ.34]
2985 * Gets the current process ID.
2987 * RETURNS
2988 * The current process ID.
2990 * NOTES
2991 * Is DWORD really the correct return type for this function?
2993 DWORD WINAPI CoGetCurrentProcess(void)
2995 return GetCurrentProcessId();
2998 /******************************************************************************
2999 * CoRegisterMessageFilter [OLE32.@]
3001 * Registers a message filter.
3003 * PARAMS
3004 * lpMessageFilter [I] Pointer to interface.
3005 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3007 * RETURNS
3008 * Success: S_OK.
3009 * Failure: HRESULT code.
3011 * NOTES
3012 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3013 * lpMessageFilter removes the message filter.
3015 * If lplpMessageFilter is not NULL the previous message filter will be
3016 * returned in the memory pointer to this parameter and the caller is
3017 * responsible for releasing the object.
3019 * The current thread be in an apartment otherwise the function will crash.
3021 HRESULT WINAPI CoRegisterMessageFilter(
3022 LPMESSAGEFILTER lpMessageFilter,
3023 LPMESSAGEFILTER *lplpMessageFilter)
3025 struct apartment *apt;
3026 IMessageFilter *lpOldMessageFilter;
3028 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3030 apt = COM_CurrentApt();
3032 /* can't set a message filter in a multi-threaded apartment */
3033 if (!apt || apt->multi_threaded)
3035 WARN("can't set message filter in MTA or uninitialized apt\n");
3036 return CO_E_NOT_SUPPORTED;
3039 if (lpMessageFilter)
3040 IMessageFilter_AddRef(lpMessageFilter);
3042 EnterCriticalSection(&apt->cs);
3044 lpOldMessageFilter = apt->filter;
3045 apt->filter = lpMessageFilter;
3047 LeaveCriticalSection(&apt->cs);
3049 if (lplpMessageFilter)
3050 *lplpMessageFilter = lpOldMessageFilter;
3051 else if (lpOldMessageFilter)
3052 IMessageFilter_Release(lpOldMessageFilter);
3054 return S_OK;
3057 /***********************************************************************
3058 * CoIsOle1Class [OLE32.@]
3060 * Determines whether the specified class an OLE v1 class.
3062 * PARAMS
3063 * clsid [I] Class to test.
3065 * RETURNS
3066 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3068 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3070 FIXME("%s\n", debugstr_guid(clsid));
3071 return FALSE;
3074 /***********************************************************************
3075 * IsEqualGUID [OLE32.@]
3077 * Compares two Unique Identifiers.
3079 * PARAMS
3080 * rguid1 [I] The first GUID to compare.
3081 * rguid2 [I] The other GUID to compare.
3083 * RETURNS
3084 * TRUE if equal
3086 #undef IsEqualGUID
3087 BOOL WINAPI IsEqualGUID(
3088 REFGUID rguid1,
3089 REFGUID rguid2)
3091 return !memcmp(rguid1,rguid2,sizeof(GUID));
3094 /***********************************************************************
3095 * CoInitializeSecurity [OLE32.@]
3097 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3098 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3099 void* pReserved1, DWORD dwAuthnLevel,
3100 DWORD dwImpLevel, void* pReserved2,
3101 DWORD dwCapabilities, void* pReserved3)
3103 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3104 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3105 dwCapabilities, pReserved3);
3106 return S_OK;
3109 /***********************************************************************
3110 * CoSuspendClassObjects [OLE32.@]
3112 * Suspends all registered class objects to prevent further requests coming in
3113 * for those objects.
3115 * RETURNS
3116 * Success: S_OK.
3117 * Failure: HRESULT code.
3119 HRESULT WINAPI CoSuspendClassObjects(void)
3121 FIXME("\n");
3122 return S_OK;
3125 /***********************************************************************
3126 * CoAddRefServerProcess [OLE32.@]
3128 * Helper function for incrementing the reference count of a local-server
3129 * process.
3131 * RETURNS
3132 * New reference count.
3134 * SEE ALSO
3135 * CoReleaseServerProcess().
3137 ULONG WINAPI CoAddRefServerProcess(void)
3139 ULONG refs;
3141 TRACE("\n");
3143 EnterCriticalSection(&csRegisteredClassList);
3144 refs = ++s_COMServerProcessReferences;
3145 LeaveCriticalSection(&csRegisteredClassList);
3147 TRACE("refs before: %d\n", refs - 1);
3149 return refs;
3152 /***********************************************************************
3153 * CoReleaseServerProcess [OLE32.@]
3155 * Helper function for decrementing the reference count of a local-server
3156 * process.
3158 * RETURNS
3159 * New reference count.
3161 * NOTES
3162 * When reference count reaches 0, this function suspends all registered
3163 * classes so no new connections are accepted.
3165 * SEE ALSO
3166 * CoAddRefServerProcess(), CoSuspendClassObjects().
3168 ULONG WINAPI CoReleaseServerProcess(void)
3170 ULONG refs;
3172 TRACE("\n");
3174 EnterCriticalSection(&csRegisteredClassList);
3176 refs = --s_COMServerProcessReferences;
3177 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3179 LeaveCriticalSection(&csRegisteredClassList);
3181 TRACE("refs after: %d\n", refs);
3183 return refs;
3186 /***********************************************************************
3187 * CoIsHandlerConnected [OLE32.@]
3189 * Determines whether a proxy is connected to a remote stub.
3191 * PARAMS
3192 * pUnk [I] Pointer to object that may or may not be connected.
3194 * RETURNS
3195 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3196 * FALSE otherwise.
3198 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3200 FIXME("%p\n", pUnk);
3202 return TRUE;
3205 /***********************************************************************
3206 * CoAllowSetForegroundWindow [OLE32.@]
3209 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3211 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3212 return S_OK;
3215 /***********************************************************************
3216 * CoQueryProxyBlanket [OLE32.@]
3218 * Retrieves the security settings being used by a proxy.
3220 * PARAMS
3221 * pProxy [I] Pointer to the proxy object.
3222 * pAuthnSvc [O] The type of authentication service.
3223 * pAuthzSvc [O] The type of authorization service.
3224 * ppServerPrincName [O] Optional. The server prinicple name.
3225 * pAuthnLevel [O] The authentication level.
3226 * pImpLevel [O] The impersonation level.
3227 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3228 * pCapabilities [O] Flags affecting the security behaviour.
3230 * RETURNS
3231 * Success: S_OK.
3232 * Failure: HRESULT code.
3234 * SEE ALSO
3235 * CoCopyProxy, CoSetProxyBlanket.
3237 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3238 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3239 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3241 IClientSecurity *pCliSec;
3242 HRESULT hr;
3244 TRACE("%p\n", pProxy);
3246 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3247 if (SUCCEEDED(hr))
3249 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3250 pAuthzSvc, ppServerPrincName,
3251 pAuthnLevel, pImpLevel, ppAuthInfo,
3252 pCapabilities);
3253 IClientSecurity_Release(pCliSec);
3256 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3257 return hr;
3260 /***********************************************************************
3261 * CoSetProxyBlanket [OLE32.@]
3263 * Sets the security settings for a proxy.
3265 * PARAMS
3266 * pProxy [I] Pointer to the proxy object.
3267 * AuthnSvc [I] The type of authentication service.
3268 * AuthzSvc [I] The type of authorization service.
3269 * pServerPrincName [I] The server prinicple name.
3270 * AuthnLevel [I] The authentication level.
3271 * ImpLevel [I] The impersonation level.
3272 * pAuthInfo [I] Information specific to the authorization/authentication service.
3273 * Capabilities [I] Flags affecting the security behaviour.
3275 * RETURNS
3276 * Success: S_OK.
3277 * Failure: HRESULT code.
3279 * SEE ALSO
3280 * CoQueryProxyBlanket, CoCopyProxy.
3282 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3283 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3284 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3286 IClientSecurity *pCliSec;
3287 HRESULT hr;
3289 TRACE("%p\n", pProxy);
3291 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3292 if (SUCCEEDED(hr))
3294 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3295 AuthzSvc, pServerPrincName,
3296 AuthnLevel, ImpLevel, pAuthInfo,
3297 Capabilities);
3298 IClientSecurity_Release(pCliSec);
3301 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3302 return hr;
3305 /***********************************************************************
3306 * CoCopyProxy [OLE32.@]
3308 * Copies a proxy.
3310 * PARAMS
3311 * pProxy [I] Pointer to the proxy object.
3312 * ppCopy [O] Copy of the proxy.
3314 * RETURNS
3315 * Success: S_OK.
3316 * Failure: HRESULT code.
3318 * SEE ALSO
3319 * CoQueryProxyBlanket, CoSetProxyBlanket.
3321 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3323 IClientSecurity *pCliSec;
3324 HRESULT hr;
3326 TRACE("%p\n", pProxy);
3328 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3329 if (SUCCEEDED(hr))
3331 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3332 IClientSecurity_Release(pCliSec);
3335 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3336 return hr;
3340 /***********************************************************************
3341 * CoGetCallContext [OLE32.@]
3343 * Gets the context of the currently executing server call in the current
3344 * thread.
3346 * PARAMS
3347 * riid [I] Context interface to return.
3348 * ppv [O] Pointer to memory that will receive the context on return.
3350 * RETURNS
3351 * Success: S_OK.
3352 * Failure: HRESULT code.
3354 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3356 struct oletls *info = COM_CurrentInfo();
3358 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3360 if (!info)
3361 return E_OUTOFMEMORY;
3363 if (!info->call_state)
3364 return RPC_E_CALL_COMPLETE;
3366 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3369 /***********************************************************************
3370 * CoSwitchCallContext [OLE32.@]
3372 * Switches the context of the currently executing server call in the current
3373 * thread.
3375 * PARAMS
3376 * pObject [I] Pointer to new context object
3377 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3379 * RETURNS
3380 * Success: S_OK.
3381 * Failure: HRESULT code.
3383 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3385 struct oletls *info = COM_CurrentInfo();
3387 TRACE("(%p, %p)\n", pObject, ppOldObject);
3389 if (!info)
3390 return E_OUTOFMEMORY;
3392 *ppOldObject = info->call_state;
3393 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3395 return S_OK;
3398 /***********************************************************************
3399 * CoQueryClientBlanket [OLE32.@]
3401 * Retrieves the authentication information about the client of the currently
3402 * executing server call in the current thread.
3404 * PARAMS
3405 * pAuthnSvc [O] Optional. The type of authentication service.
3406 * pAuthzSvc [O] Optional. The type of authorization service.
3407 * pServerPrincName [O] Optional. The server prinicple name.
3408 * pAuthnLevel [O] Optional. The authentication level.
3409 * pImpLevel [O] Optional. The impersonation level.
3410 * pPrivs [O] Optional. Information about the privileges of the client.
3411 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3413 * RETURNS
3414 * Success: S_OK.
3415 * Failure: HRESULT code.
3417 * SEE ALSO
3418 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3420 HRESULT WINAPI CoQueryClientBlanket(
3421 DWORD *pAuthnSvc,
3422 DWORD *pAuthzSvc,
3423 OLECHAR **pServerPrincName,
3424 DWORD *pAuthnLevel,
3425 DWORD *pImpLevel,
3426 RPC_AUTHZ_HANDLE *pPrivs,
3427 DWORD *pCapabilities)
3429 IServerSecurity *pSrvSec;
3430 HRESULT hr;
3432 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3433 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3434 pPrivs, pCapabilities);
3436 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3437 if (SUCCEEDED(hr))
3439 hr = IServerSecurity_QueryBlanket(
3440 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3441 pImpLevel, pPrivs, pCapabilities);
3442 IServerSecurity_Release(pSrvSec);
3445 return hr;
3448 /***********************************************************************
3449 * CoImpersonateClient [OLE32.@]
3451 * Impersonates the client of the currently executing server call in the
3452 * current thread.
3454 * PARAMS
3455 * None.
3457 * RETURNS
3458 * Success: S_OK.
3459 * Failure: HRESULT code.
3461 * NOTES
3462 * If this function fails then the current thread will not be impersonating
3463 * the client and all actions will take place on behalf of the server.
3464 * Therefore, it is important to check the return value from this function.
3466 * SEE ALSO
3467 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3469 HRESULT WINAPI CoImpersonateClient(void)
3471 IServerSecurity *pSrvSec;
3472 HRESULT hr;
3474 TRACE("\n");
3476 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3477 if (SUCCEEDED(hr))
3479 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3480 IServerSecurity_Release(pSrvSec);
3483 return hr;
3486 /***********************************************************************
3487 * CoRevertToSelf [OLE32.@]
3489 * Ends the impersonation of the client of the currently executing server
3490 * call in the current thread.
3492 * PARAMS
3493 * None.
3495 * RETURNS
3496 * Success: S_OK.
3497 * Failure: HRESULT code.
3499 * SEE ALSO
3500 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3502 HRESULT WINAPI CoRevertToSelf(void)
3504 IServerSecurity *pSrvSec;
3505 HRESULT hr;
3507 TRACE("\n");
3509 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3510 if (SUCCEEDED(hr))
3512 hr = IServerSecurity_RevertToSelf(pSrvSec);
3513 IServerSecurity_Release(pSrvSec);
3516 return hr;
3519 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3521 /* first try to retrieve messages for incoming COM calls to the apartment window */
3522 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3523 /* next retrieve other messages necessary for the app to remain responsive */
3524 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3527 /***********************************************************************
3528 * CoWaitForMultipleHandles [OLE32.@]
3530 * Waits for one or more handles to become signaled.
3532 * PARAMS
3533 * dwFlags [I] Flags. See notes.
3534 * dwTimeout [I] Timeout in milliseconds.
3535 * cHandles [I] Number of handles pointed to by pHandles.
3536 * pHandles [I] Handles to wait for.
3537 * lpdwindex [O] Index of handle that was signaled.
3539 * RETURNS
3540 * Success: S_OK.
3541 * Failure: RPC_S_CALLPENDING on timeout.
3543 * NOTES
3545 * The dwFlags parameter can be zero or more of the following:
3546 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3547 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3549 * SEE ALSO
3550 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3552 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3553 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3555 HRESULT hr = S_OK;
3556 DWORD start_time = GetTickCount();
3557 APARTMENT *apt = COM_CurrentApt();
3558 BOOL message_loop = apt && !apt->multi_threaded;
3560 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3561 pHandles, lpdwindex);
3563 while (TRUE)
3565 DWORD now = GetTickCount();
3566 DWORD res;
3568 if (now - start_time > dwTimeout)
3570 hr = RPC_S_CALLPENDING;
3571 break;
3574 if (message_loop)
3576 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3577 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3579 TRACE("waiting for rpc completion or window message\n");
3581 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3582 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3583 QS_ALLINPUT, wait_flags);
3585 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3587 MSG msg;
3589 /* call message filter */
3591 if (COM_CurrentApt()->filter)
3593 PENDINGTYPE pendingtype =
3594 COM_CurrentInfo()->pending_call_count_server ?
3595 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3596 DWORD be_handled = IMessageFilter_MessagePending(
3597 COM_CurrentApt()->filter, 0 /* FIXME */,
3598 now - start_time, pendingtype);
3599 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3600 switch (be_handled)
3602 case PENDINGMSG_CANCELCALL:
3603 WARN("call canceled\n");
3604 hr = RPC_E_CALL_CANCELED;
3605 break;
3606 case PENDINGMSG_WAITNOPROCESS:
3607 case PENDINGMSG_WAITDEFPROCESS:
3608 default:
3609 /* FIXME: MSDN is very vague about the difference
3610 * between WAITNOPROCESS and WAITDEFPROCESS - there
3611 * appears to be none, so it is possibly a left-over
3612 * from the 16-bit world. */
3613 break;
3617 /* note: using "if" here instead of "while" might seem less
3618 * efficient, but only if we are optimising for quick delivery
3619 * of pending messages, rather than quick completion of the
3620 * COM call */
3621 if (COM_PeekMessage(apt, &msg))
3623 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3624 TranslateMessage(&msg);
3625 DispatchMessageW(&msg);
3626 if (msg.message == WM_QUIT)
3628 TRACE("resending WM_QUIT to outer message loop\n");
3629 PostQuitMessage(msg.wParam);
3630 /* no longer need to process messages */
3631 message_loop = FALSE;
3634 continue;
3637 else
3639 TRACE("waiting for rpc completion\n");
3641 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3642 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3643 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3644 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3647 if (res < WAIT_OBJECT_0 + cHandles)
3649 /* handle signaled, store index */
3650 *lpdwindex = (res - WAIT_OBJECT_0);
3651 break;
3653 else if (res == WAIT_TIMEOUT)
3655 hr = RPC_S_CALLPENDING;
3656 break;
3658 else
3660 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3661 hr = E_UNEXPECTED;
3662 break;
3665 TRACE("-- 0x%08x\n", hr);
3666 return hr;
3670 /***********************************************************************
3671 * CoGetObject [OLE32.@]
3673 * Gets the object named by converting the name to a moniker and binding to it.
3675 * PARAMS
3676 * pszName [I] String representing the object.
3677 * pBindOptions [I] Parameters affecting the binding to the named object.
3678 * riid [I] Interface to bind to on the objecct.
3679 * ppv [O] On output, the interface riid of the object represented
3680 * by pszName.
3682 * RETURNS
3683 * Success: S_OK.
3684 * Failure: HRESULT code.
3686 * SEE ALSO
3687 * MkParseDisplayName.
3689 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3690 REFIID riid, void **ppv)
3692 IBindCtx *pbc;
3693 HRESULT hr;
3695 *ppv = NULL;
3697 hr = CreateBindCtx(0, &pbc);
3698 if (SUCCEEDED(hr))
3700 if (pBindOptions)
3701 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3703 if (SUCCEEDED(hr))
3705 ULONG chEaten;
3706 IMoniker *pmk;
3708 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3709 if (SUCCEEDED(hr))
3711 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3712 IMoniker_Release(pmk);
3716 IBindCtx_Release(pbc);
3718 return hr;
3721 /***********************************************************************
3722 * CoRegisterChannelHook [OLE32.@]
3724 * Registers a process-wide hook that is called during ORPC calls.
3726 * PARAMS
3727 * guidExtension [I] GUID of the channel hook to register.
3728 * pChannelHook [I] Channel hook object to register.
3730 * RETURNS
3731 * Success: S_OK.
3732 * Failure: HRESULT code.
3734 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3736 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3738 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3741 typedef struct Context
3743 const IComThreadingInfoVtbl *lpVtbl;
3744 const IContextCallbackVtbl *lpCallbackVtbl;
3745 LONG refs;
3746 APTTYPE apttype;
3747 } Context;
3749 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3751 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpVtbl));
3754 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3756 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl));
3759 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3761 *ppv = NULL;
3763 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3764 IsEqualIID(riid, &IID_IUnknown))
3766 *ppv = &iface->lpVtbl;
3767 } else if (IsEqualIID(riid, &IID_IContextCallback))
3769 *ppv = &iface->lpCallbackVtbl;
3772 if (*ppv)
3774 IUnknown_AddRef((IUnknown*)*ppv);
3775 return S_OK;
3778 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3779 return E_NOINTERFACE;
3782 static ULONG Context_AddRef(Context *This)
3784 return InterlockedIncrement(&This->refs);
3787 static ULONG Context_Release(Context *This)
3789 ULONG refs = InterlockedDecrement(&This->refs);
3790 if (!refs)
3791 HeapFree(GetProcessHeap(), 0, This);
3792 return refs;
3795 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3797 Context *This = impl_from_IComThreadingInfo(iface);
3798 return Context_QueryInterface(This, riid, ppv);
3801 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3803 Context *This = impl_from_IComThreadingInfo(iface);
3804 return Context_AddRef(This);
3807 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3809 Context *This = impl_from_IComThreadingInfo(iface);
3810 return Context_Release(This);
3813 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3815 Context *This = impl_from_IComThreadingInfo(iface);
3817 TRACE("(%p)\n", apttype);
3819 *apttype = This->apttype;
3820 return S_OK;
3823 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3825 Context *This = impl_from_IComThreadingInfo(iface);
3827 TRACE("(%p)\n", thdtype);
3829 switch (This->apttype)
3831 case APTTYPE_STA:
3832 case APTTYPE_MAINSTA:
3833 *thdtype = THDTYPE_PROCESSMESSAGES;
3834 break;
3835 default:
3836 *thdtype = THDTYPE_BLOCKMESSAGES;
3837 break;
3839 return S_OK;
3842 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3844 FIXME("(%p): stub\n", logical_thread_id);
3845 return E_NOTIMPL;
3848 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3850 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3851 return E_NOTIMPL;
3854 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3856 Context_CTI_QueryInterface,
3857 Context_CTI_AddRef,
3858 Context_CTI_Release,
3859 Context_CTI_GetCurrentApartmentType,
3860 Context_CTI_GetCurrentThreadType,
3861 Context_CTI_GetCurrentLogicalThreadId,
3862 Context_CTI_SetCurrentLogicalThreadId
3865 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
3867 Context *This = impl_from_IContextCallback(iface);
3868 return Context_QueryInterface(This, riid, ppv);
3871 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
3873 Context *This = impl_from_IContextCallback(iface);
3874 return Context_AddRef(This);
3877 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
3879 Context *This = impl_from_IContextCallback(iface);
3880 return Context_Release(This);
3883 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
3884 ComCallData *param, REFIID riid, int method, IUnknown *punk)
3886 Context *This = impl_from_IContextCallback(iface);
3888 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
3889 return E_NOTIMPL;
3892 static const IContextCallbackVtbl Context_Callback_Vtbl =
3894 Context_CC_QueryInterface,
3895 Context_CC_AddRef,
3896 Context_CC_Release,
3897 Context_CC_ContextCallback
3901 /***********************************************************************
3902 * CoGetObjectContext [OLE32.@]
3904 * Retrieves an object associated with the current context (i.e. apartment).
3906 * PARAMS
3907 * riid [I] ID of the interface of the object to retrieve.
3908 * ppv [O] Address where object will be stored on return.
3910 * RETURNS
3911 * Success: S_OK.
3912 * Failure: HRESULT code.
3914 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
3916 APARTMENT *apt = COM_CurrentApt();
3917 Context *context;
3918 HRESULT hr;
3920 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3922 *ppv = NULL;
3923 if (!apt)
3925 ERR("apartment not initialised\n");
3926 return CO_E_NOTINITIALIZED;
3929 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
3930 if (!context)
3931 return E_OUTOFMEMORY;
3933 context->lpVtbl = &Context_Threading_Vtbl;
3934 context->lpCallbackVtbl = &Context_Callback_Vtbl;
3935 context->refs = 1;
3936 if (apt->multi_threaded)
3937 context->apttype = APTTYPE_MTA;
3938 else if (apt->main)
3939 context->apttype = APTTYPE_MAINSTA;
3940 else
3941 context->apttype = APTTYPE_STA;
3943 hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
3944 IUnknown_Release((IUnknown *)&context->lpVtbl);
3946 return hr;
3950 /***********************************************************************
3951 * CoGetContextToken [OLE32.@]
3953 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
3955 struct oletls *info = COM_CurrentInfo();
3956 static int calls;
3957 if(!(calls++)) FIXME( "stub\n" );
3958 if (!info)
3959 return E_OUTOFMEMORY;
3960 if (token) *token = info->context_token;
3961 return E_NOTIMPL;
3965 /***********************************************************************
3966 * DllMain (OLE32.@)
3968 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3970 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3972 switch(fdwReason) {
3973 case DLL_PROCESS_ATTACH:
3974 hProxyDll = hinstDLL;
3975 COMPOBJ_InitProcess();
3976 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3977 break;
3979 case DLL_PROCESS_DETACH:
3980 if (TRACE_ON(ole)) CoRevokeMallocSpy();
3981 OLEDD_UnInitialize();
3982 COMPOBJ_UninitProcess();
3983 RPC_UnregisterAllChannelHooks();
3984 COMPOBJ_DllList_Free();
3985 break;
3987 case DLL_THREAD_DETACH:
3988 COM_TlsDestroy();
3989 break;
3991 return TRUE;
3994 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */