push 8b07bf1f08b23b9893a622b47d2be359556765b1
[wine/hacks.git] / dlls / ole32 / compobj.c
blobc8c48081d40738434cafa1e4594e86c4c31f9322
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #define USE_COM_CONTEXT_DEF
56 #include "objbase.h"
57 #include "ole2.h"
58 #include "ole2ver.h"
59 #include "ctxtcall.h"
60 #include "dde.h"
62 #include "compobj_private.h"
64 #include "wine/unicode.h"
65 #include "wine/debug.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(ole);
69 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
71 /****************************************************************************
72 * This section defines variables internal to the COM module.
75 static APARTMENT *MTA; /* protected by csApartment */
76 static APARTMENT *MainApartment; /* the first STA apartment */
77 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
79 static CRITICAL_SECTION csApartment;
80 static CRITICAL_SECTION_DEBUG critsect_debug =
82 0, 0, &csApartment,
83 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
84 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
86 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
88 struct registered_psclsid
90 struct list entry;
91 IID iid;
92 CLSID clsid;
96 * This lock count counts the number of times CoInitialize is called. It is
97 * decreased every time CoUninitialize is called. When it hits 0, the COM
98 * libraries are freed
100 static LONG s_COMLockCount = 0;
101 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
102 static LONG s_COMServerProcessReferences = 0;
105 * This linked list contains the list of registered class objects. These
106 * are mostly used to register the factories for out-of-proc servers of OLE
107 * objects.
109 * TODO: Make this data structure aware of inter-process communication. This
110 * means that parts of this will be exported to rpcss.
112 typedef struct tagRegisteredClass
114 struct list entry;
115 CLSID classIdentifier;
116 OXID apartment_id;
117 LPUNKNOWN classObject;
118 DWORD runContext;
119 DWORD connectFlags;
120 DWORD dwCookie;
121 LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */
122 void *RpcRegistration;
123 } RegisteredClass;
125 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
127 static CRITICAL_SECTION csRegisteredClassList;
128 static CRITICAL_SECTION_DEBUG class_cs_debug =
130 0, 0, &csRegisteredClassList,
131 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
132 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
134 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
136 /*****************************************************************************
137 * This section contains OpenDllList definitions
139 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
140 * other functions that do LoadLibrary _without_ giving back a HMODULE.
141 * Without this list these handles would never be freed.
143 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
144 * next unload-call but not before 600 sec.
147 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
148 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
150 typedef struct tagOpenDll
152 LONG refs;
153 LPWSTR library_name;
154 HANDLE library;
155 DllGetClassObjectFunc DllGetClassObject;
156 DllCanUnloadNowFunc DllCanUnloadNow;
157 struct list entry;
158 } OpenDll;
160 static struct list openDllList = LIST_INIT(openDllList);
162 static CRITICAL_SECTION csOpenDllList;
163 static CRITICAL_SECTION_DEBUG dll_cs_debug =
165 0, 0, &csOpenDllList,
166 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
167 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
169 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
171 struct apartment_loaded_dll
173 struct list entry;
174 OpenDll *dll;
175 DWORD unload_time;
176 BOOL multi_threaded;
179 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',' ',
180 '0','x','#','#','#','#','#','#','#','#',' ',0};
182 /*****************************************************************************
183 * This section contains OpenDllList implementation
186 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
188 OpenDll *ptr;
189 OpenDll *ret = NULL;
190 EnterCriticalSection(&csOpenDllList);
191 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
193 if (!strcmpiW(library_name, ptr->library_name) &&
194 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
196 ret = ptr;
197 break;
200 LeaveCriticalSection(&csOpenDllList);
201 return ret;
204 /* caller must ensure that library_name is not already in the open dll list */
205 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
207 OpenDll *entry;
208 int len;
209 HRESULT hr = S_OK;
210 HANDLE hLibrary;
211 DllCanUnloadNowFunc DllCanUnloadNow;
212 DllGetClassObjectFunc DllGetClassObject;
214 TRACE("\n");
216 *ret = COMPOBJ_DllList_Get(library_name);
217 if (*ret) return S_OK;
219 /* do this outside the csOpenDllList to avoid creating a lock dependency on
220 * the loader lock */
221 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
222 if (!hLibrary)
224 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
225 /* failure: DLL could not be loaded */
226 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
229 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
230 /* Note: failing to find DllCanUnloadNow is not a failure */
231 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
232 if (!DllGetClassObject)
234 /* failure: the dll did not export DllGetClassObject */
235 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
236 FreeLibrary(hLibrary);
237 return CO_E_DLLNOTFOUND;
240 EnterCriticalSection( &csOpenDllList );
242 *ret = COMPOBJ_DllList_Get(library_name);
243 if (*ret)
245 /* another caller to this function already added the dll while we
246 * weren't in the critical section */
247 FreeLibrary(hLibrary);
249 else
251 len = strlenW(library_name);
252 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
253 if (entry)
254 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
255 if (entry && entry->library_name)
257 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
258 entry->library = hLibrary;
259 entry->refs = 1;
260 entry->DllCanUnloadNow = DllCanUnloadNow;
261 entry->DllGetClassObject = DllGetClassObject;
262 list_add_tail(&openDllList, &entry->entry);
264 else
266 HeapFree(GetProcessHeap(), 0, entry);
267 hr = E_OUTOFMEMORY;
268 FreeLibrary(hLibrary);
270 *ret = entry;
273 LeaveCriticalSection( &csOpenDllList );
275 return hr;
278 /* pass FALSE for free_entry to release a reference without destroying the
279 * entry if it reaches zero or TRUE otherwise */
280 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
282 if (!InterlockedDecrement(&entry->refs) && free_entry)
284 EnterCriticalSection(&csOpenDllList);
285 list_remove(&entry->entry);
286 LeaveCriticalSection(&csOpenDllList);
288 TRACE("freeing %p\n", entry->library);
289 FreeLibrary(entry->library);
291 HeapFree(GetProcessHeap(), 0, entry->library_name);
292 HeapFree(GetProcessHeap(), 0, entry);
296 /* frees memory associated with active dll list */
297 static void COMPOBJ_DllList_Free(void)
299 OpenDll *entry, *cursor2;
300 EnterCriticalSection(&csOpenDllList);
301 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
303 list_remove(&entry->entry);
305 HeapFree(GetProcessHeap(), 0, entry->library_name);
306 HeapFree(GetProcessHeap(), 0, entry);
308 LeaveCriticalSection(&csOpenDllList);
311 /******************************************************************************
312 * Manage apartments.
315 static DWORD apartment_addref(struct apartment *apt)
317 DWORD refs = InterlockedIncrement(&apt->refs);
318 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
319 return refs;
322 /* allocates memory and fills in the necessary fields for a new apartment
323 * object. must be called inside apartment cs */
324 static APARTMENT *apartment_construct(DWORD model)
326 APARTMENT *apt;
328 TRACE("creating new apartment, model=%d\n", model);
330 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
331 apt->tid = GetCurrentThreadId();
333 list_init(&apt->proxies);
334 list_init(&apt->stubmgrs);
335 list_init(&apt->psclsids);
336 list_init(&apt->loaded_dlls);
337 apt->ipidc = 0;
338 apt->refs = 1;
339 apt->remunk_exported = FALSE;
340 apt->oidc = 1;
341 InitializeCriticalSection(&apt->cs);
342 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
344 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
346 if (apt->multi_threaded)
348 /* FIXME: should be randomly generated by in an RPC call to rpcss */
349 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
351 else
353 /* FIXME: should be randomly generated by in an RPC call to rpcss */
354 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
357 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
359 list_add_head(&apts, &apt->entry);
361 return apt;
364 /* gets and existing apartment if one exists or otherwise creates an apartment
365 * structure which stores OLE apartment-local information and stores a pointer
366 * to it in the thread-local storage */
367 static APARTMENT *apartment_get_or_create(DWORD model)
369 APARTMENT *apt = COM_CurrentApt();
371 if (!apt)
373 if (model & COINIT_APARTMENTTHREADED)
375 EnterCriticalSection(&csApartment);
377 apt = apartment_construct(model);
378 if (!MainApartment)
380 MainApartment = apt;
381 apt->main = TRUE;
382 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
385 LeaveCriticalSection(&csApartment);
387 if (apt->main)
388 apartment_createwindowifneeded(apt);
390 else
392 EnterCriticalSection(&csApartment);
394 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
395 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
396 * in a process */
397 if (MTA)
399 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
400 apartment_addref(MTA);
402 else
403 MTA = apartment_construct(model);
405 apt = MTA;
407 LeaveCriticalSection(&csApartment);
409 COM_CurrentInfo()->apt = apt;
412 return apt;
415 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
417 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
420 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
422 list_remove(&curClass->entry);
424 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
425 RPC_StopLocalServer(curClass->RpcRegistration);
428 * Release the reference to the class object.
430 IUnknown_Release(curClass->classObject);
432 if (curClass->pMarshaledData)
434 LARGE_INTEGER zero;
435 memset(&zero, 0, sizeof(zero));
436 IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
437 CoReleaseMarshalData(curClass->pMarshaledData);
438 IStream_Release(curClass->pMarshaledData);
441 HeapFree(GetProcessHeap(), 0, curClass);
444 static void COM_RevokeAllClasses(const struct apartment *apt)
446 RegisteredClass *curClass, *cursor;
448 EnterCriticalSection( &csRegisteredClassList );
450 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
452 if (curClass->apartment_id == apt->oxid)
453 COM_RevokeRegisteredClassObject(curClass);
456 LeaveCriticalSection( &csRegisteredClassList );
459 /***********************************************************************
460 * CoRevokeClassObject [OLE32.@]
462 * Removes a class object from the class registry.
464 * PARAMS
465 * dwRegister [I] Cookie returned from CoRegisterClassObject().
467 * RETURNS
468 * Success: S_OK.
469 * Failure: HRESULT code.
471 * NOTES
472 * Must be called from the same apartment that called CoRegisterClassObject(),
473 * otherwise it will fail with RPC_E_WRONG_THREAD.
475 * SEE ALSO
476 * CoRegisterClassObject
478 HRESULT WINAPI CoRevokeClassObject(
479 DWORD dwRegister)
481 HRESULT hr = E_INVALIDARG;
482 RegisteredClass *curClass;
483 APARTMENT *apt;
485 TRACE("(%08x)\n",dwRegister);
487 apt = COM_CurrentApt();
488 if (!apt)
490 ERR("COM was not initialized\n");
491 return CO_E_NOTINITIALIZED;
494 EnterCriticalSection( &csRegisteredClassList );
496 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
499 * Check if we have a match on the cookie.
501 if (curClass->dwCookie == dwRegister)
503 if (curClass->apartment_id == apt->oxid)
505 COM_RevokeRegisteredClassObject(curClass);
506 hr = S_OK;
508 else
510 ERR("called from wrong apartment, should be called from %s\n",
511 wine_dbgstr_longlong(curClass->apartment_id));
512 hr = RPC_E_WRONG_THREAD;
514 break;
518 LeaveCriticalSection( &csRegisteredClassList );
520 return hr;
523 /* frees unused libraries loaded by apartment_getclassobject by calling the
524 * DLL's DllCanUnloadNow entry point */
525 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
527 struct apartment_loaded_dll *entry, *next;
528 EnterCriticalSection(&apt->cs);
529 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
531 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
533 DWORD real_delay = delay;
535 if (real_delay == INFINITE)
537 /* DLLs that return multi-threaded objects aren't unloaded
538 * straight away to cope for programs that have races between
539 * last object destruction and threads in the DLLs that haven't
540 * finished, despite DllCanUnloadNow returning S_OK */
541 if (entry->multi_threaded)
542 real_delay = 10 * 60 * 1000; /* 10 minutes */
543 else
544 real_delay = 0;
547 if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
549 list_remove(&entry->entry);
550 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
551 HeapFree(GetProcessHeap(), 0, entry);
553 else
554 entry->unload_time = GetTickCount() + real_delay;
556 else if (entry->unload_time)
557 entry->unload_time = 0;
559 LeaveCriticalSection(&apt->cs);
562 DWORD apartment_release(struct apartment *apt)
564 DWORD ret;
566 EnterCriticalSection(&csApartment);
568 ret = InterlockedDecrement(&apt->refs);
569 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
570 /* destruction stuff that needs to happen under csApartment CS */
571 if (ret == 0)
573 if (apt == MTA) MTA = NULL;
574 else if (apt == MainApartment) MainApartment = NULL;
575 list_remove(&apt->entry);
578 LeaveCriticalSection(&csApartment);
580 if (ret == 0)
582 struct list *cursor, *cursor2;
584 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
586 /* Release the references to the registered class objects */
587 COM_RevokeAllClasses(apt);
589 /* no locking is needed for this apartment, because no other thread
590 * can access it at this point */
592 apartment_disconnectproxies(apt);
594 if (apt->win) DestroyWindow(apt->win);
595 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
597 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
599 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
600 /* release the implicit reference given by the fact that the
601 * stub has external references (it must do since it is in the
602 * stub manager list in the apartment and all non-apartment users
603 * must have a ref on the apartment and so it cannot be destroyed).
605 stub_manager_int_release(stubmgr);
608 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
610 struct registered_psclsid *registered_psclsid =
611 LIST_ENTRY(cursor, struct registered_psclsid, entry);
613 list_remove(&registered_psclsid->entry);
614 HeapFree(GetProcessHeap(), 0, registered_psclsid);
617 /* if this assert fires, then another thread took a reference to a
618 * stub manager without taking a reference to the containing
619 * apartment, which it must do. */
620 assert(list_empty(&apt->stubmgrs));
622 if (apt->filter) IUnknown_Release(apt->filter);
624 /* free as many unused libraries as possible... */
625 apartment_freeunusedlibraries(apt, 0);
627 /* ... and free the memory for the apartment loaded dll entry and
628 * release the dll list reference without freeing the library for the
629 * rest */
630 while ((cursor = list_head(&apt->loaded_dlls)))
632 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
633 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
634 list_remove(cursor);
635 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
638 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
639 DeleteCriticalSection(&apt->cs);
641 HeapFree(GetProcessHeap(), 0, apt);
644 return ret;
647 /* The given OXID must be local to this process:
649 * The ref parameter is here mostly to ensure people remember that
650 * they get one, you should normally take a ref for thread safety.
652 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
654 APARTMENT *result = NULL;
655 struct list *cursor;
657 EnterCriticalSection(&csApartment);
658 LIST_FOR_EACH( cursor, &apts )
660 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
661 if (apt->oxid == oxid)
663 result = apt;
664 if (ref) apartment_addref(result);
665 break;
668 LeaveCriticalSection(&csApartment);
670 return result;
673 /* gets the apartment which has a given creator thread ID. The caller must
674 * release the reference from the apartment as soon as the apartment pointer
675 * is no longer required. */
676 APARTMENT *apartment_findfromtid(DWORD tid)
678 APARTMENT *result = NULL;
679 struct list *cursor;
681 EnterCriticalSection(&csApartment);
682 LIST_FOR_EACH( cursor, &apts )
684 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
685 if (apt->tid == tid)
687 result = apt;
688 apartment_addref(result);
689 break;
692 LeaveCriticalSection(&csApartment);
694 return result;
697 /* gets the main apartment if it exists. The caller must
698 * release the reference from the apartment as soon as the apartment pointer
699 * is no longer required. */
700 static APARTMENT *apartment_findmain(void)
702 APARTMENT *result;
704 EnterCriticalSection(&csApartment);
706 result = MainApartment;
707 if (result) apartment_addref(result);
709 LeaveCriticalSection(&csApartment);
711 return result;
714 /* gets the multi-threaded apartment if it exists. The caller must
715 * release the reference from the apartment as soon as the apartment pointer
716 * is no longer required. */
717 static APARTMENT *apartment_find_multi_threaded(void)
719 APARTMENT *result = NULL;
720 struct list *cursor;
722 EnterCriticalSection(&csApartment);
724 LIST_FOR_EACH( cursor, &apts )
726 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
727 if (apt->multi_threaded)
729 result = apt;
730 apartment_addref(result);
731 break;
735 LeaveCriticalSection(&csApartment);
736 return result;
739 /* gets the specified class object by loading the appropriate DLL, if
740 * necessary and calls the DllGetClassObject function for the DLL */
741 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
742 BOOL apartment_threaded,
743 REFCLSID rclsid, REFIID riid, void **ppv)
745 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
746 HRESULT hr = S_OK;
747 BOOL found = FALSE;
748 struct apartment_loaded_dll *apartment_loaded_dll;
750 if (!strcmpiW(dllpath, wszOle32))
752 /* we don't need to control the lifetime of this dll, so use the local
753 * implementation of DllGetClassObject directly */
754 TRACE("calling ole32!DllGetClassObject\n");
755 hr = DllGetClassObject(rclsid, riid, ppv);
757 if (hr != S_OK)
758 ERR("DllGetClassObject returned error 0x%08x\n", hr);
760 return hr;
763 EnterCriticalSection(&apt->cs);
765 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
766 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
768 TRACE("found %s already loaded\n", debugstr_w(dllpath));
769 found = TRUE;
770 break;
773 if (!found)
775 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
776 if (!apartment_loaded_dll)
777 hr = E_OUTOFMEMORY;
778 if (SUCCEEDED(hr))
780 apartment_loaded_dll->unload_time = 0;
781 apartment_loaded_dll->multi_threaded = FALSE;
782 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
783 if (FAILED(hr))
784 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
786 if (SUCCEEDED(hr))
788 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
789 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
793 LeaveCriticalSection(&apt->cs);
795 if (SUCCEEDED(hr))
797 /* one component being multi-threaded overrides any number of
798 * apartment-threaded components */
799 if (!apartment_threaded)
800 apartment_loaded_dll->multi_threaded = TRUE;
802 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
803 /* OK: get the ClassObject */
804 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
806 if (hr != S_OK)
807 ERR("DllGetClassObject returned error 0x%08x\n", hr);
810 return hr;
813 /***********************************************************************
814 * COM_RegReadPath [internal]
816 * Reads a registry value and expands it when necessary
818 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
820 DWORD ret;
821 HKEY key;
822 DWORD keytype;
823 WCHAR src[MAX_PATH];
824 DWORD dwLength = dstlen * sizeof(WCHAR);
826 if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
827 if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
828 if (keytype == REG_EXPAND_SZ) {
829 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
830 } else {
831 lstrcpynW(dst, src, dstlen);
834 RegCloseKey (key);
836 return ret;
839 struct host_object_params
841 HKEY hkeydll;
842 CLSID clsid; /* clsid of object to marshal */
843 IID iid; /* interface to marshal */
844 HANDLE event; /* event signalling when ready for multi-threaded case */
845 HRESULT hr; /* result for multi-threaded case */
846 IStream *stream; /* stream that the object will be marshaled into */
847 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
850 static HRESULT apartment_hostobject(struct apartment *apt,
851 const struct host_object_params *params)
853 IUnknown *object;
854 HRESULT hr;
855 static const LARGE_INTEGER llZero;
856 WCHAR dllpath[MAX_PATH+1];
858 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
860 if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
862 /* failure: CLSID is not found in registry */
863 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
864 return REGDB_E_CLASSNOTREG;
867 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
868 &params->clsid, &params->iid, (void **)&object);
869 if (FAILED(hr))
870 return hr;
872 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
873 if (FAILED(hr))
874 IUnknown_Release(object);
875 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
877 return hr;
880 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
882 switch (msg)
884 case DM_EXECUTERPC:
885 RPC_ExecuteCall((struct dispatch_params *)lParam);
886 return 0;
887 case DM_HOSTOBJECT:
888 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
889 default:
890 return DefWindowProcW(hWnd, msg, wParam, lParam);
894 struct host_thread_params
896 COINIT threading_model;
897 HANDLE ready_event;
898 HWND apartment_hwnd;
901 /* thread for hosting an object to allow an object to appear to be created in
902 * an apartment with an incompatible threading model */
903 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
905 struct host_thread_params *params = p;
906 MSG msg;
907 HRESULT hr;
908 struct apartment *apt;
910 TRACE("\n");
912 hr = CoInitializeEx(NULL, params->threading_model);
913 if (FAILED(hr)) return hr;
915 apt = COM_CurrentApt();
916 if (params->threading_model == COINIT_APARTMENTTHREADED)
918 apartment_createwindowifneeded(apt);
919 params->apartment_hwnd = apartment_getwindow(apt);
921 else
922 params->apartment_hwnd = NULL;
924 /* force the message queue to be created before signaling parent thread */
925 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
927 SetEvent(params->ready_event);
928 params = NULL; /* can't touch params after here as it may be invalid */
930 while (GetMessageW(&msg, NULL, 0, 0))
932 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
934 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
935 obj_params->hr = apartment_hostobject(apt, obj_params);
936 SetEvent(obj_params->event);
938 else
940 TranslateMessage(&msg);
941 DispatchMessageW(&msg);
945 TRACE("exiting\n");
947 CoUninitialize();
949 return S_OK;
952 /* finds or creates a host apartment, creates the object inside it and returns
953 * a proxy to it so that the object can be used in the apartment of the
954 * caller of this function */
955 static HRESULT apartment_hostobject_in_hostapt(
956 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
957 HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
959 struct host_object_params params;
960 HWND apartment_hwnd = NULL;
961 DWORD apartment_tid = 0;
962 HRESULT hr;
964 if (!multi_threaded && main_apartment)
966 APARTMENT *host_apt = apartment_findmain();
967 if (host_apt)
969 apartment_hwnd = apartment_getwindow(host_apt);
970 apartment_release(host_apt);
974 if (!apartment_hwnd)
976 EnterCriticalSection(&apt->cs);
978 if (!apt->host_apt_tid)
980 struct host_thread_params thread_params;
981 HANDLE handles[2];
982 DWORD wait_value;
984 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
985 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
986 thread_params.apartment_hwnd = NULL;
987 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
988 if (!handles[1])
990 CloseHandle(handles[0]);
991 LeaveCriticalSection(&apt->cs);
992 return E_OUTOFMEMORY;
994 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
995 CloseHandle(handles[0]);
996 CloseHandle(handles[1]);
997 if (wait_value == WAIT_OBJECT_0)
998 apt->host_apt_hwnd = thread_params.apartment_hwnd;
999 else
1001 LeaveCriticalSection(&apt->cs);
1002 return E_OUTOFMEMORY;
1006 if (multi_threaded || !main_apartment)
1008 apartment_hwnd = apt->host_apt_hwnd;
1009 apartment_tid = apt->host_apt_tid;
1012 LeaveCriticalSection(&apt->cs);
1015 /* another thread may have become the main apartment in the time it took
1016 * us to create the thread for the host apartment */
1017 if (!apartment_hwnd && !multi_threaded && main_apartment)
1019 APARTMENT *host_apt = apartment_findmain();
1020 if (host_apt)
1022 apartment_hwnd = apartment_getwindow(host_apt);
1023 apartment_release(host_apt);
1027 params.hkeydll = hkeydll;
1028 params.clsid = *rclsid;
1029 params.iid = *riid;
1030 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1031 if (FAILED(hr))
1032 return hr;
1033 params.apartment_threaded = !multi_threaded;
1034 if (multi_threaded)
1036 params.hr = S_OK;
1037 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1038 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1039 hr = E_OUTOFMEMORY;
1040 else
1042 WaitForSingleObject(params.event, INFINITE);
1043 hr = params.hr;
1045 CloseHandle(params.event);
1047 else
1049 if (!apartment_hwnd)
1051 ERR("host apartment didn't create window\n");
1052 hr = E_OUTOFMEMORY;
1054 else
1055 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1057 if (SUCCEEDED(hr))
1058 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1059 IStream_Release(params.stream);
1060 return hr;
1063 /* create a window for the apartment or return the current one if one has
1064 * already been created */
1065 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1067 if (apt->multi_threaded)
1068 return S_OK;
1070 if (!apt->win)
1072 HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1073 0, 0, 0, 0,
1074 HWND_MESSAGE, 0, hProxyDll, NULL);
1075 if (!hwnd)
1077 ERR("CreateWindow failed with error %d\n", GetLastError());
1078 return HRESULT_FROM_WIN32(GetLastError());
1080 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1081 /* someone beat us to it */
1082 DestroyWindow(hwnd);
1085 return S_OK;
1088 /* retrieves the window for the main- or apartment-threaded apartment */
1089 HWND apartment_getwindow(const struct apartment *apt)
1091 assert(!apt->multi_threaded);
1092 return apt->win;
1095 void apartment_joinmta(void)
1097 apartment_addref(MTA);
1098 COM_CurrentInfo()->apt = MTA;
1101 static void COMPOBJ_InitProcess( void )
1103 WNDCLASSW wclass;
1105 /* Dispatching to the correct thread in an apartment is done through
1106 * window messages rather than RPC transports. When an interface is
1107 * marshalled into another apartment in the same process, a window of the
1108 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1109 * application) is responsible for pumping the message loop in that thread.
1110 * The WM_USER messages which point to the RPCs are then dispatched to
1111 * apartment_wndproc by the user's code from the apartment in which the
1112 * interface was unmarshalled.
1114 memset(&wclass, 0, sizeof(wclass));
1115 wclass.lpfnWndProc = apartment_wndproc;
1116 wclass.hInstance = hProxyDll;
1117 wclass.lpszClassName = wszAptWinClass;
1118 RegisterClassW(&wclass);
1121 static void COMPOBJ_UninitProcess( void )
1123 UnregisterClassW(wszAptWinClass, hProxyDll);
1126 static void COM_TlsDestroy(void)
1128 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1129 if (info)
1131 if (info->apt) apartment_release(info->apt);
1132 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1133 if (info->state) IUnknown_Release(info->state);
1134 if (info->spy) IUnknown_Release(info->spy);
1135 if (info->context_token) IObjContext_Release(info->context_token);
1136 HeapFree(GetProcessHeap(), 0, info);
1137 NtCurrentTeb()->ReservedForOle = NULL;
1141 /******************************************************************************
1142 * CoBuildVersion [OLE32.@]
1144 * Gets the build version of the DLL.
1146 * PARAMS
1148 * RETURNS
1149 * Current build version, hiword is majornumber, loword is minornumber
1151 DWORD WINAPI CoBuildVersion(void)
1153 TRACE("Returning version %d, build %d.\n", rmm, rup);
1154 return (rmm<<16)+rup;
1157 /******************************************************************************
1158 * CoRegisterInitializeSpy [OLE32.@]
1160 * Add a Spy that watches CoInitializeEx calls
1162 * PARAMS
1163 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1164 * cookie [II] cookie receiver
1166 * RETURNS
1167 * Success: S_OK if not already initialized, S_FALSE otherwise.
1168 * Failure: HRESULT code.
1170 * SEE ALSO
1171 * CoInitializeEx
1173 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1175 struct oletls *info = COM_CurrentInfo();
1176 HRESULT hr;
1178 TRACE("(%p, %p)\n", spy, cookie);
1180 if (!spy || !cookie || !info)
1182 if (!info)
1183 WARN("Could not allocate tls\n");
1184 return E_INVALIDARG;
1187 if (info->spy)
1189 FIXME("Already registered?\n");
1190 return E_UNEXPECTED;
1193 hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1194 if (SUCCEEDED(hr))
1196 cookie->QuadPart = (DWORD_PTR)spy;
1197 return S_OK;
1199 return hr;
1202 /******************************************************************************
1203 * CoRevokeInitializeSpy [OLE32.@]
1205 * Remove a spy that previously watched CoInitializeEx calls
1207 * PARAMS
1208 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1210 * RETURNS
1211 * Success: S_OK if a spy is removed
1212 * Failure: E_INVALIDARG
1214 * SEE ALSO
1215 * CoInitializeEx
1217 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1219 struct oletls *info = COM_CurrentInfo();
1220 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1222 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1223 return E_INVALIDARG;
1225 IUnknown_Release(info->spy);
1226 info->spy = NULL;
1227 return S_OK;
1231 /******************************************************************************
1232 * CoInitialize [OLE32.@]
1234 * Initializes the COM libraries by calling CoInitializeEx with
1235 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1237 * PARAMS
1238 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1240 * RETURNS
1241 * Success: S_OK if not already initialized, S_FALSE otherwise.
1242 * Failure: HRESULT code.
1244 * SEE ALSO
1245 * CoInitializeEx
1247 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1250 * Just delegate to the newer method.
1252 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1255 /******************************************************************************
1256 * CoInitializeEx [OLE32.@]
1258 * Initializes the COM libraries.
1260 * PARAMS
1261 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1262 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1264 * RETURNS
1265 * S_OK if successful,
1266 * S_FALSE if this function was called already.
1267 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1268 * threading model.
1270 * NOTES
1272 * The behavior used to set the IMalloc used for memory management is
1273 * obsolete.
1274 * The dwCoInit parameter must specify one of the following apartment
1275 * threading models:
1276 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1277 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1278 * The parameter may also specify zero or more of the following flags:
1279 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1280 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1282 * SEE ALSO
1283 * CoUninitialize
1285 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1287 struct oletls *info = COM_CurrentInfo();
1288 HRESULT hr = S_OK;
1289 APARTMENT *apt;
1291 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1293 if (lpReserved!=NULL)
1295 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1299 * Check the lock count. If this is the first time going through the initialize
1300 * process, we have to initialize the libraries.
1302 * And crank-up that lock count.
1304 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1307 * Initialize the various COM libraries and data structures.
1309 TRACE("() - Initializing the COM libraries\n");
1311 /* we may need to defer this until after apartment initialisation */
1312 RunningObjectTableImpl_Initialize();
1315 if (info->spy)
1316 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1318 if (!(apt = info->apt))
1320 apt = apartment_get_or_create(dwCoInit);
1321 if (!apt) return E_OUTOFMEMORY;
1323 else if (!apartment_is_model(apt, dwCoInit))
1325 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1326 code then we are probably using the wrong threading model to implement that API. */
1327 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1328 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1329 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1330 return RPC_E_CHANGED_MODE;
1332 else
1333 hr = S_FALSE;
1335 info->inits++;
1337 if (info->spy)
1338 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1340 return hr;
1343 /***********************************************************************
1344 * CoUninitialize [OLE32.@]
1346 * This method will decrement the refcount on the current apartment, freeing
1347 * the resources associated with it if it is the last thread in the apartment.
1348 * If the last apartment is freed, the function will additionally release
1349 * any COM resources associated with the process.
1351 * PARAMS
1353 * RETURNS
1354 * Nothing.
1356 * SEE ALSO
1357 * CoInitializeEx
1359 void WINAPI CoUninitialize(void)
1361 struct oletls * info = COM_CurrentInfo();
1362 LONG lCOMRefCnt;
1364 TRACE("()\n");
1366 /* will only happen on OOM */
1367 if (!info) return;
1369 if (info->spy)
1370 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1372 /* sanity check */
1373 if (!info->inits)
1375 ERR("Mismatched CoUninitialize\n");
1377 if (info->spy)
1378 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1379 return;
1382 if (!--info->inits)
1384 apartment_release(info->apt);
1385 info->apt = NULL;
1389 * Decrease the reference count.
1390 * If we are back to 0 locks on the COM library, make sure we free
1391 * all the associated data structures.
1393 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1394 if (lCOMRefCnt==1)
1396 TRACE("() - Releasing the COM libraries\n");
1398 RunningObjectTableImpl_UnInitialize();
1400 else if (lCOMRefCnt<1) {
1401 ERR( "CoUninitialize() - not CoInitialized.\n" );
1402 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1404 if (info->spy)
1405 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1408 /******************************************************************************
1409 * CoDisconnectObject [OLE32.@]
1411 * Disconnects all connections to this object from remote processes. Dispatches
1412 * pending RPCs while blocking new RPCs from occurring, and then calls
1413 * IMarshal::DisconnectObject on the given object.
1415 * Typically called when the object server is forced to shut down, for instance by
1416 * the user.
1418 * PARAMS
1419 * lpUnk [I] The object whose stub should be disconnected.
1420 * reserved [I] Reserved. Should be set to 0.
1422 * RETURNS
1423 * Success: S_OK.
1424 * Failure: HRESULT code.
1426 * SEE ALSO
1427 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1429 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1431 HRESULT hr;
1432 IMarshal *marshal;
1433 APARTMENT *apt;
1435 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1437 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1438 if (hr == S_OK)
1440 hr = IMarshal_DisconnectObject(marshal, reserved);
1441 IMarshal_Release(marshal);
1442 return hr;
1445 apt = COM_CurrentApt();
1446 if (!apt)
1447 return CO_E_NOTINITIALIZED;
1449 apartment_disconnectobject(apt, lpUnk);
1451 /* Note: native is pretty broken here because it just silently
1452 * fails, without returning an appropriate error code if the object was
1453 * not found, making apps think that the object was disconnected, when
1454 * it actually wasn't */
1456 return S_OK;
1459 /******************************************************************************
1460 * CoCreateGuid [OLE32.@]
1462 * Simply forwards to UuidCreate in RPCRT4.
1464 * PARAMS
1465 * pguid [O] Points to the GUID to initialize.
1467 * RETURNS
1468 * Success: S_OK.
1469 * Failure: HRESULT code.
1471 * SEE ALSO
1472 * UuidCreate
1474 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1476 DWORD status = UuidCreate(pguid);
1477 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1478 return HRESULT_FROM_WIN32( status );
1481 /******************************************************************************
1482 * CLSIDFromString [OLE32.@]
1483 * IIDFromString [OLE32.@]
1485 * Converts a unique identifier from its string representation into
1486 * the GUID struct.
1488 * PARAMS
1489 * idstr [I] The string representation of the GUID.
1490 * id [O] GUID converted from the string.
1492 * RETURNS
1493 * S_OK on success
1494 * CO_E_CLASSSTRING if idstr is not a valid CLSID
1496 * SEE ALSO
1497 * StringFromCLSID
1499 static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1501 int i;
1502 BYTE table[256];
1504 if (!s) {
1505 memset( id, 0, sizeof (CLSID) );
1506 return S_OK;
1509 /* validate the CLSID string */
1510 if (strlenW(s) != 38)
1511 return CO_E_CLASSSTRING;
1513 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1514 return CO_E_CLASSSTRING;
1516 for (i=1; i<37; i++) {
1517 if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1518 if (!(((s[i] >= '0') && (s[i] <= '9')) ||
1519 ((s[i] >= 'a') && (s[i] <= 'f')) ||
1520 ((s[i] >= 'A') && (s[i] <= 'F'))))
1521 return CO_E_CLASSSTRING;
1524 TRACE("%s -> %p\n", debugstr_w(s), id);
1526 /* quick lookup table */
1527 memset(table, 0, 256);
1529 for (i = 0; i < 10; i++) {
1530 table['0' + i] = i;
1532 for (i = 0; i < 6; i++) {
1533 table['A' + i] = i+10;
1534 table['a' + i] = i+10;
1537 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1539 id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1540 table[s[5]] << 12 | table[s[6]] << 8 | table[s[7]] << 4 | table[s[8]]);
1541 id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1542 id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1544 /* these are just sequential bytes */
1545 id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1546 id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1547 id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1548 id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1549 id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1550 id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1551 id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1552 id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1554 return S_OK;
1557 /*****************************************************************************/
1559 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1561 HRESULT ret;
1563 if (!id)
1564 return E_INVALIDARG;
1566 ret = __CLSIDFromString(idstr, id);
1567 if(ret != S_OK) { /* It appears a ProgID is also valid */
1568 ret = CLSIDFromProgID(idstr, id);
1570 return ret;
1574 /******************************************************************************
1575 * StringFromCLSID [OLE32.@]
1576 * StringFromIID [OLE32.@]
1578 * Converts a GUID into the respective string representation.
1579 * The target string is allocated using the OLE IMalloc.
1581 * PARAMS
1582 * id [I] the GUID to be converted.
1583 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1585 * RETURNS
1586 * S_OK
1587 * E_FAIL
1589 * SEE ALSO
1590 * StringFromGUID2, CLSIDFromString
1592 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1594 HRESULT ret;
1595 LPMALLOC mllc;
1597 if ((ret = CoGetMalloc(0,&mllc))) return ret;
1598 if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1599 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1600 return S_OK;
1603 /******************************************************************************
1604 * StringFromGUID2 [OLE32.@]
1606 * Modified version of StringFromCLSID that allows you to specify max
1607 * buffer size.
1609 * PARAMS
1610 * id [I] GUID to convert to string.
1611 * str [O] Buffer where the result will be stored.
1612 * cmax [I] Size of the buffer in characters.
1614 * RETURNS
1615 * Success: The length of the resulting string in characters.
1616 * Failure: 0.
1618 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1620 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1621 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1622 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1623 '%','0','2','X','%','0','2','X','}',0 };
1624 if (!id || cmax < CHARS_IN_GUID) return 0;
1625 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1626 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1627 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1628 return CHARS_IN_GUID;
1631 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1632 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1634 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1635 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1636 LONG res;
1637 HKEY key;
1639 strcpyW(path, wszCLSIDSlash);
1640 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1641 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1642 if (res == ERROR_FILE_NOT_FOUND)
1643 return REGDB_E_CLASSNOTREG;
1644 else if (res != ERROR_SUCCESS)
1645 return REGDB_E_READREGDB;
1647 if (!keyname)
1649 *subkey = key;
1650 return S_OK;
1653 res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1654 RegCloseKey(key);
1655 if (res == ERROR_FILE_NOT_FOUND)
1656 return REGDB_E_KEYMISSING;
1657 else if (res != ERROR_SUCCESS)
1658 return REGDB_E_READREGDB;
1660 return S_OK;
1663 /* open HKCR\\AppId\\{string form of appid clsid} key */
1664 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1666 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1667 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1668 DWORD res;
1669 WCHAR buf[CHARS_IN_GUID];
1670 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1671 DWORD size;
1672 HKEY hkey;
1673 DWORD type;
1674 HRESULT hr;
1676 /* read the AppID value under the class's key */
1677 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1678 if (FAILED(hr))
1679 return hr;
1681 size = sizeof(buf);
1682 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1683 RegCloseKey(hkey);
1684 if (res == ERROR_FILE_NOT_FOUND)
1685 return REGDB_E_KEYMISSING;
1686 else if (res != ERROR_SUCCESS || type!=REG_SZ)
1687 return REGDB_E_READREGDB;
1689 strcpyW(keyname, szAppIdKey);
1690 strcatW(keyname, buf);
1691 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1692 if (res == ERROR_FILE_NOT_FOUND)
1693 return REGDB_E_KEYMISSING;
1694 else if (res != ERROR_SUCCESS)
1695 return REGDB_E_READREGDB;
1697 return S_OK;
1700 /******************************************************************************
1701 * ProgIDFromCLSID [OLE32.@]
1703 * Converts a class id into the respective program ID.
1705 * PARAMS
1706 * clsid [I] Class ID, as found in registry.
1707 * ppszProgID [O] Associated ProgID.
1709 * RETURNS
1710 * S_OK
1711 * E_OUTOFMEMORY
1712 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1714 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1716 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1717 HKEY hkey;
1718 HRESULT ret;
1719 LONG progidlen = 0;
1721 if (!ppszProgID)
1723 ERR("ppszProgId isn't optional\n");
1724 return E_INVALIDARG;
1727 *ppszProgID = NULL;
1728 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1729 if (FAILED(ret))
1730 return ret;
1732 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1733 ret = REGDB_E_CLASSNOTREG;
1735 if (ret == S_OK)
1737 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1738 if (*ppszProgID)
1740 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1741 ret = REGDB_E_CLASSNOTREG;
1743 else
1744 ret = E_OUTOFMEMORY;
1747 RegCloseKey(hkey);
1748 return ret;
1751 /******************************************************************************
1752 * CLSIDFromProgID [OLE32.@]
1754 * Converts a program id into the respective GUID.
1756 * PARAMS
1757 * progid [I] Unicode program ID, as found in registry.
1758 * clsid [O] Associated CLSID.
1760 * RETURNS
1761 * Success: S_OK
1762 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1764 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1766 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1767 WCHAR buf2[CHARS_IN_GUID];
1768 LONG buf2len = sizeof(buf2);
1769 HKEY xhkey;
1770 WCHAR *buf;
1772 if (!progid || !clsid)
1774 ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1775 return E_INVALIDARG;
1778 /* initialise clsid in case of failure */
1779 memset(clsid, 0, sizeof(*clsid));
1781 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1782 strcpyW( buf, progid );
1783 strcatW( buf, clsidW );
1784 if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1786 HeapFree(GetProcessHeap(),0,buf);
1787 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1788 return CO_E_CLASSSTRING;
1790 HeapFree(GetProcessHeap(),0,buf);
1792 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1794 RegCloseKey(xhkey);
1795 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1796 return CO_E_CLASSSTRING;
1798 RegCloseKey(xhkey);
1799 return __CLSIDFromString(buf2,clsid);
1803 /*****************************************************************************
1804 * CoGetPSClsid [OLE32.@]
1806 * Retrieves the CLSID of the proxy/stub factory that implements
1807 * IPSFactoryBuffer for the specified interface.
1809 * PARAMS
1810 * riid [I] Interface whose proxy/stub CLSID is to be returned.
1811 * pclsid [O] Where to store returned proxy/stub CLSID.
1813 * RETURNS
1814 * S_OK
1815 * E_OUTOFMEMORY
1816 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1818 * NOTES
1820 * The standard marshaller activates the object with the CLSID
1821 * returned and uses the CreateProxy and CreateStub methods on its
1822 * IPSFactoryBuffer interface to construct the proxies and stubs for a
1823 * given object.
1825 * CoGetPSClsid determines this CLSID by searching the
1826 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1827 * in the registry and any interface id registered by
1828 * CoRegisterPSClsid within the current process.
1830 * BUGS
1832 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1833 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1834 * considered a bug in native unless an application depends on this (unlikely).
1836 * SEE ALSO
1837 * CoRegisterPSClsid.
1839 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1841 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1842 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1843 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1844 WCHAR value[CHARS_IN_GUID];
1845 LONG len;
1846 HKEY hkey;
1847 APARTMENT *apt = COM_CurrentApt();
1848 struct registered_psclsid *registered_psclsid;
1850 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1852 if (!apt)
1854 ERR("apartment not initialised\n");
1855 return CO_E_NOTINITIALIZED;
1858 if (!pclsid)
1860 ERR("pclsid isn't optional\n");
1861 return E_INVALIDARG;
1864 EnterCriticalSection(&apt->cs);
1866 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1867 if (IsEqualIID(&registered_psclsid->iid, riid))
1869 *pclsid = registered_psclsid->clsid;
1870 LeaveCriticalSection(&apt->cs);
1871 return S_OK;
1874 LeaveCriticalSection(&apt->cs);
1876 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1877 strcpyW(path, wszInterface);
1878 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1879 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1881 /* Open the key.. */
1882 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1884 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1885 return REGDB_E_IIDNOTREG;
1888 /* ... Once we have the key, query the registry to get the
1889 value of CLSID as a string, and convert it into a
1890 proper CLSID structure to be passed back to the app */
1891 len = sizeof(value);
1892 if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1894 RegCloseKey(hkey);
1895 return REGDB_E_IIDNOTREG;
1897 RegCloseKey(hkey);
1899 /* We have the CLSID we want back from the registry as a string, so
1900 let's convert it into a CLSID structure */
1901 if (CLSIDFromString(value, pclsid) != NOERROR)
1902 return REGDB_E_IIDNOTREG;
1904 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1905 return S_OK;
1908 /*****************************************************************************
1909 * CoRegisterPSClsid [OLE32.@]
1911 * Register a proxy/stub CLSID for the given interface in the current process
1912 * only.
1914 * PARAMS
1915 * riid [I] Interface whose proxy/stub CLSID is to be registered.
1916 * rclsid [I] CLSID of the proxy/stub.
1918 * RETURNS
1919 * Success: S_OK
1920 * Failure: E_OUTOFMEMORY
1922 * NOTES
1924 * This function does not add anything to the registry and the effects are
1925 * limited to the lifetime of the current process.
1927 * SEE ALSO
1928 * CoGetPSClsid.
1930 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1932 APARTMENT *apt = COM_CurrentApt();
1933 struct registered_psclsid *registered_psclsid;
1935 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1937 if (!apt)
1939 ERR("apartment not initialised\n");
1940 return CO_E_NOTINITIALIZED;
1943 EnterCriticalSection(&apt->cs);
1945 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1946 if (IsEqualIID(&registered_psclsid->iid, riid))
1948 registered_psclsid->clsid = *rclsid;
1949 LeaveCriticalSection(&apt->cs);
1950 return S_OK;
1953 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1954 if (!registered_psclsid)
1956 LeaveCriticalSection(&apt->cs);
1957 return E_OUTOFMEMORY;
1960 registered_psclsid->iid = *riid;
1961 registered_psclsid->clsid = *rclsid;
1962 list_add_head(&apt->psclsids, &registered_psclsid->entry);
1964 LeaveCriticalSection(&apt->cs);
1966 return S_OK;
1970 /***
1971 * COM_GetRegisteredClassObject
1973 * This internal method is used to scan the registered class list to
1974 * find a class object.
1976 * Params:
1977 * rclsid Class ID of the class to find.
1978 * dwClsContext Class context to match.
1979 * ppv [out] returns a pointer to the class object. Complying
1980 * to normal COM usage, this method will increase the
1981 * reference count on this object.
1983 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1984 DWORD dwClsContext, LPUNKNOWN* ppUnk)
1986 HRESULT hr = S_FALSE;
1987 RegisteredClass *curClass;
1989 EnterCriticalSection( &csRegisteredClassList );
1991 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1994 * Check if we have a match on the class ID and context.
1996 if ((apt->oxid == curClass->apartment_id) &&
1997 (dwClsContext & curClass->runContext) &&
1998 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2001 * We have a match, return the pointer to the class object.
2003 *ppUnk = curClass->classObject;
2005 IUnknown_AddRef(curClass->classObject);
2007 hr = S_OK;
2008 break;
2012 LeaveCriticalSection( &csRegisteredClassList );
2014 return hr;
2017 /******************************************************************************
2018 * CoRegisterClassObject [OLE32.@]
2020 * Registers the class object for a given class ID. Servers housed in EXE
2021 * files use this method instead of exporting DllGetClassObject to allow
2022 * other code to connect to their objects.
2024 * PARAMS
2025 * rclsid [I] CLSID of the object to register.
2026 * pUnk [I] IUnknown of the object.
2027 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2028 * flags [I] REGCLS flags indicating how connections are made.
2029 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2031 * RETURNS
2032 * S_OK on success,
2033 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2034 * CO_E_OBJISREG if the object is already registered. We should not return this.
2036 * SEE ALSO
2037 * CoRevokeClassObject, CoGetClassObject
2039 * NOTES
2040 * In-process objects are only registered for the current apartment.
2041 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2042 * in other apartments.
2044 * BUGS
2045 * MSDN claims that multiple interface registrations are legal, but we
2046 * can't do that with our current implementation.
2048 HRESULT WINAPI CoRegisterClassObject(
2049 REFCLSID rclsid,
2050 LPUNKNOWN pUnk,
2051 DWORD dwClsContext,
2052 DWORD flags,
2053 LPDWORD lpdwRegister)
2055 RegisteredClass* newClass;
2056 LPUNKNOWN foundObject;
2057 HRESULT hr;
2058 APARTMENT *apt;
2060 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2061 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2063 if ( (lpdwRegister==0) || (pUnk==0) )
2064 return E_INVALIDARG;
2066 apt = COM_CurrentApt();
2067 if (!apt)
2069 ERR("COM was not initialized\n");
2070 return CO_E_NOTINITIALIZED;
2073 *lpdwRegister = 0;
2075 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2076 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2077 if (flags & REGCLS_MULTIPLEUSE)
2078 dwClsContext |= CLSCTX_INPROC_SERVER;
2081 * First, check if the class is already registered.
2082 * If it is, this should cause an error.
2084 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2085 if (hr == S_OK) {
2086 if (flags & REGCLS_MULTIPLEUSE) {
2087 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2088 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2089 IUnknown_Release(foundObject);
2090 return hr;
2092 IUnknown_Release(foundObject);
2093 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2094 return CO_E_OBJISREG;
2097 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2098 if ( newClass == NULL )
2099 return E_OUTOFMEMORY;
2101 newClass->classIdentifier = *rclsid;
2102 newClass->apartment_id = apt->oxid;
2103 newClass->runContext = dwClsContext;
2104 newClass->connectFlags = flags;
2105 newClass->pMarshaledData = NULL;
2106 newClass->RpcRegistration = NULL;
2109 * Use the address of the chain node as the cookie since we are sure it's
2110 * unique. FIXME: not on 64-bit platforms.
2112 newClass->dwCookie = (DWORD)newClass;
2115 * Since we're making a copy of the object pointer, we have to increase its
2116 * reference count.
2118 newClass->classObject = pUnk;
2119 IUnknown_AddRef(newClass->classObject);
2121 EnterCriticalSection( &csRegisteredClassList );
2122 list_add_tail(&RegisteredClassList, &newClass->entry);
2123 LeaveCriticalSection( &csRegisteredClassList );
2125 *lpdwRegister = newClass->dwCookie;
2127 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2128 hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2129 if (hr) {
2130 FIXME("Failed to create stream on hglobal, %x\n", hr);
2131 return hr;
2133 hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
2134 newClass->classObject, MSHCTX_LOCAL, NULL,
2135 MSHLFLAGS_TABLESTRONG);
2136 if (hr) {
2137 FIXME("CoMarshalInterface failed, %x!\n",hr);
2138 return hr;
2141 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2142 newClass->pMarshaledData,
2143 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2144 &newClass->RpcRegistration);
2146 return S_OK;
2149 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2151 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2152 DWORD keytype;
2153 DWORD ret;
2154 DWORD dwLength = len * sizeof(WCHAR);
2156 ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2157 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2158 value[0] = '\0';
2161 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2162 REFCLSID rclsid, REFIID riid,
2163 BOOL hostifnecessary, void **ppv)
2165 WCHAR dllpath[MAX_PATH+1];
2166 BOOL apartment_threaded;
2168 if (hostifnecessary)
2170 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2171 static const WCHAR wszFree[] = {'F','r','e','e',0};
2172 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2173 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2175 get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2176 /* "Apartment" */
2177 if (!strcmpiW(threading_model, wszApartment))
2179 apartment_threaded = TRUE;
2180 if (apt->multi_threaded)
2181 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2183 /* "Free" */
2184 else if (!strcmpiW(threading_model, wszFree))
2186 apartment_threaded = FALSE;
2187 if (!apt->multi_threaded)
2188 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2190 /* everything except "Apartment", "Free" and "Both" */
2191 else if (strcmpiW(threading_model, wszBoth))
2193 apartment_threaded = TRUE;
2194 /* everything else is main-threaded */
2195 if (threading_model[0])
2196 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2197 debugstr_w(threading_model), debugstr_guid(rclsid));
2199 if (apt->multi_threaded || !apt->main)
2200 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2202 else
2203 apartment_threaded = FALSE;
2205 else
2206 apartment_threaded = !apt->multi_threaded;
2208 if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2210 /* failure: CLSID is not found in registry */
2211 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2212 return REGDB_E_CLASSNOTREG;
2215 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2216 rclsid, riid, ppv);
2219 /***********************************************************************
2220 * CoGetClassObject [OLE32.@]
2222 * Creates an object of the specified class.
2224 * PARAMS
2225 * rclsid [I] Class ID to create an instance of.
2226 * dwClsContext [I] Flags to restrict the location of the created instance.
2227 * pServerInfo [I] Optional. Details for connecting to a remote server.
2228 * iid [I] The ID of the interface of the instance to return.
2229 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2231 * RETURNS
2232 * Success: S_OK
2233 * Failure: HRESULT code.
2235 * NOTES
2236 * The dwClsContext parameter can be one or more of the following:
2237 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2238 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2239 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2240 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2242 * SEE ALSO
2243 * CoCreateInstance()
2245 HRESULT WINAPI CoGetClassObject(
2246 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2247 REFIID iid, LPVOID *ppv)
2249 LPUNKNOWN regClassObject;
2250 HRESULT hres = E_UNEXPECTED;
2251 APARTMENT *apt;
2252 BOOL release_apt = FALSE;
2254 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2256 if (!ppv)
2257 return E_INVALIDARG;
2259 *ppv = NULL;
2261 if (!(apt = COM_CurrentApt()))
2263 if (!(apt = apartment_find_multi_threaded()))
2265 ERR("apartment not initialised\n");
2266 return CO_E_NOTINITIALIZED;
2268 release_apt = TRUE;
2271 if (pServerInfo) {
2272 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2273 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2277 * First, try and see if we can't match the class ID with one of the
2278 * registered classes.
2280 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2281 &regClassObject))
2283 /* Get the required interface from the retrieved pointer. */
2284 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2287 * Since QI got another reference on the pointer, we want to release the
2288 * one we already have. If QI was unsuccessful, this will release the object. This
2289 * is good since we are not returning it in the "out" parameter.
2291 IUnknown_Release(regClassObject);
2292 if (release_apt) apartment_release(apt);
2293 return hres;
2296 /* First try in-process server */
2297 if (CLSCTX_INPROC_SERVER & dwClsContext)
2299 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2300 HKEY hkey;
2302 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2304 if (release_apt) apartment_release(apt);
2305 return FTMarshalCF_Create(iid, ppv);
2308 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2309 if (FAILED(hres))
2311 if (hres == REGDB_E_CLASSNOTREG)
2312 ERR("class %s not registered\n", debugstr_guid(rclsid));
2313 else if (hres == REGDB_E_KEYMISSING)
2315 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2316 hres = REGDB_E_CLASSNOTREG;
2320 if (SUCCEEDED(hres))
2322 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2323 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2324 RegCloseKey(hkey);
2327 /* return if we got a class, otherwise fall through to one of the
2328 * other types */
2329 if (SUCCEEDED(hres))
2331 if (release_apt) apartment_release(apt);
2332 return hres;
2336 /* Next try in-process handler */
2337 if (CLSCTX_INPROC_HANDLER & dwClsContext)
2339 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2340 HKEY hkey;
2342 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2343 if (FAILED(hres))
2345 if (hres == REGDB_E_CLASSNOTREG)
2346 ERR("class %s not registered\n", debugstr_guid(rclsid));
2347 else if (hres == REGDB_E_KEYMISSING)
2349 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2350 hres = REGDB_E_CLASSNOTREG;
2354 if (SUCCEEDED(hres))
2356 hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2357 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2358 RegCloseKey(hkey);
2361 /* return if we got a class, otherwise fall through to one of the
2362 * other types */
2363 if (SUCCEEDED(hres))
2365 if (release_apt) apartment_release(apt);
2366 return hres;
2369 if (release_apt) apartment_release(apt);
2371 /* Next try out of process */
2372 if (CLSCTX_LOCAL_SERVER & dwClsContext)
2374 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2375 if (SUCCEEDED(hres))
2376 return hres;
2379 /* Finally try remote: this requires networked DCOM (a lot of work) */
2380 if (CLSCTX_REMOTE_SERVER & dwClsContext)
2382 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2383 hres = E_NOINTERFACE;
2386 if (FAILED(hres))
2387 ERR("no class object %s could be created for context 0x%x\n",
2388 debugstr_guid(rclsid), dwClsContext);
2389 return hres;
2392 /***********************************************************************
2393 * CoResumeClassObjects (OLE32.@)
2395 * Resumes all class objects registered with REGCLS_SUSPENDED.
2397 * RETURNS
2398 * Success: S_OK.
2399 * Failure: HRESULT code.
2401 HRESULT WINAPI CoResumeClassObjects(void)
2403 FIXME("stub\n");
2404 return S_OK;
2407 /***********************************************************************
2408 * CoCreateInstance [OLE32.@]
2410 * Creates an instance of the specified class.
2412 * PARAMS
2413 * rclsid [I] Class ID to create an instance of.
2414 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
2415 * dwClsContext [I] Flags to restrict the location of the created instance.
2416 * iid [I] The ID of the interface of the instance to return.
2417 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
2419 * RETURNS
2420 * Success: S_OK
2421 * Failure: HRESULT code.
2423 * NOTES
2424 * The dwClsContext parameter can be one or more of the following:
2425 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2426 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2427 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2428 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2430 * Aggregation is the concept of deferring the IUnknown of an object to another
2431 * object. This allows a separate object to behave as though it was part of
2432 * the object and to allow this the pUnkOuter parameter can be set. Note that
2433 * not all objects support having an outer of unknown.
2435 * SEE ALSO
2436 * CoGetClassObject()
2438 HRESULT WINAPI CoCreateInstance(
2439 REFCLSID rclsid,
2440 LPUNKNOWN pUnkOuter,
2441 DWORD dwClsContext,
2442 REFIID iid,
2443 LPVOID *ppv)
2445 HRESULT hres;
2446 LPCLASSFACTORY lpclf = 0;
2447 APARTMENT *apt;
2449 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2450 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2453 * Sanity check
2455 if (ppv==0)
2456 return E_POINTER;
2459 * Initialize the "out" parameter
2461 *ppv = 0;
2463 if (!(apt = COM_CurrentApt()))
2465 if (!(apt = apartment_find_multi_threaded()))
2467 ERR("apartment not initialised\n");
2468 return CO_E_NOTINITIALIZED;
2470 apartment_release(apt);
2474 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2475 * Rather than create a class factory, we can just check for it here
2477 if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2478 if (StdGlobalInterfaceTableInstance == NULL)
2479 StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2480 hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2481 if (hres) return hres;
2483 TRACE("Retrieved GIT (%p)\n", *ppv);
2484 return S_OK;
2488 * Get a class factory to construct the object we want.
2490 hres = CoGetClassObject(rclsid,
2491 dwClsContext,
2492 NULL,
2493 &IID_IClassFactory,
2494 (LPVOID)&lpclf);
2496 if (FAILED(hres))
2497 return hres;
2500 * Create the object and don't forget to release the factory
2502 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2503 IClassFactory_Release(lpclf);
2504 if(FAILED(hres))
2506 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2507 FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2508 else
2509 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2512 return hres;
2515 /***********************************************************************
2516 * CoCreateInstanceEx [OLE32.@]
2518 HRESULT WINAPI CoCreateInstanceEx(
2519 REFCLSID rclsid,
2520 LPUNKNOWN pUnkOuter,
2521 DWORD dwClsContext,
2522 COSERVERINFO* pServerInfo,
2523 ULONG cmq,
2524 MULTI_QI* pResults)
2526 IUnknown* pUnk = NULL;
2527 HRESULT hr;
2528 ULONG index;
2529 ULONG successCount = 0;
2532 * Sanity check
2534 if ( (cmq==0) || (pResults==NULL))
2535 return E_INVALIDARG;
2537 if (pServerInfo!=NULL)
2538 FIXME("() non-NULL pServerInfo not supported!\n");
2541 * Initialize all the "out" parameters.
2543 for (index = 0; index < cmq; index++)
2545 pResults[index].pItf = NULL;
2546 pResults[index].hr = E_NOINTERFACE;
2550 * Get the object and get its IUnknown pointer.
2552 hr = CoCreateInstance(rclsid,
2553 pUnkOuter,
2554 dwClsContext,
2555 &IID_IUnknown,
2556 (VOID**)&pUnk);
2558 if (hr)
2559 return hr;
2562 * Then, query for all the interfaces requested.
2564 for (index = 0; index < cmq; index++)
2566 pResults[index].hr = IUnknown_QueryInterface(pUnk,
2567 pResults[index].pIID,
2568 (VOID**)&(pResults[index].pItf));
2570 if (pResults[index].hr == S_OK)
2571 successCount++;
2575 * Release our temporary unknown pointer.
2577 IUnknown_Release(pUnk);
2579 if (successCount == 0)
2580 return E_NOINTERFACE;
2582 if (successCount!=cmq)
2583 return CO_S_NOTALLINTERFACES;
2585 return S_OK;
2588 /***********************************************************************
2589 * CoLoadLibrary (OLE32.@)
2591 * Loads a library.
2593 * PARAMS
2594 * lpszLibName [I] Path to library.
2595 * bAutoFree [I] Whether the library should automatically be freed.
2597 * RETURNS
2598 * Success: Handle to loaded library.
2599 * Failure: NULL.
2601 * SEE ALSO
2602 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2604 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2606 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2608 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2611 /***********************************************************************
2612 * CoFreeLibrary [OLE32.@]
2614 * Unloads a library from memory.
2616 * PARAMS
2617 * hLibrary [I] Handle to library to unload.
2619 * RETURNS
2620 * Nothing
2622 * SEE ALSO
2623 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2625 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2627 FreeLibrary(hLibrary);
2631 /***********************************************************************
2632 * CoFreeAllLibraries [OLE32.@]
2634 * Function for backwards compatibility only. Does nothing.
2636 * RETURNS
2637 * Nothing.
2639 * SEE ALSO
2640 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2642 void WINAPI CoFreeAllLibraries(void)
2644 /* NOP */
2647 /***********************************************************************
2648 * CoFreeUnusedLibrariesEx [OLE32.@]
2650 * Frees any previously unused libraries whose delay has expired and marks
2651 * currently unused libraries for unloading. Unused are identified as those that
2652 * return S_OK from their DllCanUnloadNow function.
2654 * PARAMS
2655 * dwUnloadDelay [I] Unload delay in milliseconds.
2656 * dwReserved [I] Reserved. Set to 0.
2658 * RETURNS
2659 * Nothing.
2661 * SEE ALSO
2662 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2664 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2666 struct apartment *apt = COM_CurrentApt();
2667 if (!apt)
2669 ERR("apartment not initialised\n");
2670 return;
2673 apartment_freeunusedlibraries(apt, dwUnloadDelay);
2676 /***********************************************************************
2677 * CoFreeUnusedLibraries [OLE32.@]
2679 * Frees any unused libraries. Unused are identified as those that return
2680 * S_OK from their DllCanUnloadNow function.
2682 * RETURNS
2683 * Nothing.
2685 * SEE ALSO
2686 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2688 void WINAPI CoFreeUnusedLibraries(void)
2690 CoFreeUnusedLibrariesEx(INFINITE, 0);
2693 /***********************************************************************
2694 * CoFileTimeNow [OLE32.@]
2696 * Retrieves the current time in FILETIME format.
2698 * PARAMS
2699 * lpFileTime [O] The current time.
2701 * RETURNS
2702 * S_OK.
2704 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2706 GetSystemTimeAsFileTime( lpFileTime );
2707 return S_OK;
2710 /******************************************************************************
2711 * CoLockObjectExternal [OLE32.@]
2713 * Increments or decrements the external reference count of a stub object.
2715 * PARAMS
2716 * pUnk [I] Stub object.
2717 * fLock [I] If TRUE then increments the external ref-count,
2718 * otherwise decrements.
2719 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2720 * calling CoDisconnectObject.
2722 * RETURNS
2723 * Success: S_OK.
2724 * Failure: HRESULT code.
2726 * NOTES
2727 * If fLock is TRUE and an object is passed in that doesn't have a stub
2728 * manager then a new stub manager is created for the object.
2730 HRESULT WINAPI CoLockObjectExternal(
2731 LPUNKNOWN pUnk,
2732 BOOL fLock,
2733 BOOL fLastUnlockReleases)
2735 struct stub_manager *stubmgr;
2736 struct apartment *apt;
2738 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2739 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2741 apt = COM_CurrentApt();
2742 if (!apt) return CO_E_NOTINITIALIZED;
2744 stubmgr = get_stub_manager_from_object(apt, pUnk);
2746 if (stubmgr)
2748 if (fLock)
2749 stub_manager_ext_addref(stubmgr, 1, FALSE);
2750 else
2751 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2753 stub_manager_int_release(stubmgr);
2755 return S_OK;
2757 else if (fLock)
2759 stubmgr = new_stub_manager(apt, pUnk);
2761 if (stubmgr)
2763 stub_manager_ext_addref(stubmgr, 1, FALSE);
2764 stub_manager_int_release(stubmgr);
2767 return S_OK;
2769 else
2771 WARN("stub object not found %p\n", pUnk);
2772 /* Note: native is pretty broken here because it just silently
2773 * fails, without returning an appropriate error code, making apps
2774 * think that the object was disconnected, when it actually wasn't */
2775 return S_OK;
2779 /***********************************************************************
2780 * CoInitializeWOW (OLE32.@)
2782 * WOW equivalent of CoInitialize?
2784 * PARAMS
2785 * x [I] Unknown.
2786 * y [I] Unknown.
2788 * RETURNS
2789 * Unknown.
2791 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2793 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2794 return 0;
2797 /***********************************************************************
2798 * CoGetState [OLE32.@]
2800 * Retrieves the thread state object previously stored by CoSetState().
2802 * PARAMS
2803 * ppv [I] Address where pointer to object will be stored.
2805 * RETURNS
2806 * Success: S_OK.
2807 * Failure: E_OUTOFMEMORY.
2809 * NOTES
2810 * Crashes on all invalid ppv addresses, including NULL.
2811 * If the function returns a non-NULL object then the caller must release its
2812 * reference on the object when the object is no longer required.
2814 * SEE ALSO
2815 * CoSetState().
2817 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2819 struct oletls *info = COM_CurrentInfo();
2820 if (!info) return E_OUTOFMEMORY;
2822 *ppv = NULL;
2824 if (info->state)
2826 IUnknown_AddRef(info->state);
2827 *ppv = info->state;
2828 TRACE("apt->state=%p\n", info->state);
2831 return S_OK;
2834 /***********************************************************************
2835 * CoSetState [OLE32.@]
2837 * Sets the thread state object.
2839 * PARAMS
2840 * pv [I] Pointer to state object to be stored.
2842 * NOTES
2843 * The system keeps a reference on the object while the object stored.
2845 * RETURNS
2846 * Success: S_OK.
2847 * Failure: E_OUTOFMEMORY.
2849 HRESULT WINAPI CoSetState(IUnknown * pv)
2851 struct oletls *info = COM_CurrentInfo();
2852 if (!info) return E_OUTOFMEMORY;
2854 if (pv) IUnknown_AddRef(pv);
2856 if (info->state)
2858 TRACE("-- release %p now\n", info->state);
2859 IUnknown_Release(info->state);
2862 info->state = pv;
2864 return S_OK;
2868 /******************************************************************************
2869 * CoTreatAsClass [OLE32.@]
2871 * Sets the TreatAs value of a class.
2873 * PARAMS
2874 * clsidOld [I] Class to set TreatAs value on.
2875 * clsidNew [I] The class the clsidOld should be treated as.
2877 * RETURNS
2878 * Success: S_OK.
2879 * Failure: HRESULT code.
2881 * SEE ALSO
2882 * CoGetTreatAsClass
2884 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2886 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2887 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2888 HKEY hkey = NULL;
2889 WCHAR szClsidNew[CHARS_IN_GUID];
2890 HRESULT res = S_OK;
2891 WCHAR auto_treat_as[CHARS_IN_GUID];
2892 LONG auto_treat_as_size = sizeof(auto_treat_as);
2893 CLSID id;
2895 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2896 if (FAILED(res))
2897 goto done;
2898 if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2900 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2901 CLSIDFromString(auto_treat_as, &id) == S_OK)
2903 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2905 res = REGDB_E_WRITEREGDB;
2906 goto done;
2909 else
2911 RegDeleteKeyW(hkey, wszTreatAs);
2912 goto done;
2915 else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2916 !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2918 res = REGDB_E_WRITEREGDB;
2919 goto done;
2922 done:
2923 if (hkey) RegCloseKey(hkey);
2924 return res;
2927 /******************************************************************************
2928 * CoGetTreatAsClass [OLE32.@]
2930 * Gets the TreatAs value of a class.
2932 * PARAMS
2933 * clsidOld [I] Class to get the TreatAs value of.
2934 * clsidNew [I] The class the clsidOld should be treated as.
2936 * RETURNS
2937 * Success: S_OK.
2938 * Failure: HRESULT code.
2940 * SEE ALSO
2941 * CoSetTreatAsClass
2943 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2945 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2946 HKEY hkey = NULL;
2947 WCHAR szClsidNew[CHARS_IN_GUID];
2948 HRESULT res = S_OK;
2949 LONG len = sizeof(szClsidNew);
2951 FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2952 *clsidNew = *clsidOld; /* copy over old value */
2954 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2955 if (FAILED(res))
2957 res = S_FALSE;
2958 goto done;
2960 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2962 res = S_FALSE;
2963 goto done;
2965 res = CLSIDFromString(szClsidNew,clsidNew);
2966 if (FAILED(res))
2967 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2968 done:
2969 if (hkey) RegCloseKey(hkey);
2970 return res;
2973 /******************************************************************************
2974 * CoGetCurrentProcess [OLE32.@]
2976 * Gets the current process ID.
2978 * RETURNS
2979 * The current process ID.
2981 * NOTES
2982 * Is DWORD really the correct return type for this function?
2984 DWORD WINAPI CoGetCurrentProcess(void)
2986 return GetCurrentProcessId();
2989 /******************************************************************************
2990 * CoRegisterMessageFilter [OLE32.@]
2992 * Registers a message filter.
2994 * PARAMS
2995 * lpMessageFilter [I] Pointer to interface.
2996 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2998 * RETURNS
2999 * Success: S_OK.
3000 * Failure: HRESULT code.
3002 * NOTES
3003 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3004 * lpMessageFilter removes the message filter.
3006 * If lplpMessageFilter is not NULL the previous message filter will be
3007 * returned in the memory pointer to this parameter and the caller is
3008 * responsible for releasing the object.
3010 * The current thread be in an apartment otherwise the function will crash.
3012 HRESULT WINAPI CoRegisterMessageFilter(
3013 LPMESSAGEFILTER lpMessageFilter,
3014 LPMESSAGEFILTER *lplpMessageFilter)
3016 struct apartment *apt;
3017 IMessageFilter *lpOldMessageFilter;
3019 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3021 apt = COM_CurrentApt();
3023 /* can't set a message filter in a multi-threaded apartment */
3024 if (!apt || apt->multi_threaded)
3026 WARN("can't set message filter in MTA or uninitialized apt\n");
3027 return CO_E_NOT_SUPPORTED;
3030 if (lpMessageFilter)
3031 IMessageFilter_AddRef(lpMessageFilter);
3033 EnterCriticalSection(&apt->cs);
3035 lpOldMessageFilter = apt->filter;
3036 apt->filter = lpMessageFilter;
3038 LeaveCriticalSection(&apt->cs);
3040 if (lplpMessageFilter)
3041 *lplpMessageFilter = lpOldMessageFilter;
3042 else if (lpOldMessageFilter)
3043 IMessageFilter_Release(lpOldMessageFilter);
3045 return S_OK;
3048 /***********************************************************************
3049 * CoIsOle1Class [OLE32.@]
3051 * Determines whether the specified class an OLE v1 class.
3053 * PARAMS
3054 * clsid [I] Class to test.
3056 * RETURNS
3057 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3059 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3061 FIXME("%s\n", debugstr_guid(clsid));
3062 return FALSE;
3065 /***********************************************************************
3066 * IsEqualGUID [OLE32.@]
3068 * Compares two Unique Identifiers.
3070 * PARAMS
3071 * rguid1 [I] The first GUID to compare.
3072 * rguid2 [I] The other GUID to compare.
3074 * RETURNS
3075 * TRUE if equal
3077 #undef IsEqualGUID
3078 BOOL WINAPI IsEqualGUID(
3079 REFGUID rguid1,
3080 REFGUID rguid2)
3082 return !memcmp(rguid1,rguid2,sizeof(GUID));
3085 /***********************************************************************
3086 * CoInitializeSecurity [OLE32.@]
3088 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3089 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3090 void* pReserved1, DWORD dwAuthnLevel,
3091 DWORD dwImpLevel, void* pReserved2,
3092 DWORD dwCapabilities, void* pReserved3)
3094 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3095 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3096 dwCapabilities, pReserved3);
3097 return S_OK;
3100 /***********************************************************************
3101 * CoSuspendClassObjects [OLE32.@]
3103 * Suspends all registered class objects to prevent further requests coming in
3104 * for those objects.
3106 * RETURNS
3107 * Success: S_OK.
3108 * Failure: HRESULT code.
3110 HRESULT WINAPI CoSuspendClassObjects(void)
3112 FIXME("\n");
3113 return S_OK;
3116 /***********************************************************************
3117 * CoAddRefServerProcess [OLE32.@]
3119 * Helper function for incrementing the reference count of a local-server
3120 * process.
3122 * RETURNS
3123 * New reference count.
3125 * SEE ALSO
3126 * CoReleaseServerProcess().
3128 ULONG WINAPI CoAddRefServerProcess(void)
3130 ULONG refs;
3132 TRACE("\n");
3134 EnterCriticalSection(&csRegisteredClassList);
3135 refs = ++s_COMServerProcessReferences;
3136 LeaveCriticalSection(&csRegisteredClassList);
3138 TRACE("refs before: %d\n", refs - 1);
3140 return refs;
3143 /***********************************************************************
3144 * CoReleaseServerProcess [OLE32.@]
3146 * Helper function for decrementing the reference count of a local-server
3147 * process.
3149 * RETURNS
3150 * New reference count.
3152 * NOTES
3153 * When reference count reaches 0, this function suspends all registered
3154 * classes so no new connections are accepted.
3156 * SEE ALSO
3157 * CoAddRefServerProcess(), CoSuspendClassObjects().
3159 ULONG WINAPI CoReleaseServerProcess(void)
3161 ULONG refs;
3163 TRACE("\n");
3165 EnterCriticalSection(&csRegisteredClassList);
3167 refs = --s_COMServerProcessReferences;
3168 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3170 LeaveCriticalSection(&csRegisteredClassList);
3172 TRACE("refs after: %d\n", refs);
3174 return refs;
3177 /***********************************************************************
3178 * CoIsHandlerConnected [OLE32.@]
3180 * Determines whether a proxy is connected to a remote stub.
3182 * PARAMS
3183 * pUnk [I] Pointer to object that may or may not be connected.
3185 * RETURNS
3186 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3187 * FALSE otherwise.
3189 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3191 FIXME("%p\n", pUnk);
3193 return TRUE;
3196 /***********************************************************************
3197 * CoAllowSetForegroundWindow [OLE32.@]
3200 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3202 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3203 return S_OK;
3206 /***********************************************************************
3207 * CoQueryProxyBlanket [OLE32.@]
3209 * Retrieves the security settings being used by a proxy.
3211 * PARAMS
3212 * pProxy [I] Pointer to the proxy object.
3213 * pAuthnSvc [O] The type of authentication service.
3214 * pAuthzSvc [O] The type of authorization service.
3215 * ppServerPrincName [O] Optional. The server prinicple name.
3216 * pAuthnLevel [O] The authentication level.
3217 * pImpLevel [O] The impersonation level.
3218 * ppAuthInfo [O] Information specific to the authorization/authentication service.
3219 * pCapabilities [O] Flags affecting the security behaviour.
3221 * RETURNS
3222 * Success: S_OK.
3223 * Failure: HRESULT code.
3225 * SEE ALSO
3226 * CoCopyProxy, CoSetProxyBlanket.
3228 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3229 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3230 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3232 IClientSecurity *pCliSec;
3233 HRESULT hr;
3235 TRACE("%p\n", pProxy);
3237 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3238 if (SUCCEEDED(hr))
3240 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3241 pAuthzSvc, ppServerPrincName,
3242 pAuthnLevel, pImpLevel, ppAuthInfo,
3243 pCapabilities);
3244 IClientSecurity_Release(pCliSec);
3247 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3248 return hr;
3251 /***********************************************************************
3252 * CoSetProxyBlanket [OLE32.@]
3254 * Sets the security settings for a proxy.
3256 * PARAMS
3257 * pProxy [I] Pointer to the proxy object.
3258 * AuthnSvc [I] The type of authentication service.
3259 * AuthzSvc [I] The type of authorization service.
3260 * pServerPrincName [I] The server prinicple name.
3261 * AuthnLevel [I] The authentication level.
3262 * ImpLevel [I] The impersonation level.
3263 * pAuthInfo [I] Information specific to the authorization/authentication service.
3264 * Capabilities [I] Flags affecting the security behaviour.
3266 * RETURNS
3267 * Success: S_OK.
3268 * Failure: HRESULT code.
3270 * SEE ALSO
3271 * CoQueryProxyBlanket, CoCopyProxy.
3273 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3274 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3275 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3277 IClientSecurity *pCliSec;
3278 HRESULT hr;
3280 TRACE("%p\n", pProxy);
3282 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3283 if (SUCCEEDED(hr))
3285 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3286 AuthzSvc, pServerPrincName,
3287 AuthnLevel, ImpLevel, pAuthInfo,
3288 Capabilities);
3289 IClientSecurity_Release(pCliSec);
3292 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3293 return hr;
3296 /***********************************************************************
3297 * CoCopyProxy [OLE32.@]
3299 * Copies a proxy.
3301 * PARAMS
3302 * pProxy [I] Pointer to the proxy object.
3303 * ppCopy [O] Copy of the proxy.
3305 * RETURNS
3306 * Success: S_OK.
3307 * Failure: HRESULT code.
3309 * SEE ALSO
3310 * CoQueryProxyBlanket, CoSetProxyBlanket.
3312 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3314 IClientSecurity *pCliSec;
3315 HRESULT hr;
3317 TRACE("%p\n", pProxy);
3319 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3320 if (SUCCEEDED(hr))
3322 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3323 IClientSecurity_Release(pCliSec);
3326 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3327 return hr;
3331 /***********************************************************************
3332 * CoGetCallContext [OLE32.@]
3334 * Gets the context of the currently executing server call in the current
3335 * thread.
3337 * PARAMS
3338 * riid [I] Context interface to return.
3339 * ppv [O] Pointer to memory that will receive the context on return.
3341 * RETURNS
3342 * Success: S_OK.
3343 * Failure: HRESULT code.
3345 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3347 struct oletls *info = COM_CurrentInfo();
3349 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3351 if (!info)
3352 return E_OUTOFMEMORY;
3354 if (!info->call_state)
3355 return RPC_E_CALL_COMPLETE;
3357 return IUnknown_QueryInterface(info->call_state, riid, ppv);
3360 /***********************************************************************
3361 * CoSwitchCallContext [OLE32.@]
3363 * Switches the context of the currently executing server call in the current
3364 * thread.
3366 * PARAMS
3367 * pObject [I] Pointer to new context object
3368 * ppOldObject [O] Pointer to memory that will receive old context object pointer
3370 * RETURNS
3371 * Success: S_OK.
3372 * Failure: HRESULT code.
3374 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
3376 struct oletls *info = COM_CurrentInfo();
3378 TRACE("(%p, %p)\n", pObject, ppOldObject);
3380 if (!info)
3381 return E_OUTOFMEMORY;
3383 *ppOldObject = info->call_state;
3384 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
3386 return S_OK;
3389 /***********************************************************************
3390 * CoQueryClientBlanket [OLE32.@]
3392 * Retrieves the authentication information about the client of the currently
3393 * executing server call in the current thread.
3395 * PARAMS
3396 * pAuthnSvc [O] Optional. The type of authentication service.
3397 * pAuthzSvc [O] Optional. The type of authorization service.
3398 * pServerPrincName [O] Optional. The server prinicple name.
3399 * pAuthnLevel [O] Optional. The authentication level.
3400 * pImpLevel [O] Optional. The impersonation level.
3401 * pPrivs [O] Optional. Information about the privileges of the client.
3402 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
3404 * RETURNS
3405 * Success: S_OK.
3406 * Failure: HRESULT code.
3408 * SEE ALSO
3409 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3411 HRESULT WINAPI CoQueryClientBlanket(
3412 DWORD *pAuthnSvc,
3413 DWORD *pAuthzSvc,
3414 OLECHAR **pServerPrincName,
3415 DWORD *pAuthnLevel,
3416 DWORD *pImpLevel,
3417 RPC_AUTHZ_HANDLE *pPrivs,
3418 DWORD *pCapabilities)
3420 IServerSecurity *pSrvSec;
3421 HRESULT hr;
3423 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3424 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3425 pPrivs, pCapabilities);
3427 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3428 if (SUCCEEDED(hr))
3430 hr = IServerSecurity_QueryBlanket(
3431 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3432 pImpLevel, pPrivs, pCapabilities);
3433 IServerSecurity_Release(pSrvSec);
3436 return hr;
3439 /***********************************************************************
3440 * CoImpersonateClient [OLE32.@]
3442 * Impersonates the client of the currently executing server call in the
3443 * current thread.
3445 * PARAMS
3446 * None.
3448 * RETURNS
3449 * Success: S_OK.
3450 * Failure: HRESULT code.
3452 * NOTES
3453 * If this function fails then the current thread will not be impersonating
3454 * the client and all actions will take place on behalf of the server.
3455 * Therefore, it is important to check the return value from this function.
3457 * SEE ALSO
3458 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3460 HRESULT WINAPI CoImpersonateClient(void)
3462 IServerSecurity *pSrvSec;
3463 HRESULT hr;
3465 TRACE("\n");
3467 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3468 if (SUCCEEDED(hr))
3470 hr = IServerSecurity_ImpersonateClient(pSrvSec);
3471 IServerSecurity_Release(pSrvSec);
3474 return hr;
3477 /***********************************************************************
3478 * CoRevertToSelf [OLE32.@]
3480 * Ends the impersonation of the client of the currently executing server
3481 * call in the current thread.
3483 * PARAMS
3484 * None.
3486 * RETURNS
3487 * Success: S_OK.
3488 * Failure: HRESULT code.
3490 * SEE ALSO
3491 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3493 HRESULT WINAPI CoRevertToSelf(void)
3495 IServerSecurity *pSrvSec;
3496 HRESULT hr;
3498 TRACE("\n");
3500 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3501 if (SUCCEEDED(hr))
3503 hr = IServerSecurity_RevertToSelf(pSrvSec);
3504 IServerSecurity_Release(pSrvSec);
3507 return hr;
3510 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3512 /* first try to retrieve messages for incoming COM calls to the apartment window */
3513 return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3514 /* next retrieve other messages necessary for the app to remain responsive */
3515 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
3516 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
3519 /***********************************************************************
3520 * CoWaitForMultipleHandles [OLE32.@]
3522 * Waits for one or more handles to become signaled.
3524 * PARAMS
3525 * dwFlags [I] Flags. See notes.
3526 * dwTimeout [I] Timeout in milliseconds.
3527 * cHandles [I] Number of handles pointed to by pHandles.
3528 * pHandles [I] Handles to wait for.
3529 * lpdwindex [O] Index of handle that was signaled.
3531 * RETURNS
3532 * Success: S_OK.
3533 * Failure: RPC_S_CALLPENDING on timeout.
3535 * NOTES
3537 * The dwFlags parameter can be zero or more of the following:
3538 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3539 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3541 * SEE ALSO
3542 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
3544 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3545 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3547 HRESULT hr = S_OK;
3548 DWORD start_time = GetTickCount();
3549 APARTMENT *apt = COM_CurrentApt();
3550 BOOL message_loop = apt && !apt->multi_threaded;
3552 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3553 pHandles, lpdwindex);
3555 while (TRUE)
3557 DWORD now = GetTickCount();
3558 DWORD res;
3560 if (now - start_time > dwTimeout)
3562 hr = RPC_S_CALLPENDING;
3563 break;
3566 if (message_loop)
3568 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3569 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3571 TRACE("waiting for rpc completion or window message\n");
3573 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3574 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3575 QS_ALLINPUT, wait_flags);
3577 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
3579 MSG msg;
3581 /* call message filter */
3583 if (COM_CurrentApt()->filter)
3585 PENDINGTYPE pendingtype =
3586 COM_CurrentInfo()->pending_call_count_server ?
3587 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3588 DWORD be_handled = IMessageFilter_MessagePending(
3589 COM_CurrentApt()->filter, 0 /* FIXME */,
3590 now - start_time, pendingtype);
3591 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3592 switch (be_handled)
3594 case PENDINGMSG_CANCELCALL:
3595 WARN("call canceled\n");
3596 hr = RPC_E_CALL_CANCELED;
3597 break;
3598 case PENDINGMSG_WAITNOPROCESS:
3599 case PENDINGMSG_WAITDEFPROCESS:
3600 default:
3601 /* FIXME: MSDN is very vague about the difference
3602 * between WAITNOPROCESS and WAITDEFPROCESS - there
3603 * appears to be none, so it is possibly a left-over
3604 * from the 16-bit world. */
3605 break;
3609 /* note: using "if" here instead of "while" might seem less
3610 * efficient, but only if we are optimising for quick delivery
3611 * of pending messages, rather than quick completion of the
3612 * COM call */
3613 if (COM_PeekMessage(apt, &msg))
3615 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3616 TranslateMessage(&msg);
3617 DispatchMessageW(&msg);
3618 if (msg.message == WM_QUIT)
3620 TRACE("resending WM_QUIT to outer message loop\n");
3621 PostQuitMessage(msg.wParam);
3622 /* no longer need to process messages */
3623 message_loop = FALSE;
3626 continue;
3629 else
3631 TRACE("waiting for rpc completion\n");
3633 res = WaitForMultipleObjectsEx(cHandles, pHandles,
3634 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3635 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3636 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3639 if (res < WAIT_OBJECT_0 + cHandles)
3641 /* handle signaled, store index */
3642 *lpdwindex = (res - WAIT_OBJECT_0);
3643 break;
3645 else if (res == WAIT_TIMEOUT)
3647 hr = RPC_S_CALLPENDING;
3648 break;
3650 else
3652 ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3653 hr = E_UNEXPECTED;
3654 break;
3657 TRACE("-- 0x%08x\n", hr);
3658 return hr;
3662 /***********************************************************************
3663 * CoGetObject [OLE32.@]
3665 * Gets the object named by converting the name to a moniker and binding to it.
3667 * PARAMS
3668 * pszName [I] String representing the object.
3669 * pBindOptions [I] Parameters affecting the binding to the named object.
3670 * riid [I] Interface to bind to on the objecct.
3671 * ppv [O] On output, the interface riid of the object represented
3672 * by pszName.
3674 * RETURNS
3675 * Success: S_OK.
3676 * Failure: HRESULT code.
3678 * SEE ALSO
3679 * MkParseDisplayName.
3681 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3682 REFIID riid, void **ppv)
3684 IBindCtx *pbc;
3685 HRESULT hr;
3687 *ppv = NULL;
3689 hr = CreateBindCtx(0, &pbc);
3690 if (SUCCEEDED(hr))
3692 if (pBindOptions)
3693 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3695 if (SUCCEEDED(hr))
3697 ULONG chEaten;
3698 IMoniker *pmk;
3700 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3701 if (SUCCEEDED(hr))
3703 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3704 IMoniker_Release(pmk);
3708 IBindCtx_Release(pbc);
3710 return hr;
3713 /***********************************************************************
3714 * CoRegisterChannelHook [OLE32.@]
3716 * Registers a process-wide hook that is called during ORPC calls.
3718 * PARAMS
3719 * guidExtension [I] GUID of the channel hook to register.
3720 * pChannelHook [I] Channel hook object to register.
3722 * RETURNS
3723 * Success: S_OK.
3724 * Failure: HRESULT code.
3726 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3728 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3730 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3733 typedef struct Context
3735 const IComThreadingInfoVtbl *lpVtbl;
3736 const IContextCallbackVtbl *lpCallbackVtbl;
3737 const IObjContextVtbl *lpContextVtbl;
3738 LONG refs;
3739 APTTYPE apttype;
3740 } Context;
3742 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3744 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpVtbl));
3747 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3749 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl));
3752 static inline Context *impl_from_IObjContext( IObjContext *iface )
3754 return (Context *)((char*)iface - FIELD_OFFSET(Context, lpContextVtbl));
3757 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3759 *ppv = NULL;
3761 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3762 IsEqualIID(riid, &IID_IUnknown))
3764 *ppv = &iface->lpVtbl;
3766 else if (IsEqualIID(riid, &IID_IContextCallback))
3768 *ppv = &iface->lpCallbackVtbl;
3770 else if (IsEqualIID(riid, &IID_IObjContext))
3772 *ppv = &iface->lpContextVtbl;
3775 if (*ppv)
3777 IUnknown_AddRef((IUnknown*)*ppv);
3778 return S_OK;
3781 FIXME("interface not implemented %s\n", debugstr_guid(riid));
3782 return E_NOINTERFACE;
3785 static ULONG Context_AddRef(Context *This)
3787 return InterlockedIncrement(&This->refs);
3790 static ULONG Context_Release(Context *This)
3792 ULONG refs = InterlockedDecrement(&This->refs);
3793 if (!refs)
3794 HeapFree(GetProcessHeap(), 0, This);
3795 return refs;
3798 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3800 Context *This = impl_from_IComThreadingInfo(iface);
3801 return Context_QueryInterface(This, riid, ppv);
3804 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3806 Context *This = impl_from_IComThreadingInfo(iface);
3807 return Context_AddRef(This);
3810 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3812 Context *This = impl_from_IComThreadingInfo(iface);
3813 return Context_Release(This);
3816 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3818 Context *This = impl_from_IComThreadingInfo(iface);
3820 TRACE("(%p)\n", apttype);
3822 *apttype = This->apttype;
3823 return S_OK;
3826 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3828 Context *This = impl_from_IComThreadingInfo(iface);
3830 TRACE("(%p)\n", thdtype);
3832 switch (This->apttype)
3834 case APTTYPE_STA:
3835 case APTTYPE_MAINSTA:
3836 *thdtype = THDTYPE_PROCESSMESSAGES;
3837 break;
3838 default:
3839 *thdtype = THDTYPE_BLOCKMESSAGES;
3840 break;
3842 return S_OK;
3845 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3847 FIXME("(%p): stub\n", logical_thread_id);
3848 return E_NOTIMPL;
3851 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3853 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3854 return E_NOTIMPL;
3857 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3859 Context_CTI_QueryInterface,
3860 Context_CTI_AddRef,
3861 Context_CTI_Release,
3862 Context_CTI_GetCurrentApartmentType,
3863 Context_CTI_GetCurrentThreadType,
3864 Context_CTI_GetCurrentLogicalThreadId,
3865 Context_CTI_SetCurrentLogicalThreadId
3868 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
3870 Context *This = impl_from_IContextCallback(iface);
3871 return Context_QueryInterface(This, riid, ppv);
3874 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
3876 Context *This = impl_from_IContextCallback(iface);
3877 return Context_AddRef(This);
3880 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
3882 Context *This = impl_from_IContextCallback(iface);
3883 return Context_Release(This);
3886 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
3887 ComCallData *param, REFIID riid, int method, IUnknown *punk)
3889 Context *This = impl_from_IContextCallback(iface);
3891 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
3892 return E_NOTIMPL;
3895 static const IContextCallbackVtbl Context_Callback_Vtbl =
3897 Context_CC_QueryInterface,
3898 Context_CC_AddRef,
3899 Context_CC_Release,
3900 Context_CC_ContextCallback
3903 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
3905 Context *This = impl_from_IObjContext(iface);
3906 return Context_QueryInterface(This, riid, ppv);
3909 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
3911 Context *This = impl_from_IObjContext(iface);
3912 return Context_AddRef(This);
3915 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
3917 Context *This = impl_from_IObjContext(iface);
3918 return Context_Release(This);
3921 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
3923 Context *This = impl_from_IObjContext(iface);
3925 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3926 return E_NOTIMPL;
3929 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
3931 Context *This = impl_from_IObjContext(iface);
3933 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
3934 return E_NOTIMPL;
3937 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
3939 Context *This = impl_from_IObjContext(iface);
3941 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3942 return E_NOTIMPL;
3945 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
3947 Context *This = impl_from_IObjContext(iface);
3949 FIXME("(%p/%p)->(%p)\n", This, iface, props);
3950 return E_NOTIMPL;
3953 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
3955 Context *This = impl_from_IObjContext(iface);
3956 FIXME("(%p/%p)\n", This, iface);
3959 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
3961 Context *This = impl_from_IObjContext(iface);
3962 FIXME("(%p/%p)\n", This, iface);
3965 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
3967 Context *This = impl_from_IObjContext(iface);
3968 FIXME("(%p/%p)\n", This, iface);
3971 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
3973 Context *This = impl_from_IObjContext(iface);
3974 FIXME("(%p/%p)\n", This, iface);
3977 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
3979 Context *This = impl_from_IObjContext(iface);
3980 FIXME("(%p/%p)\n", This, iface);
3983 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
3985 Context *This = impl_from_IObjContext(iface);
3986 FIXME("(%p/%p)\n", This, iface);
3989 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
3991 Context *This = impl_from_IObjContext(iface);
3992 FIXME("(%p/%p)\n", This, iface);
3995 static const IObjContextVtbl Context_Object_Vtbl =
3997 Context_OC_QueryInterface,
3998 Context_OC_AddRef,
3999 Context_OC_Release,
4000 Context_OC_SetProperty,
4001 Context_OC_RemoveProperty,
4002 Context_OC_GetProperty,
4003 Context_OC_EnumContextProps,
4004 Context_OC_Reserved1,
4005 Context_OC_Reserved2,
4006 Context_OC_Reserved3,
4007 Context_OC_Reserved4,
4008 Context_OC_Reserved5,
4009 Context_OC_Reserved6,
4010 Context_OC_Reserved7
4013 /***********************************************************************
4014 * CoGetObjectContext [OLE32.@]
4016 * Retrieves an object associated with the current context (i.e. apartment).
4018 * PARAMS
4019 * riid [I] ID of the interface of the object to retrieve.
4020 * ppv [O] Address where object will be stored on return.
4022 * RETURNS
4023 * Success: S_OK.
4024 * Failure: HRESULT code.
4026 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4028 APARTMENT *apt = COM_CurrentApt();
4029 Context *context;
4030 HRESULT hr;
4032 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4034 *ppv = NULL;
4035 if (!apt)
4037 if (!(apt = apartment_find_multi_threaded()))
4039 ERR("apartment not initialised\n");
4040 return CO_E_NOTINITIALIZED;
4042 apartment_release(apt);
4045 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4046 if (!context)
4047 return E_OUTOFMEMORY;
4049 context->lpVtbl = &Context_Threading_Vtbl;
4050 context->lpCallbackVtbl = &Context_Callback_Vtbl;
4051 context->lpContextVtbl = &Context_Object_Vtbl;
4052 context->refs = 1;
4053 if (apt->multi_threaded)
4054 context->apttype = APTTYPE_MTA;
4055 else if (apt->main)
4056 context->apttype = APTTYPE_MAINSTA;
4057 else
4058 context->apttype = APTTYPE_STA;
4060 hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
4061 IUnknown_Release((IUnknown *)&context->lpVtbl);
4063 return hr;
4067 /***********************************************************************
4068 * CoGetContextToken [OLE32.@]
4070 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4072 struct oletls *info = COM_CurrentInfo();
4074 TRACE("(%p)\n", token);
4076 if (!info)
4077 return E_OUTOFMEMORY;
4079 if (!info->apt)
4081 APARTMENT *apt;
4082 if (!(apt = apartment_find_multi_threaded()))
4084 ERR("apartment not initialised\n");
4085 return CO_E_NOTINITIALIZED;
4087 apartment_release(apt);
4090 if (!token)
4091 return E_POINTER;
4093 if (!info->context_token)
4095 HRESULT hr;
4096 IObjContext *ctx;
4098 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4099 if (FAILED(hr)) return hr;
4100 info->context_token = ctx;
4103 *token = (ULONG_PTR)info->context_token;
4104 TRACE("apt->context_token=%p\n", info->context_token);
4106 return S_OK;
4110 /***********************************************************************
4111 * DllMain (OLE32.@)
4113 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4115 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4117 switch(fdwReason) {
4118 case DLL_PROCESS_ATTACH:
4119 hProxyDll = hinstDLL;
4120 COMPOBJ_InitProcess();
4121 if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
4122 break;
4124 case DLL_PROCESS_DETACH:
4125 if (TRACE_ON(ole)) CoRevokeMallocSpy();
4126 OLEDD_UnInitialize();
4127 COMPOBJ_UninitProcess();
4128 RPC_UnregisterAllChannelHooks();
4129 COMPOBJ_DllList_Free();
4130 break;
4132 case DLL_THREAD_DETACH:
4133 COM_TlsDestroy();
4134 break;
4136 return TRUE;
4139 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */