ole32: Lock spies list when iterating it.
[wine.git] / dlls / ole32 / compobj.c
blobc5a36059b9282df9b5064343015e380da810504d
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 <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <assert.h>
44 #define COBJMACROS
45 #define NONAMELESSUNION
47 #include "ntstatus.h"
48 #define WIN32_NO_STATUS
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winerror.h"
52 #include "winreg.h"
53 #include "winuser.h"
54 #define USE_COM_CONTEXT_DEF
55 #include "objbase.h"
56 #include "ole2.h"
57 #include "ole2ver.h"
58 #include "ctxtcall.h"
59 #include "dde.h"
60 #include "servprov.h"
62 #include "initguid.h"
63 #include "compobj_private.h"
64 #include "moniker.h"
66 #include "wine/debug.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(ole);
70 /****************************************************************************
71 * This section defines variables internal to the COM module.
74 static APARTMENT *MTA; /* protected by csApartment */
75 static APARTMENT *MainApartment; /* the first STA apartment */
76 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
78 static CRITICAL_SECTION csApartment;
79 static CRITICAL_SECTION_DEBUG critsect_debug =
81 0, 0, &csApartment,
82 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
83 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
85 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
87 enum comclass_threadingmodel
89 ThreadingModel_Apartment = 1,
90 ThreadingModel_Free = 2,
91 ThreadingModel_No = 3,
92 ThreadingModel_Both = 4,
93 ThreadingModel_Neutral = 5
96 enum comclass_miscfields
98 MiscStatus = 1,
99 MiscStatusIcon = 2,
100 MiscStatusContent = 4,
101 MiscStatusThumbnail = 8,
102 MiscStatusDocPrint = 16
105 struct comclassredirect_data
107 ULONG size;
108 BYTE res;
109 BYTE miscmask;
110 BYTE res1[2];
111 DWORD model;
112 GUID clsid;
113 GUID alias;
114 GUID clsid2;
115 GUID tlbid;
116 ULONG name_len;
117 ULONG name_offset;
118 ULONG progid_len;
119 ULONG progid_offset;
120 ULONG clrdata_len;
121 ULONG clrdata_offset;
122 DWORD miscstatus;
123 DWORD miscstatuscontent;
124 DWORD miscstatusthumbnail;
125 DWORD miscstatusicon;
126 DWORD miscstatusdocprint;
129 struct ifacepsredirect_data
131 ULONG size;
132 DWORD mask;
133 GUID iid;
134 ULONG nummethods;
135 GUID tlbid;
136 GUID base;
137 ULONG name_len;
138 ULONG name_offset;
141 struct progidredirect_data
143 ULONG size;
144 DWORD reserved;
145 ULONG clsid_offset;
148 struct class_reg_data
150 union
152 struct
154 struct comclassredirect_data *data;
155 void *section;
156 HANDLE hactctx;
157 } actctx;
158 HKEY hkey;
159 } u;
160 BOOL hkey;
163 struct registered_psclsid
165 struct list entry;
166 IID iid;
167 CLSID clsid;
170 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list);
172 static CRITICAL_SECTION cs_registered_psclsid_list;
173 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
175 0, 0, &cs_registered_psclsid_list,
176 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
177 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
179 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
182 * This is a marshallable object exposing registered local servers.
183 * IServiceProvider is used only because it happens meet requirements
184 * and already has proxy/stub code. If more functionality is needed,
185 * a custom interface may be used instead.
187 struct LocalServer
189 IServiceProvider IServiceProvider_iface;
190 LONG ref;
191 APARTMENT *apt;
192 IStream *marshal_stream;
196 * This lock count counts the number of times CoInitialize is called. It is
197 * decreased every time CoUninitialize is called. When it hits 0, the COM
198 * libraries are freed
200 static LONG s_COMLockCount = 0;
201 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
202 static LONG s_COMServerProcessReferences = 0;
205 * This linked list contains the list of registered class objects. These
206 * are mostly used to register the factories for out-of-proc servers of OLE
207 * objects.
209 * TODO: Make this data structure aware of inter-process communication. This
210 * means that parts of this will be exported to rpcss.
212 typedef struct tagRegisteredClass
214 struct list entry;
215 CLSID classIdentifier;
216 OXID apartment_id;
217 LPUNKNOWN classObject;
218 DWORD runContext;
219 DWORD connectFlags;
220 DWORD dwCookie;
221 void *RpcRegistration;
222 } RegisteredClass;
224 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
226 static CRITICAL_SECTION csRegisteredClassList;
227 static CRITICAL_SECTION_DEBUG class_cs_debug =
229 0, 0, &csRegisteredClassList,
230 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
231 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
233 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
235 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
237 switch (aspect)
239 case DVASPECT_CONTENT:
240 return MiscStatusContent;
241 case DVASPECT_THUMBNAIL:
242 return MiscStatusThumbnail;
243 case DVASPECT_ICON:
244 return MiscStatusIcon;
245 case DVASPECT_DOCPRINT:
246 return MiscStatusDocPrint;
247 default:
248 return MiscStatus;
252 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
254 ACTCTX_SECTION_KEYED_DATA data;
256 data.cbSize = sizeof(data);
257 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
258 clsid, &data))
260 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
261 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
263 if (!(comclass->miscmask & misc))
265 if (!(comclass->miscmask & MiscStatus))
267 *status = 0;
268 return TRUE;
270 misc = MiscStatus;
273 switch (misc)
275 case MiscStatus:
276 *status = comclass->miscstatus;
277 break;
278 case MiscStatusIcon:
279 *status = comclass->miscstatusicon;
280 break;
281 case MiscStatusContent:
282 *status = comclass->miscstatuscontent;
283 break;
284 case MiscStatusThumbnail:
285 *status = comclass->miscstatusthumbnail;
286 break;
287 case MiscStatusDocPrint:
288 *status = comclass->miscstatusdocprint;
289 break;
290 default:
294 return TRUE;
296 else
297 return FALSE;
300 /* wrapper for NtCreateKey that creates the key recursively if necessary */
301 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
303 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
305 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
307 HANDLE subkey, root = attr->RootDirectory;
308 WCHAR *buffer = attr->ObjectName->Buffer;
309 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
310 UNICODE_STRING str;
312 while (i < len && buffer[i] != '\\') i++;
313 if (i == len) return status;
315 attrs = attr->Attributes;
316 attr->ObjectName = &str;
318 while (i < len)
320 str.Buffer = buffer + pos;
321 str.Length = (i - pos) * sizeof(WCHAR);
322 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
323 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
324 if (status) return status;
325 attr->RootDirectory = subkey;
326 while (i < len && buffer[i] == '\\') i++;
327 pos = i;
328 while (i < len && buffer[i] != '\\') i++;
330 str.Buffer = buffer + pos;
331 str.Length = (i - pos) * sizeof(WCHAR);
332 attr->Attributes = attrs;
333 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
334 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
336 return status;
339 static const WCHAR classes_rootW[] =
340 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
341 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
343 static HKEY classes_root_hkey;
345 /* create the special HKEY_CLASSES_ROOT key */
346 static HKEY create_classes_root_hkey(DWORD access)
348 HKEY hkey, ret = 0;
349 OBJECT_ATTRIBUTES attr;
350 UNICODE_STRING name;
352 attr.Length = sizeof(attr);
353 attr.RootDirectory = 0;
354 attr.ObjectName = &name;
355 attr.Attributes = 0;
356 attr.SecurityDescriptor = NULL;
357 attr.SecurityQualityOfService = NULL;
358 RtlInitUnicodeString( &name, classes_rootW );
359 if (create_key( &hkey, access, &attr )) return 0;
360 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
362 if (!(access & KEY_WOW64_64KEY))
364 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
365 ret = hkey;
366 else
367 NtClose( hkey ); /* somebody beat us to it */
369 else
370 ret = hkey;
371 return ret;
374 /* map the hkey from special root to normal key if necessary */
375 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
377 HKEY ret = hkey;
378 const BOOL is_win64 = sizeof(void*) > sizeof(int);
379 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
381 if (hkey == HKEY_CLASSES_ROOT &&
382 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
383 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
384 if (force_wow32 && ret && ret == classes_root_hkey)
386 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
387 access &= ~KEY_WOW64_32KEY;
388 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
389 return 0;
390 ret = hkey;
393 return ret;
396 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
398 OBJECT_ATTRIBUTES attr;
399 UNICODE_STRING nameW;
401 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
403 attr.Length = sizeof(attr);
404 attr.RootDirectory = hkey;
405 attr.ObjectName = &nameW;
406 attr.Attributes = 0;
407 attr.SecurityDescriptor = NULL;
408 attr.SecurityQualityOfService = NULL;
409 RtlInitUnicodeString( &nameW, name );
411 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
414 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
416 OBJECT_ATTRIBUTES attr;
417 UNICODE_STRING nameW;
419 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
421 attr.Length = sizeof(attr);
422 attr.RootDirectory = hkey;
423 attr.ObjectName = &nameW;
424 attr.Attributes = 0;
425 attr.SecurityDescriptor = NULL;
426 attr.SecurityQualityOfService = NULL;
427 RtlInitUnicodeString( &nameW, name );
429 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
432 /*****************************************************************************
433 * This section contains OpenDllList definitions
435 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
436 * other functions that do LoadLibrary _without_ giving back a HMODULE.
437 * Without this list these handles would never be freed.
439 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
440 * next unload-call but not before 600 sec.
443 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
444 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
446 typedef struct tagOpenDll
448 LONG refs;
449 LPWSTR library_name;
450 HANDLE library;
451 DllGetClassObjectFunc DllGetClassObject;
452 DllCanUnloadNowFunc DllCanUnloadNow;
453 struct list entry;
454 } OpenDll;
456 static struct list openDllList = LIST_INIT(openDllList);
458 static CRITICAL_SECTION csOpenDllList;
459 static CRITICAL_SECTION_DEBUG dll_cs_debug =
461 0, 0, &csOpenDllList,
462 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
463 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
465 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
467 struct apartment_loaded_dll
469 struct list entry;
470 OpenDll *dll;
471 DWORD unload_time;
472 BOOL multi_threaded;
475 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',0};
477 static ATOM apt_win_class;
479 /*****************************************************************************
480 * This section contains OpenDllList implementation
483 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
485 OpenDll *ptr;
486 OpenDll *ret = NULL;
487 EnterCriticalSection(&csOpenDllList);
488 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
490 if (!wcsicmp(library_name, ptr->library_name) &&
491 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
493 ret = ptr;
494 break;
497 LeaveCriticalSection(&csOpenDllList);
498 return ret;
501 /* caller must ensure that library_name is not already in the open dll list */
502 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
504 OpenDll *entry;
505 int len;
506 HRESULT hr = S_OK;
507 HANDLE hLibrary;
508 DllCanUnloadNowFunc DllCanUnloadNow;
509 DllGetClassObjectFunc DllGetClassObject;
511 TRACE("%s\n", debugstr_w(library_name));
513 *ret = COMPOBJ_DllList_Get(library_name);
514 if (*ret) return S_OK;
516 /* do this outside the csOpenDllList to avoid creating a lock dependency on
517 * the loader lock */
518 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
519 if (!hLibrary)
521 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
522 /* failure: DLL could not be loaded */
523 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
526 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
527 /* Note: failing to find DllCanUnloadNow is not a failure */
528 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
529 if (!DllGetClassObject)
531 /* failure: the dll did not export DllGetClassObject */
532 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
533 FreeLibrary(hLibrary);
534 return CO_E_DLLNOTFOUND;
537 EnterCriticalSection( &csOpenDllList );
539 *ret = COMPOBJ_DllList_Get(library_name);
540 if (*ret)
542 /* another caller to this function already added the dll while we
543 * weren't in the critical section */
544 FreeLibrary(hLibrary);
546 else
548 len = lstrlenW(library_name);
549 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
550 if (entry)
551 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
552 if (entry && entry->library_name)
554 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
555 entry->library = hLibrary;
556 entry->refs = 1;
557 entry->DllCanUnloadNow = DllCanUnloadNow;
558 entry->DllGetClassObject = DllGetClassObject;
559 list_add_tail(&openDllList, &entry->entry);
560 *ret = entry;
562 else
564 HeapFree(GetProcessHeap(), 0, entry);
565 hr = E_OUTOFMEMORY;
566 FreeLibrary(hLibrary);
570 LeaveCriticalSection( &csOpenDllList );
572 return hr;
575 /* pass FALSE for free_entry to release a reference without destroying the
576 * entry if it reaches zero or TRUE otherwise */
577 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
579 if (!InterlockedDecrement(&entry->refs) && free_entry)
581 EnterCriticalSection(&csOpenDllList);
582 list_remove(&entry->entry);
583 LeaveCriticalSection(&csOpenDllList);
585 TRACE("freeing %p\n", entry->library);
586 FreeLibrary(entry->library);
588 HeapFree(GetProcessHeap(), 0, entry->library_name);
589 HeapFree(GetProcessHeap(), 0, entry);
593 /* frees memory associated with active dll list */
594 static void COMPOBJ_DllList_Free(void)
596 OpenDll *entry, *cursor2;
597 EnterCriticalSection(&csOpenDllList);
598 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
600 list_remove(&entry->entry);
602 HeapFree(GetProcessHeap(), 0, entry->library_name);
603 HeapFree(GetProcessHeap(), 0, entry);
605 LeaveCriticalSection(&csOpenDllList);
606 DeleteCriticalSection(&csOpenDllList);
609 /******************************************************************************
610 * Manage apartments.
613 static DWORD apartment_addref(struct apartment *apt)
615 DWORD refs = InterlockedIncrement(&apt->refs);
616 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
617 return refs;
620 /* allocates memory and fills in the necessary fields for a new apartment
621 * object. must be called inside apartment cs */
622 static APARTMENT *apartment_construct(DWORD model)
624 APARTMENT *apt;
626 TRACE("creating new apartment, model=%d\n", model);
628 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
629 apt->tid = GetCurrentThreadId();
631 list_init(&apt->proxies);
632 list_init(&apt->stubmgrs);
633 list_init(&apt->loaded_dlls);
634 apt->ipidc = 0;
635 apt->refs = 1;
636 apt->remunk_exported = FALSE;
637 apt->oidc = 1;
638 InitializeCriticalSection(&apt->cs);
639 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
641 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
643 if (apt->multi_threaded)
645 /* FIXME: should be randomly generated by in an RPC call to rpcss */
646 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
648 else
650 /* FIXME: should be randomly generated by in an RPC call to rpcss */
651 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
654 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
656 list_add_head(&apts, &apt->entry);
658 return apt;
661 /* gets and existing apartment if one exists or otherwise creates an apartment
662 * structure which stores OLE apartment-local information and stores a pointer
663 * to it in the thread-local storage */
664 static APARTMENT *apartment_get_or_create(DWORD model)
666 APARTMENT *apt = COM_CurrentApt();
668 if (!apt)
670 if (model & COINIT_APARTMENTTHREADED)
672 EnterCriticalSection(&csApartment);
674 apt = apartment_construct(model);
675 if (!MainApartment)
677 MainApartment = apt;
678 apt->main = TRUE;
679 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
682 LeaveCriticalSection(&csApartment);
684 if (apt->main)
685 apartment_createwindowifneeded(apt);
687 else
689 EnterCriticalSection(&csApartment);
691 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
692 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
693 * in a process */
694 if (MTA)
696 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
697 apartment_addref(MTA);
699 else
700 MTA = apartment_construct(model);
702 apt = MTA;
704 LeaveCriticalSection(&csApartment);
706 COM_CurrentInfo()->apt = apt;
709 return apt;
712 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
714 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
717 /* gets the multi-threaded apartment if it exists. The caller must
718 * release the reference from the apartment as soon as the apartment pointer
719 * is no longer required. */
720 static APARTMENT *apartment_find_mta(void)
722 APARTMENT *apt;
724 EnterCriticalSection(&csApartment);
726 if ((apt = MTA))
727 apartment_addref(apt);
729 LeaveCriticalSection(&csApartment);
731 return apt;
734 /* Return the current apartment if it exists, or, failing that, the MTA. Caller
735 * must free the returned apartment in either case. */
736 APARTMENT *apartment_get_current_or_mta(void)
738 APARTMENT *apt = COM_CurrentApt();
739 if (apt)
741 apartment_addref(apt);
742 return apt;
744 return apartment_find_mta();
747 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
749 list_remove(&curClass->entry);
751 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
752 RPC_StopLocalServer(curClass->RpcRegistration);
754 IUnknown_Release(curClass->classObject);
755 HeapFree(GetProcessHeap(), 0, curClass);
758 static void COM_RevokeAllClasses(const struct apartment *apt)
760 RegisteredClass *curClass, *cursor;
762 EnterCriticalSection( &csRegisteredClassList );
764 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
766 if (curClass->apartment_id == apt->oxid)
767 COM_RevokeRegisteredClassObject(curClass);
770 LeaveCriticalSection( &csRegisteredClassList );
773 static void revoke_registered_psclsids(void)
775 struct registered_psclsid *psclsid, *psclsid2;
777 EnterCriticalSection( &cs_registered_psclsid_list );
779 LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, &registered_psclsid_list, struct registered_psclsid, entry)
781 list_remove(&psclsid->entry);
782 HeapFree(GetProcessHeap(), 0, psclsid);
785 LeaveCriticalSection( &cs_registered_psclsid_list );
788 /******************************************************************************
789 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
792 typedef struct ManualResetEvent {
793 ISynchronize ISynchronize_iface;
794 ISynchronizeHandle ISynchronizeHandle_iface;
795 LONG ref;
796 HANDLE event;
797 } MREImpl;
799 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
801 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
804 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
806 MREImpl *This = impl_from_ISynchronize(iface);
808 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
810 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
811 *ppv = &This->ISynchronize_iface;
812 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
813 *ppv = &This->ISynchronizeHandle_iface;
814 }else {
815 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
816 *ppv = NULL;
817 return E_NOINTERFACE;
820 IUnknown_AddRef((IUnknown*)*ppv);
821 return S_OK;
824 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
826 MREImpl *This = impl_from_ISynchronize(iface);
827 LONG ref = InterlockedIncrement(&This->ref);
828 TRACE("%p - ref %d\n", This, ref);
830 return ref;
833 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
835 MREImpl *This = impl_from_ISynchronize(iface);
836 LONG ref = InterlockedDecrement(&This->ref);
837 TRACE("%p - ref %d\n", This, ref);
839 if(!ref)
841 CloseHandle(This->event);
842 HeapFree(GetProcessHeap(), 0, This);
845 return ref;
848 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
850 MREImpl *This = impl_from_ISynchronize(iface);
851 UINT index;
852 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
853 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
856 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
858 MREImpl *This = impl_from_ISynchronize(iface);
859 TRACE("%p\n", This);
860 SetEvent(This->event);
861 return S_OK;
864 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
866 MREImpl *This = impl_from_ISynchronize(iface);
867 TRACE("%p\n", This);
868 ResetEvent(This->event);
869 return S_OK;
872 static ISynchronizeVtbl vt_ISynchronize = {
873 ISynchronize_fnQueryInterface,
874 ISynchronize_fnAddRef,
875 ISynchronize_fnRelease,
876 ISynchronize_fnWait,
877 ISynchronize_fnSignal,
878 ISynchronize_fnReset
881 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
883 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
886 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
888 MREImpl *This = impl_from_ISynchronizeHandle(iface);
889 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
892 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
894 MREImpl *This = impl_from_ISynchronizeHandle(iface);
895 return ISynchronize_AddRef(&This->ISynchronize_iface);
898 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
900 MREImpl *This = impl_from_ISynchronizeHandle(iface);
901 return ISynchronize_Release(&This->ISynchronize_iface);
904 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
906 MREImpl *This = impl_from_ISynchronizeHandle(iface);
908 *ph = This->event;
909 return S_OK;
912 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
913 SynchronizeHandle_QueryInterface,
914 SynchronizeHandle_AddRef,
915 SynchronizeHandle_Release,
916 SynchronizeHandle_GetHandle
919 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
921 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
922 HRESULT hr;
924 if(punkouter)
925 FIXME("Aggregation not implemented.\n");
927 This->ref = 1;
928 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
929 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
930 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
932 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
933 ISynchronize_Release(&This->ISynchronize_iface);
934 return hr;
937 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
939 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
942 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
944 LocalServer *This = impl_from_IServiceProvider(iface);
946 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
948 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
949 *ppv = &This->IServiceProvider_iface;
950 }else {
951 *ppv = NULL;
952 return E_NOINTERFACE;
955 IUnknown_AddRef((IUnknown*)*ppv);
956 return S_OK;
959 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
961 LocalServer *This = impl_from_IServiceProvider(iface);
962 LONG ref = InterlockedIncrement(&This->ref);
964 TRACE("(%p) ref=%d\n", This, ref);
966 return ref;
969 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
971 LocalServer *This = impl_from_IServiceProvider(iface);
972 LONG ref = InterlockedDecrement(&This->ref);
974 TRACE("(%p) ref=%d\n", This, ref);
976 if(!ref) {
977 assert(!This->apt);
978 HeapFree(GetProcessHeap(), 0, This);
981 return ref;
984 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
986 LocalServer *This = impl_from_IServiceProvider(iface);
987 APARTMENT *apt = COM_CurrentApt();
988 RegisteredClass *iter;
989 HRESULT hres = E_FAIL;
991 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
993 if(!This->apt)
994 return E_UNEXPECTED;
996 EnterCriticalSection(&csRegisteredClassList);
998 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
999 if(iter->apartment_id == apt->oxid
1000 && (iter->runContext & CLSCTX_LOCAL_SERVER)
1001 && IsEqualGUID(&iter->classIdentifier, guid)) {
1002 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
1003 break;
1007 LeaveCriticalSection( &csRegisteredClassList );
1009 return hres;
1012 static const IServiceProviderVtbl LocalServerVtbl = {
1013 LocalServer_QueryInterface,
1014 LocalServer_AddRef,
1015 LocalServer_Release,
1016 LocalServer_QueryService
1019 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
1021 HRESULT hres = S_OK;
1023 EnterCriticalSection(&apt->cs);
1025 if(!apt->local_server) {
1026 LocalServer *obj;
1028 obj = heap_alloc(sizeof(*obj));
1029 if(obj) {
1030 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
1031 obj->ref = 1;
1032 obj->apt = apt;
1034 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
1035 if(SUCCEEDED(hres)) {
1036 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
1037 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1038 if(FAILED(hres))
1039 IStream_Release(obj->marshal_stream);
1042 if(SUCCEEDED(hres))
1043 apt->local_server = obj;
1044 else
1045 heap_free(obj);
1046 }else {
1047 hres = E_OUTOFMEMORY;
1051 if(SUCCEEDED(hres))
1052 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1054 LeaveCriticalSection(&apt->cs);
1056 if(FAILED(hres))
1057 ERR("Failed: %08x\n", hres);
1058 return hres;
1061 /***********************************************************************
1062 * CoRevokeClassObject [OLE32.@]
1064 * Removes a class object from the class registry.
1066 * PARAMS
1067 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1069 * RETURNS
1070 * Success: S_OK.
1071 * Failure: HRESULT code.
1073 * NOTES
1074 * Must be called from the same apartment that called CoRegisterClassObject(),
1075 * otherwise it will fail with RPC_E_WRONG_THREAD.
1077 * SEE ALSO
1078 * CoRegisterClassObject
1080 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
1081 DWORD dwRegister)
1083 HRESULT hr = E_INVALIDARG;
1084 RegisteredClass *curClass;
1085 APARTMENT *apt;
1087 TRACE("(%08x)\n",dwRegister);
1089 if (!(apt = apartment_get_current_or_mta()))
1091 ERR("COM was not initialized\n");
1092 return CO_E_NOTINITIALIZED;
1095 EnterCriticalSection( &csRegisteredClassList );
1097 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1100 * Check if we have a match on the cookie.
1102 if (curClass->dwCookie == dwRegister)
1104 if (curClass->apartment_id == apt->oxid)
1106 COM_RevokeRegisteredClassObject(curClass);
1107 hr = S_OK;
1109 else
1111 ERR("called from wrong apartment, should be called from %s\n",
1112 wine_dbgstr_longlong(curClass->apartment_id));
1113 hr = RPC_E_WRONG_THREAD;
1115 break;
1119 LeaveCriticalSection( &csRegisteredClassList );
1120 apartment_release(apt);
1121 return hr;
1124 /* frees unused libraries loaded by apartment_getclassobject by calling the
1125 * DLL's DllCanUnloadNow entry point */
1126 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1128 struct apartment_loaded_dll *entry, *next;
1129 EnterCriticalSection(&apt->cs);
1130 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1132 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1134 DWORD real_delay = delay;
1136 if (real_delay == INFINITE)
1138 /* DLLs that return multi-threaded objects aren't unloaded
1139 * straight away to cope for programs that have races between
1140 * last object destruction and threads in the DLLs that haven't
1141 * finished, despite DllCanUnloadNow returning S_OK */
1142 if (entry->multi_threaded)
1143 real_delay = 10 * 60 * 1000; /* 10 minutes */
1144 else
1145 real_delay = 0;
1148 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1150 list_remove(&entry->entry);
1151 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1152 HeapFree(GetProcessHeap(), 0, entry);
1154 else
1156 entry->unload_time = GetTickCount() + real_delay;
1157 if (!entry->unload_time) entry->unload_time = 1;
1160 else if (entry->unload_time)
1161 entry->unload_time = 0;
1163 LeaveCriticalSection(&apt->cs);
1166 DWORD apartment_release(struct apartment *apt)
1168 DWORD ret;
1170 EnterCriticalSection(&csApartment);
1172 ret = InterlockedDecrement(&apt->refs);
1173 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1175 if (apt->being_destroyed)
1177 LeaveCriticalSection(&csApartment);
1178 return ret;
1181 /* destruction stuff that needs to happen under csApartment CS */
1182 if (ret == 0)
1184 apt->being_destroyed = TRUE;
1185 if (apt == MTA) MTA = NULL;
1186 else if (apt == MainApartment) MainApartment = NULL;
1187 list_remove(&apt->entry);
1190 LeaveCriticalSection(&csApartment);
1192 if (ret == 0)
1194 struct list *cursor, *cursor2;
1196 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1198 if(apt->local_server) {
1199 LocalServer *local_server = apt->local_server;
1200 LARGE_INTEGER zero;
1202 memset(&zero, 0, sizeof(zero));
1203 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1204 CoReleaseMarshalData(local_server->marshal_stream);
1205 IStream_Release(local_server->marshal_stream);
1206 local_server->marshal_stream = NULL;
1208 apt->local_server = NULL;
1209 local_server->apt = NULL;
1210 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1213 /* Release the references to the registered class objects */
1214 COM_RevokeAllClasses(apt);
1216 /* no locking is needed for this apartment, because no other thread
1217 * can access it at this point */
1219 apartment_disconnectproxies(apt);
1221 if (apt->win) DestroyWindow(apt->win);
1222 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1224 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1226 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1227 /* release the implicit reference given by the fact that the
1228 * stub has external references (it must do since it is in the
1229 * stub manager list in the apartment and all non-apartment users
1230 * must have a ref on the apartment and so it cannot be destroyed).
1232 stub_manager_int_release(stubmgr);
1235 /* if this assert fires, then another thread took a reference to a
1236 * stub manager without taking a reference to the containing
1237 * apartment, which it must do. */
1238 assert(list_empty(&apt->stubmgrs));
1240 if (apt->filter) IMessageFilter_Release(apt->filter);
1242 /* free as many unused libraries as possible... */
1243 apartment_freeunusedlibraries(apt, 0);
1245 /* ... and free the memory for the apartment loaded dll entry and
1246 * release the dll list reference without freeing the library for the
1247 * rest */
1248 while ((cursor = list_head(&apt->loaded_dlls)))
1250 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1251 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1252 list_remove(cursor);
1253 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1256 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1257 DeleteCriticalSection(&apt->cs);
1259 HeapFree(GetProcessHeap(), 0, apt);
1262 return ret;
1265 /* The given OXID must be local to this process:
1267 * The ref parameter is here mostly to ensure people remember that
1268 * they get one, you should normally take a ref for thread safety.
1270 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1272 APARTMENT *result = NULL;
1273 struct list *cursor;
1275 EnterCriticalSection(&csApartment);
1276 LIST_FOR_EACH( cursor, &apts )
1278 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1279 if (apt->oxid == oxid)
1281 result = apt;
1282 if (ref) apartment_addref(result);
1283 break;
1286 LeaveCriticalSection(&csApartment);
1288 return result;
1291 /* gets the apartment which has a given creator thread ID. The caller must
1292 * release the reference from the apartment as soon as the apartment pointer
1293 * is no longer required. */
1294 APARTMENT *apartment_findfromtid(DWORD tid)
1296 APARTMENT *result = NULL;
1297 struct list *cursor;
1299 EnterCriticalSection(&csApartment);
1300 LIST_FOR_EACH( cursor, &apts )
1302 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1303 if (apt->tid == tid)
1305 result = apt;
1306 apartment_addref(result);
1307 break;
1310 LeaveCriticalSection(&csApartment);
1312 return result;
1315 /* gets the main apartment if it exists. The caller must
1316 * release the reference from the apartment as soon as the apartment pointer
1317 * is no longer required. */
1318 static APARTMENT *apartment_findmain(void)
1320 APARTMENT *result;
1322 EnterCriticalSection(&csApartment);
1324 result = MainApartment;
1325 if (result) apartment_addref(result);
1327 LeaveCriticalSection(&csApartment);
1329 return result;
1332 /* gets the specified class object by loading the appropriate DLL, if
1333 * necessary and calls the DllGetClassObject function for the DLL */
1334 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1335 BOOL apartment_threaded,
1336 REFCLSID rclsid, REFIID riid, void **ppv)
1338 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1339 HRESULT hr = S_OK;
1340 BOOL found = FALSE;
1341 struct apartment_loaded_dll *apartment_loaded_dll;
1343 if (!wcsicmp(dllpath, wszOle32))
1345 /* we don't need to control the lifetime of this dll, so use the local
1346 * implementation of DllGetClassObject directly */
1347 TRACE("calling ole32!DllGetClassObject\n");
1348 hr = DllGetClassObject(rclsid, riid, ppv);
1350 if (hr != S_OK)
1351 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1353 return hr;
1356 EnterCriticalSection(&apt->cs);
1358 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1359 if (!wcsicmp(dllpath, apartment_loaded_dll->dll->library_name))
1361 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1362 found = TRUE;
1363 break;
1366 if (!found)
1368 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1369 if (!apartment_loaded_dll)
1370 hr = E_OUTOFMEMORY;
1371 if (SUCCEEDED(hr))
1373 apartment_loaded_dll->unload_time = 0;
1374 apartment_loaded_dll->multi_threaded = FALSE;
1375 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1376 if (FAILED(hr))
1377 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1379 if (SUCCEEDED(hr))
1381 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1382 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1386 LeaveCriticalSection(&apt->cs);
1388 if (SUCCEEDED(hr))
1390 /* one component being multi-threaded overrides any number of
1391 * apartment-threaded components */
1392 if (!apartment_threaded)
1393 apartment_loaded_dll->multi_threaded = TRUE;
1395 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1396 /* OK: get the ClassObject */
1397 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1399 if (hr != S_OK)
1400 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1403 return hr;
1406 /* Returns expanded dll path from the registry or activation context. */
1407 static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1409 DWORD ret;
1411 if (regdata->hkey)
1413 DWORD keytype;
1414 WCHAR src[MAX_PATH];
1415 DWORD dwLength = dstlen * sizeof(WCHAR);
1417 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1418 if (keytype == REG_EXPAND_SZ) {
1419 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1420 } else {
1421 const WCHAR *quote_start;
1422 quote_start = wcschr(src, '\"');
1423 if (quote_start) {
1424 const WCHAR *quote_end = wcschr(quote_start + 1, '\"');
1425 if (quote_end) {
1426 memmove(src, quote_start + 1,
1427 (quote_end - quote_start - 1) * sizeof(WCHAR));
1428 src[quote_end - quote_start - 1] = '\0';
1431 lstrcpynW(dst, src, dstlen);
1434 return !ret;
1436 else
1438 static const WCHAR dllW[] = {'.','d','l','l',0};
1439 ULONG_PTR cookie;
1440 WCHAR *nameW;
1442 *dst = 0;
1443 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1444 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1445 ret = SearchPathW(NULL, nameW, dllW, dstlen, dst, NULL);
1446 DeactivateActCtx(0, cookie);
1447 return *dst != 0;
1451 struct host_object_params
1453 struct class_reg_data regdata;
1454 CLSID clsid; /* clsid of object to marshal */
1455 IID iid; /* interface to marshal */
1456 HANDLE event; /* event signalling when ready for multi-threaded case */
1457 HRESULT hr; /* result for multi-threaded case */
1458 IStream *stream; /* stream that the object will be marshaled into */
1459 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1462 static HRESULT apartment_hostobject(struct apartment *apt,
1463 const struct host_object_params *params)
1465 IUnknown *object;
1466 HRESULT hr;
1467 static const LARGE_INTEGER llZero;
1468 WCHAR dllpath[MAX_PATH+1];
1470 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1472 if (!get_object_dll_path(&params->regdata, dllpath, ARRAY_SIZE(dllpath)))
1474 /* failure: CLSID is not found in registry */
1475 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1476 return REGDB_E_CLASSNOTREG;
1479 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1480 &params->clsid, &params->iid, (void **)&object);
1481 if (FAILED(hr))
1482 return hr;
1484 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1485 if (FAILED(hr))
1486 IUnknown_Release(object);
1487 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1489 return hr;
1492 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1494 switch (msg)
1496 case DM_EXECUTERPC:
1497 RPC_ExecuteCall((struct dispatch_params *)lParam);
1498 return 0;
1499 case DM_HOSTOBJECT:
1500 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1501 default:
1502 return DefWindowProcW(hWnd, msg, wParam, lParam);
1506 struct host_thread_params
1508 COINIT threading_model;
1509 HANDLE ready_event;
1510 HWND apartment_hwnd;
1513 /* thread for hosting an object to allow an object to appear to be created in
1514 * an apartment with an incompatible threading model */
1515 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1517 struct host_thread_params *params = p;
1518 MSG msg;
1519 HRESULT hr;
1520 struct apartment *apt;
1522 TRACE("\n");
1524 hr = CoInitializeEx(NULL, params->threading_model);
1525 if (FAILED(hr)) return hr;
1527 apt = COM_CurrentApt();
1528 if (params->threading_model == COINIT_APARTMENTTHREADED)
1530 apartment_createwindowifneeded(apt);
1531 params->apartment_hwnd = apartment_getwindow(apt);
1533 else
1534 params->apartment_hwnd = NULL;
1536 /* force the message queue to be created before signaling parent thread */
1537 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1539 SetEvent(params->ready_event);
1540 params = NULL; /* can't touch params after here as it may be invalid */
1542 while (GetMessageW(&msg, NULL, 0, 0))
1544 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1546 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1547 obj_params->hr = apartment_hostobject(apt, obj_params);
1548 SetEvent(obj_params->event);
1550 else
1552 TranslateMessage(&msg);
1553 DispatchMessageW(&msg);
1557 TRACE("exiting\n");
1559 CoUninitialize();
1561 return S_OK;
1564 /* finds or creates a host apartment, creates the object inside it and returns
1565 * a proxy to it so that the object can be used in the apartment of the
1566 * caller of this function */
1567 static HRESULT apartment_hostobject_in_hostapt(
1568 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1569 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1571 struct host_object_params params;
1572 HWND apartment_hwnd = NULL;
1573 DWORD apartment_tid = 0;
1574 HRESULT hr;
1576 if (!multi_threaded && main_apartment)
1578 APARTMENT *host_apt = apartment_findmain();
1579 if (host_apt)
1581 apartment_hwnd = apartment_getwindow(host_apt);
1582 apartment_release(host_apt);
1586 if (!apartment_hwnd)
1588 EnterCriticalSection(&apt->cs);
1590 if (!apt->host_apt_tid)
1592 struct host_thread_params thread_params;
1593 HANDLE handles[2];
1594 DWORD wait_value;
1596 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1597 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1598 thread_params.apartment_hwnd = NULL;
1599 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1600 if (!handles[1])
1602 CloseHandle(handles[0]);
1603 LeaveCriticalSection(&apt->cs);
1604 return E_OUTOFMEMORY;
1606 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1607 CloseHandle(handles[0]);
1608 CloseHandle(handles[1]);
1609 if (wait_value == WAIT_OBJECT_0)
1610 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1611 else
1613 LeaveCriticalSection(&apt->cs);
1614 return E_OUTOFMEMORY;
1618 if (multi_threaded || !main_apartment)
1620 apartment_hwnd = apt->host_apt_hwnd;
1621 apartment_tid = apt->host_apt_tid;
1624 LeaveCriticalSection(&apt->cs);
1627 /* another thread may have become the main apartment in the time it took
1628 * us to create the thread for the host apartment */
1629 if (!apartment_hwnd && !multi_threaded && main_apartment)
1631 APARTMENT *host_apt = apartment_findmain();
1632 if (host_apt)
1634 apartment_hwnd = apartment_getwindow(host_apt);
1635 apartment_release(host_apt);
1639 params.regdata = *regdata;
1640 params.clsid = *rclsid;
1641 params.iid = *riid;
1642 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1643 if (FAILED(hr))
1644 return hr;
1645 params.apartment_threaded = !multi_threaded;
1646 if (multi_threaded)
1648 params.hr = S_OK;
1649 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1650 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1651 hr = E_OUTOFMEMORY;
1652 else
1654 WaitForSingleObject(params.event, INFINITE);
1655 hr = params.hr;
1657 CloseHandle(params.event);
1659 else
1661 if (!apartment_hwnd)
1663 ERR("host apartment didn't create window\n");
1664 hr = E_OUTOFMEMORY;
1666 else
1667 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1669 if (SUCCEEDED(hr))
1670 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1671 IStream_Release(params.stream);
1672 return hr;
1675 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1677 WNDCLASSW wclass;
1679 /* Dispatching to the correct thread in an apartment is done through
1680 * window messages rather than RPC transports. When an interface is
1681 * marshalled into another apartment in the same process, a window of the
1682 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1683 * application) is responsible for pumping the message loop in that thread.
1684 * The WM_USER messages which point to the RPCs are then dispatched to
1685 * apartment_wndproc by the user's code from the apartment in which the
1686 * interface was unmarshalled.
1688 memset(&wclass, 0, sizeof(wclass));
1689 wclass.lpfnWndProc = apartment_wndproc;
1690 wclass.hInstance = hProxyDll;
1691 wclass.lpszClassName = wszAptWinClass;
1692 apt_win_class = RegisterClassW(&wclass);
1693 return TRUE;
1696 /* create a window for the apartment or return the current one if one has
1697 * already been created */
1698 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1700 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1702 if (apt->multi_threaded)
1703 return S_OK;
1705 if (!apt->win)
1707 HWND hwnd;
1709 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1711 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1712 HWND_MESSAGE, 0, hProxyDll, NULL);
1713 if (!hwnd)
1715 ERR("CreateWindow failed with error %d\n", GetLastError());
1716 return HRESULT_FROM_WIN32(GetLastError());
1718 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1719 /* someone beat us to it */
1720 DestroyWindow(hwnd);
1723 return S_OK;
1726 /* retrieves the window for the main- or apartment-threaded apartment */
1727 HWND apartment_getwindow(const struct apartment *apt)
1729 assert(!apt->multi_threaded);
1730 return apt->win;
1733 static void COM_TlsDestroy(void)
1735 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1736 if (info)
1738 struct init_spy *cursor, *cursor2;
1740 if (info->apt) apartment_release(info->apt);
1741 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1742 if (info->state) IUnknown_Release(info->state);
1744 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &info->spies, struct init_spy, entry)
1746 list_remove(&cursor->entry);
1747 if (cursor->spy) IInitializeSpy_Release(cursor->spy);
1748 heap_free(cursor);
1751 if (info->context_token) IObjContext_Release(info->context_token);
1753 HeapFree(GetProcessHeap(), 0, info);
1754 NtCurrentTeb()->ReservedForOle = NULL;
1758 /******************************************************************************
1759 * CoBuildVersion [OLE32.@]
1761 * Gets the build version of the DLL.
1763 * PARAMS
1765 * RETURNS
1766 * Current build version, hiword is majornumber, loword is minornumber
1768 DWORD WINAPI CoBuildVersion(void)
1770 TRACE("Returning version %d, build %d.\n", rmm, rup);
1771 return (rmm<<16)+rup;
1774 static struct init_spy *get_spy_entry(struct oletls *info, unsigned int id)
1776 struct init_spy *spy;
1778 LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry)
1780 if (id == spy->id && spy->spy)
1781 return spy;
1784 return NULL;
1788 * When locked, don't modify list (unless we add a new head), so that it's
1789 * safe to iterate it. Freeing of list entries is delayed and done on unlock.
1791 static inline void lock_init_spies(struct oletls *info)
1793 info->spies_lock++;
1796 static void unlock_init_spies(struct oletls *info)
1798 struct init_spy *spy, *next;
1800 if (--info->spies_lock) return;
1802 LIST_FOR_EACH_ENTRY_SAFE(spy, next, &info->spies, struct init_spy, entry)
1804 if (spy->spy) continue;
1805 list_remove(&spy->entry);
1806 heap_free(spy);
1810 /******************************************************************************
1811 * CoRegisterInitializeSpy [OLE32.@]
1813 * Add a Spy that watches CoInitializeEx calls
1815 * PARAMS
1816 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1817 * cookie [II] cookie receiver
1819 * RETURNS
1820 * Success: S_OK if not already initialized, S_FALSE otherwise.
1821 * Failure: HRESULT code.
1823 * SEE ALSO
1824 * CoInitializeEx
1826 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1828 struct oletls *info = COM_CurrentInfo();
1829 struct init_spy *entry;
1830 unsigned int id;
1831 HRESULT hr;
1833 TRACE("(%p, %p)\n", spy, cookie);
1835 if (!spy || !cookie || !info)
1837 if (!info)
1838 WARN("Could not allocate tls\n");
1839 return E_INVALIDARG;
1842 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1843 if (FAILED(hr))
1844 return hr;
1846 entry = heap_alloc(sizeof(*entry));
1847 if (!entry)
1849 IInitializeSpy_Release(spy);
1850 return E_OUTOFMEMORY;
1853 entry->spy = spy;
1855 id = 0;
1856 while (get_spy_entry(info, id) != NULL)
1858 id++;
1861 entry->id = id;
1862 list_add_head(&info->spies, &entry->entry);
1864 cookie->HighPart = GetCurrentThreadId();
1865 cookie->LowPart = entry->id;
1867 return S_OK;
1870 /******************************************************************************
1871 * CoRevokeInitializeSpy [OLE32.@]
1873 * Remove a spy that previously watched CoInitializeEx calls
1875 * PARAMS
1876 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1878 * RETURNS
1879 * Success: S_OK if a spy is removed
1880 * Failure: E_INVALIDARG
1882 * SEE ALSO
1883 * CoInitializeEx
1885 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1887 struct oletls *info = COM_CurrentInfo();
1888 struct init_spy *spy;
1890 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1892 if (!info || cookie.HighPart != GetCurrentThreadId())
1893 return E_INVALIDARG;
1895 if (!(spy = get_spy_entry(info, cookie.LowPart))) return E_INVALIDARG;
1897 IInitializeSpy_Release(spy->spy);
1898 spy->spy = NULL;
1899 if (!info->spies_lock)
1901 list_remove(&spy->entry);
1902 heap_free(spy);
1904 return S_OK;
1907 HRESULT enter_apartment( struct oletls *info, DWORD model )
1909 HRESULT hr = S_OK;
1911 if (!info->apt)
1913 if (!apartment_get_or_create( model ))
1914 return E_OUTOFMEMORY;
1916 else if (!apartment_is_model( info->apt, model ))
1918 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1919 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1920 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1921 return RPC_E_CHANGED_MODE;
1923 else
1924 hr = S_FALSE;
1926 info->inits++;
1928 return hr;
1931 void leave_apartment( struct oletls *info )
1933 if (!--info->inits)
1935 if (info->ole_inits)
1936 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1937 apartment_release( info->apt );
1938 info->apt = NULL;
1942 /******************************************************************************
1943 * CoInitialize [OLE32.@]
1945 * Initializes the COM libraries by calling CoInitializeEx with
1946 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1948 * PARAMS
1949 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1951 * RETURNS
1952 * Success: S_OK if not already initialized, S_FALSE otherwise.
1953 * Failure: HRESULT code.
1955 * SEE ALSO
1956 * CoInitializeEx
1958 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1961 * Just delegate to the newer method.
1963 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1966 /******************************************************************************
1967 * CoInitializeEx [OLE32.@]
1969 * Initializes the COM libraries.
1971 * PARAMS
1972 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1973 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1975 * RETURNS
1976 * S_OK if successful,
1977 * S_FALSE if this function was called already.
1978 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1979 * threading model.
1981 * NOTES
1983 * The behavior used to set the IMalloc used for memory management is
1984 * obsolete.
1985 * The dwCoInit parameter must specify one of the following apartment
1986 * threading models:
1987 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1988 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1989 * The parameter may also specify zero or more of the following flags:
1990 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1991 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1993 * SEE ALSO
1994 * CoUninitialize
1996 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1998 struct oletls *info = COM_CurrentInfo();
1999 struct init_spy *cursor;
2000 HRESULT hr;
2002 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
2004 if (lpReserved!=NULL)
2006 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
2010 * Check the lock count. If this is the first time going through the initialize
2011 * process, we have to initialize the libraries.
2013 * And crank-up that lock count.
2015 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
2018 * Initialize the various COM libraries and data structures.
2020 TRACE("() - Initializing the COM libraries\n");
2022 /* we may need to defer this until after apartment initialisation */
2023 RunningObjectTableImpl_Initialize();
2026 lock_init_spies(info);
2027 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2029 if (cursor->spy) IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits);
2031 unlock_init_spies(info);
2033 hr = enter_apartment( info, dwCoInit );
2035 lock_init_spies(info);
2036 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2038 if (cursor->spy) hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits);
2040 unlock_init_spies(info);
2042 return hr;
2045 /***********************************************************************
2046 * CoUninitialize [OLE32.@]
2048 * This method will decrement the refcount on the current apartment, freeing
2049 * the resources associated with it if it is the last thread in the apartment.
2050 * If the last apartment is freed, the function will additionally release
2051 * any COM resources associated with the process.
2053 * PARAMS
2055 * RETURNS
2056 * Nothing.
2058 * SEE ALSO
2059 * CoInitializeEx
2061 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2063 struct oletls * info = COM_CurrentInfo();
2064 struct init_spy *cursor, *next;
2065 LONG lCOMRefCnt;
2067 TRACE("()\n");
2069 /* will only happen on OOM */
2070 if (!info) return;
2072 lock_init_spies(info);
2073 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry)
2075 if (cursor->spy) IInitializeSpy_PreUninitialize(cursor->spy, info->inits);
2077 unlock_init_spies(info);
2079 /* sanity check */
2080 if (!info->inits)
2082 ERR("Mismatched CoUninitialize\n");
2084 lock_init_spies(info);
2085 LIST_FOR_EACH_ENTRY_SAFE(cursor, next, &info->spies, struct init_spy, entry)
2087 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2089 unlock_init_spies(info);
2091 return;
2094 leave_apartment( info );
2097 * Decrease the reference count.
2098 * If we are back to 0 locks on the COM library, make sure we free
2099 * all the associated data structures.
2101 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2102 if (lCOMRefCnt==1)
2104 TRACE("() - Releasing the COM libraries\n");
2106 revoke_registered_psclsids();
2107 RunningObjectTableImpl_UnInitialize();
2109 else if (lCOMRefCnt<1) {
2110 ERR( "CoUninitialize() - not CoInitialized.\n" );
2111 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2114 lock_init_spies(info);
2115 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2117 if (cursor->spy) IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2119 unlock_init_spies(info);
2122 /******************************************************************************
2123 * CoDisconnectObject [OLE32.@]
2125 * Disconnects all connections to this object from remote processes. Dispatches
2126 * pending RPCs while blocking new RPCs from occurring, and then calls
2127 * IMarshal::DisconnectObject on the given object.
2129 * Typically called when the object server is forced to shut down, for instance by
2130 * the user.
2132 * PARAMS
2133 * lpUnk [I] The object whose stub should be disconnected.
2134 * reserved [I] Reserved. Should be set to 0.
2136 * RETURNS
2137 * Success: S_OK.
2138 * Failure: HRESULT code.
2140 * SEE ALSO
2141 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2143 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2145 struct stub_manager *manager;
2146 HRESULT hr;
2147 IMarshal *marshal;
2148 APARTMENT *apt;
2150 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2152 if (!lpUnk) return E_INVALIDARG;
2154 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2155 if (hr == S_OK)
2157 hr = IMarshal_DisconnectObject(marshal, reserved);
2158 IMarshal_Release(marshal);
2159 return hr;
2162 if (!(apt = apartment_get_current_or_mta()))
2164 ERR("apartment not initialised\n");
2165 return CO_E_NOTINITIALIZED;
2168 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2169 if (manager) {
2170 stub_manager_disconnect(manager);
2171 /* Release stub manager twice, to remove the apartment reference. */
2172 stub_manager_int_release(manager);
2173 stub_manager_int_release(manager);
2176 /* Note: native is pretty broken here because it just silently
2177 * fails, without returning an appropriate error code if the object was
2178 * not found, making apps think that the object was disconnected, when
2179 * it actually wasn't */
2181 apartment_release(apt);
2182 return S_OK;
2185 /******************************************************************************
2186 * CoCreateGuid [OLE32.@]
2188 * Simply forwards to UuidCreate in RPCRT4.
2190 * PARAMS
2191 * pguid [O] Points to the GUID to initialize.
2193 * RETURNS
2194 * Success: S_OK.
2195 * Failure: HRESULT code.
2197 * SEE ALSO
2198 * UuidCreate
2200 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2202 DWORD status;
2204 if(!pguid) return E_INVALIDARG;
2206 status = UuidCreate(pguid);
2207 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2208 return HRESULT_FROM_WIN32( status );
2211 static inline BOOL is_valid_hex(WCHAR c)
2213 if (!(((c >= '0') && (c <= '9')) ||
2214 ((c >= 'a') && (c <= 'f')) ||
2215 ((c >= 'A') && (c <= 'F'))))
2216 return FALSE;
2217 return TRUE;
2220 static const BYTE guid_conv_table[256] =
2222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2223 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2224 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2225 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2226 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2227 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2228 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2231 /* conversion helper for CLSIDFromString/IIDFromString */
2232 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2234 int i;
2236 if (!s || s[0]!='{') {
2237 memset( id, 0, sizeof (CLSID) );
2238 if(!s) return TRUE;
2239 return FALSE;
2242 TRACE("%s -> %p\n", debugstr_w(s), id);
2244 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2246 id->Data1 = 0;
2247 for (i = 1; i < 9; i++) {
2248 if (!is_valid_hex(s[i])) return FALSE;
2249 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2251 if (s[9]!='-') return FALSE;
2253 id->Data2 = 0;
2254 for (i = 10; i < 14; i++) {
2255 if (!is_valid_hex(s[i])) return FALSE;
2256 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2258 if (s[14]!='-') return FALSE;
2260 id->Data3 = 0;
2261 for (i = 15; i < 19; i++) {
2262 if (!is_valid_hex(s[i])) return FALSE;
2263 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2265 if (s[19]!='-') return FALSE;
2267 for (i = 20; i < 37; i+=2) {
2268 if (i == 24) {
2269 if (s[i]!='-') return FALSE;
2270 i++;
2272 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2273 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2276 if (s[37] == '}' && s[38] == '\0')
2277 return TRUE;
2279 return FALSE;
2282 /*****************************************************************************/
2284 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2286 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2287 WCHAR buf2[CHARS_IN_GUID];
2288 LONG buf2len = sizeof(buf2);
2289 HKEY xhkey;
2290 WCHAR *buf;
2292 memset(clsid, 0, sizeof(*clsid));
2293 buf = HeapAlloc( GetProcessHeap(),0,(lstrlenW(progid)+8) * sizeof(WCHAR) );
2294 if (!buf) return E_OUTOFMEMORY;
2295 lstrcpyW( buf, progid );
2296 lstrcatW( buf, clsidW );
2297 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2299 HeapFree(GetProcessHeap(),0,buf);
2300 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2301 return CO_E_CLASSSTRING;
2303 HeapFree(GetProcessHeap(),0,buf);
2305 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2307 RegCloseKey(xhkey);
2308 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2309 return CO_E_CLASSSTRING;
2311 RegCloseKey(xhkey);
2312 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2315 /******************************************************************************
2316 * CLSIDFromString [OLE32.@]
2318 * Converts a unique identifier from its string representation into
2319 * the GUID struct.
2321 * PARAMS
2322 * idstr [I] The string representation of the GUID.
2323 * id [O] GUID converted from the string.
2325 * RETURNS
2326 * S_OK on success
2327 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2329 * SEE ALSO
2330 * StringFromCLSID
2332 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2334 HRESULT ret = CO_E_CLASSSTRING;
2335 CLSID tmp_id;
2337 if (!id)
2338 return E_INVALIDARG;
2340 if (guid_from_string(idstr, id))
2341 return S_OK;
2343 /* It appears a ProgID is also valid */
2344 ret = clsid_from_string_reg(idstr, &tmp_id);
2345 if(SUCCEEDED(ret))
2346 *id = tmp_id;
2348 return ret;
2351 /******************************************************************************
2352 * IIDFromString [OLE32.@]
2354 * Converts an interface identifier from its string representation to
2355 * the IID struct.
2357 * PARAMS
2358 * idstr [I] The string representation of the GUID.
2359 * id [O] IID converted from the string.
2361 * RETURNS
2362 * S_OK on success
2363 * CO_E_IIDSTRING if idstr is not a valid IID
2365 * SEE ALSO
2366 * StringFromIID
2368 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2370 TRACE("%s -> %p\n", debugstr_w(s), iid);
2372 if (!s)
2374 memset(iid, 0, sizeof(*iid));
2375 return S_OK;
2378 /* length mismatch is a special case */
2379 if (lstrlenW(s) + 1 != CHARS_IN_GUID)
2380 return E_INVALIDARG;
2382 if (s[0] != '{')
2383 return CO_E_IIDSTRING;
2385 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2388 /******************************************************************************
2389 * StringFromCLSID [OLE32.@]
2390 * StringFromIID [OLE32.@]
2392 * Converts a GUID into the respective string representation.
2393 * The target string is allocated using the OLE IMalloc.
2395 * PARAMS
2396 * id [I] the GUID to be converted.
2397 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2399 * RETURNS
2400 * S_OK
2401 * E_FAIL
2403 * SEE ALSO
2404 * StringFromGUID2, CLSIDFromString
2406 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2408 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2409 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2410 return S_OK;
2413 /******************************************************************************
2414 * StringFromGUID2 [OLE32.@]
2416 * Modified version of StringFromCLSID that allows you to specify max
2417 * buffer size.
2419 * PARAMS
2420 * id [I] GUID to convert to string.
2421 * str [O] Buffer where the result will be stored.
2422 * cmax [I] Size of the buffer in characters.
2424 * RETURNS
2425 * Success: The length of the resulting string in characters.
2426 * Failure: 0.
2428 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2430 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2431 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2432 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2433 '%','0','2','X','%','0','2','X','}',0 };
2434 if (!id || cmax < CHARS_IN_GUID) return 0;
2435 swprintf( str, CHARS_IN_GUID, formatW, id->Data1, id->Data2, id->Data3,
2436 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2437 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2438 return CHARS_IN_GUID;
2441 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2442 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2444 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2445 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) - 1];
2446 LONG res;
2447 HKEY key;
2449 lstrcpyW(path, wszCLSIDSlash);
2450 StringFromGUID2(clsid, path + lstrlenW(wszCLSIDSlash), CHARS_IN_GUID);
2451 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2452 if (res == ERROR_FILE_NOT_FOUND)
2453 return REGDB_E_CLASSNOTREG;
2454 else if (res != ERROR_SUCCESS)
2455 return REGDB_E_READREGDB;
2457 if (!keyname)
2459 *subkey = key;
2460 return S_OK;
2463 res = open_classes_key(key, keyname, access, subkey);
2464 RegCloseKey(key);
2465 if (res == ERROR_FILE_NOT_FOUND)
2466 return REGDB_E_KEYMISSING;
2467 else if (res != ERROR_SUCCESS)
2468 return REGDB_E_READREGDB;
2470 return S_OK;
2473 /* open HKCR\\AppId\\{string form of appid clsid} key */
2474 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2476 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2477 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2478 DWORD res;
2479 WCHAR buf[CHARS_IN_GUID];
2480 WCHAR keyname[ARRAY_SIZE(szAppIdKey) + CHARS_IN_GUID];
2481 DWORD size;
2482 HKEY hkey;
2483 DWORD type;
2484 HRESULT hr;
2486 /* read the AppID value under the class's key */
2487 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2488 if (FAILED(hr))
2489 return hr;
2491 size = sizeof(buf);
2492 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2493 RegCloseKey(hkey);
2494 if (res == ERROR_FILE_NOT_FOUND)
2495 return REGDB_E_KEYMISSING;
2496 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2497 return REGDB_E_READREGDB;
2499 lstrcpyW(keyname, szAppIdKey);
2500 lstrcatW(keyname, buf);
2501 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2502 if (res == ERROR_FILE_NOT_FOUND)
2503 return REGDB_E_KEYMISSING;
2504 else if (res != ERROR_SUCCESS)
2505 return REGDB_E_READREGDB;
2507 return S_OK;
2510 /******************************************************************************
2511 * ProgIDFromCLSID [OLE32.@]
2513 * Converts a class id into the respective program ID.
2515 * PARAMS
2516 * clsid [I] Class ID, as found in registry.
2517 * ppszProgID [O] Associated ProgID.
2519 * RETURNS
2520 * S_OK
2521 * E_OUTOFMEMORY
2522 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2524 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2526 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2527 ACTCTX_SECTION_KEYED_DATA data;
2528 HKEY hkey;
2529 HRESULT ret;
2530 LONG progidlen = 0;
2532 if (!ppszProgID)
2533 return E_INVALIDARG;
2535 *ppszProgID = NULL;
2537 data.cbSize = sizeof(data);
2538 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2539 clsid, &data))
2541 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2542 if (comclass->progid_len)
2544 WCHAR *ptrW;
2546 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2547 if (!*ppszProgID) return E_OUTOFMEMORY;
2549 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2550 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2551 return S_OK;
2553 else
2554 return REGDB_E_CLASSNOTREG;
2557 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2558 if (FAILED(ret))
2559 return ret;
2561 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2562 ret = REGDB_E_CLASSNOTREG;
2564 if (ret == S_OK)
2566 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2567 if (*ppszProgID)
2569 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2570 ret = REGDB_E_CLASSNOTREG;
2571 CoTaskMemFree(*ppszProgID);
2572 *ppszProgID = NULL;
2575 else
2576 ret = E_OUTOFMEMORY;
2579 RegCloseKey(hkey);
2580 return ret;
2583 /******************************************************************************
2584 * CLSIDFromProgID [OLE32.@]
2586 * Converts a program id into the respective GUID.
2588 * PARAMS
2589 * progid [I] Unicode program ID, as found in registry.
2590 * clsid [O] Associated CLSID.
2592 * RETURNS
2593 * Success: S_OK
2594 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2596 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2598 ACTCTX_SECTION_KEYED_DATA data;
2600 if (!progid || !clsid)
2601 return E_INVALIDARG;
2603 data.cbSize = sizeof(data);
2604 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2605 progid, &data))
2607 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2608 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2609 *clsid = *alias;
2610 return S_OK;
2613 return clsid_from_string_reg(progid, clsid);
2616 /******************************************************************************
2617 * CLSIDFromProgIDEx [OLE32.@]
2619 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2621 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2623 return CLSIDFromProgID(progid, clsid);
2626 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2628 HKEY hkey;
2629 WCHAR value[CHARS_IN_GUID];
2630 DWORD len;
2632 access |= KEY_READ;
2634 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2635 return REGDB_E_IIDNOTREG;
2637 len = sizeof(value);
2638 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2639 return REGDB_E_IIDNOTREG;
2640 RegCloseKey(hkey);
2642 if (CLSIDFromString(value, pclsid) != NOERROR)
2643 return REGDB_E_IIDNOTREG;
2645 return S_OK;
2648 /*****************************************************************************
2649 * CoGetPSClsid [OLE32.@]
2651 * Retrieves the CLSID of the proxy/stub factory that implements
2652 * IPSFactoryBuffer for the specified interface.
2654 * PARAMS
2655 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2656 * pclsid [O] Where to store returned proxy/stub CLSID.
2658 * RETURNS
2659 * S_OK
2660 * E_OUTOFMEMORY
2661 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2663 * NOTES
2665 * The standard marshaller activates the object with the CLSID
2666 * returned and uses the CreateProxy and CreateStub methods on its
2667 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2668 * given object.
2670 * CoGetPSClsid determines this CLSID by searching the
2671 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2672 * in the registry and any interface id registered by
2673 * CoRegisterPSClsid within the current process.
2675 * BUGS
2677 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2678 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2679 * considered a bug in native unless an application depends on this (unlikely).
2681 * SEE ALSO
2682 * CoRegisterPSClsid.
2684 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2686 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2687 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2688 WCHAR path[ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(wszPSC)];
2689 APARTMENT *apt;
2690 struct registered_psclsid *registered_psclsid;
2691 ACTCTX_SECTION_KEYED_DATA data;
2692 HRESULT hr;
2693 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2694 BOOL is_wow64;
2696 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2698 if (!(apt = apartment_get_current_or_mta()))
2700 ERR("apartment not initialised\n");
2701 return CO_E_NOTINITIALIZED;
2703 apartment_release(apt);
2705 if (!pclsid)
2706 return E_INVALIDARG;
2708 EnterCriticalSection(&cs_registered_psclsid_list);
2710 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2711 if (IsEqualIID(&registered_psclsid->iid, riid))
2713 *pclsid = registered_psclsid->clsid;
2714 LeaveCriticalSection(&cs_registered_psclsid_list);
2715 return S_OK;
2718 LeaveCriticalSection(&cs_registered_psclsid_list);
2720 data.cbSize = sizeof(data);
2721 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2722 riid, &data))
2724 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2725 *pclsid = ifaceps->iid;
2726 return S_OK;
2729 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2730 lstrcpyW(path, wszInterface);
2731 StringFromGUID2(riid, path + ARRAY_SIZE(wszInterface) - 1, CHARS_IN_GUID);
2732 lstrcpyW(path + ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2734 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2735 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2736 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2737 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2739 if (hr == S_OK)
2740 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2741 else
2742 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2744 return hr;
2747 /*****************************************************************************
2748 * CoRegisterPSClsid [OLE32.@]
2750 * Register a proxy/stub CLSID for the given interface in the current process
2751 * only.
2753 * PARAMS
2754 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2755 * rclsid [I] CLSID of the proxy/stub.
2757 * RETURNS
2758 * Success: S_OK
2759 * Failure: E_OUTOFMEMORY
2761 * NOTES
2763 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2764 * will be returned from other apartments in the same process.
2766 * This function does not add anything to the registry and the effects are
2767 * limited to the lifetime of the current process.
2769 * SEE ALSO
2770 * CoGetPSClsid.
2772 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2774 APARTMENT *apt;
2775 struct registered_psclsid *registered_psclsid;
2777 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2779 if (!(apt = apartment_get_current_or_mta()))
2781 ERR("apartment not initialised\n");
2782 return CO_E_NOTINITIALIZED;
2784 apartment_release(apt);
2786 EnterCriticalSection(&cs_registered_psclsid_list);
2788 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2789 if (IsEqualIID(&registered_psclsid->iid, riid))
2791 registered_psclsid->clsid = *rclsid;
2792 LeaveCriticalSection(&cs_registered_psclsid_list);
2793 return S_OK;
2796 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2797 if (!registered_psclsid)
2799 LeaveCriticalSection(&cs_registered_psclsid_list);
2800 return E_OUTOFMEMORY;
2803 registered_psclsid->iid = *riid;
2804 registered_psclsid->clsid = *rclsid;
2805 list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2807 LeaveCriticalSection(&cs_registered_psclsid_list);
2809 return S_OK;
2813 /***
2814 * COM_GetRegisteredClassObject
2816 * This internal method is used to scan the registered class list to
2817 * find a class object.
2819 * Params:
2820 * rclsid Class ID of the class to find.
2821 * dwClsContext Class context to match.
2822 * ppv [out] returns a pointer to the class object. Complying
2823 * to normal COM usage, this method will increase the
2824 * reference count on this object.
2826 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2827 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2829 HRESULT hr = S_FALSE;
2830 RegisteredClass *curClass;
2832 EnterCriticalSection( &csRegisteredClassList );
2834 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2837 * Check if we have a match on the class ID and context.
2839 if ((apt->oxid == curClass->apartment_id) &&
2840 (dwClsContext & curClass->runContext) &&
2841 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2844 * We have a match, return the pointer to the class object.
2846 *ppUnk = curClass->classObject;
2848 IUnknown_AddRef(curClass->classObject);
2850 hr = S_OK;
2851 break;
2855 LeaveCriticalSection( &csRegisteredClassList );
2857 return hr;
2860 /******************************************************************************
2861 * CoRegisterClassObject [OLE32.@]
2863 * Registers the class object for a given class ID. Servers housed in EXE
2864 * files use this method instead of exporting DllGetClassObject to allow
2865 * other code to connect to their objects.
2867 * PARAMS
2868 * rclsid [I] CLSID of the object to register.
2869 * pUnk [I] IUnknown of the object.
2870 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2871 * flags [I] REGCLS flags indicating how connections are made.
2872 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2874 * RETURNS
2875 * S_OK on success,
2876 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2877 * CO_E_OBJISREG if the object is already registered. We should not return this.
2879 * SEE ALSO
2880 * CoRevokeClassObject, CoGetClassObject
2882 * NOTES
2883 * In-process objects are only registered for the current apartment.
2884 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2885 * in other apartments.
2887 * BUGS
2888 * MSDN claims that multiple interface registrations are legal, but we
2889 * can't do that with our current implementation.
2891 HRESULT WINAPI CoRegisterClassObject(
2892 REFCLSID rclsid,
2893 LPUNKNOWN pUnk,
2894 DWORD dwClsContext,
2895 DWORD flags,
2896 LPDWORD lpdwRegister)
2898 static LONG next_cookie;
2899 RegisteredClass* newClass;
2900 LPUNKNOWN foundObject;
2901 HRESULT hr;
2902 APARTMENT *apt;
2904 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2905 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2907 if ( (lpdwRegister==0) || (pUnk==0) )
2908 return E_INVALIDARG;
2910 if (!(apt = apartment_get_current_or_mta()))
2912 ERR("COM was not initialized\n");
2913 return CO_E_NOTINITIALIZED;
2916 *lpdwRegister = 0;
2918 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2919 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2920 if (flags & REGCLS_MULTIPLEUSE)
2921 dwClsContext |= CLSCTX_INPROC_SERVER;
2924 * First, check if the class is already registered.
2925 * If it is, this should cause an error.
2927 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2928 if (hr == S_OK) {
2929 if (flags & REGCLS_MULTIPLEUSE) {
2930 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2931 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2932 IUnknown_Release(foundObject);
2933 apartment_release(apt);
2934 return hr;
2936 IUnknown_Release(foundObject);
2937 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2938 apartment_release(apt);
2939 return CO_E_OBJISREG;
2942 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2943 if ( newClass == NULL )
2945 apartment_release(apt);
2946 return E_OUTOFMEMORY;
2949 newClass->classIdentifier = *rclsid;
2950 newClass->apartment_id = apt->oxid;
2951 newClass->runContext = dwClsContext;
2952 newClass->connectFlags = flags;
2953 newClass->RpcRegistration = NULL;
2955 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2956 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2959 * Since we're making a copy of the object pointer, we have to increase its
2960 * reference count.
2962 newClass->classObject = pUnk;
2963 IUnknown_AddRef(newClass->classObject);
2965 EnterCriticalSection( &csRegisteredClassList );
2966 list_add_tail(&RegisteredClassList, &newClass->entry);
2967 LeaveCriticalSection( &csRegisteredClassList );
2969 *lpdwRegister = newClass->dwCookie;
2971 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2972 IStream *marshal_stream;
2974 hr = get_local_server_stream(apt, &marshal_stream);
2975 if(FAILED(hr))
2977 apartment_release(apt);
2978 return hr;
2981 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2982 marshal_stream,
2983 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2984 &newClass->RpcRegistration);
2985 IStream_Release(marshal_stream);
2987 apartment_release(apt);
2988 return S_OK;
2991 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2993 if (data->hkey)
2995 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2996 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2997 static const WCHAR wszFree[] = {'F','r','e','e',0};
2998 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2999 WCHAR threading_model[10 /* lstrlenW(L"apartment")+1 */];
3000 DWORD dwLength = sizeof(threading_model);
3001 DWORD keytype;
3002 DWORD ret;
3004 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
3005 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
3006 threading_model[0] = '\0';
3008 if (!wcsicmp(threading_model, wszApartment)) return ThreadingModel_Apartment;
3009 if (!wcsicmp(threading_model, wszFree)) return ThreadingModel_Free;
3010 if (!wcsicmp(threading_model, wszBoth)) return ThreadingModel_Both;
3012 /* there's not specific handling for this case */
3013 if (threading_model[0]) return ThreadingModel_Neutral;
3014 return ThreadingModel_No;
3016 else
3017 return data->u.actctx.data->model;
3020 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
3021 REFCLSID rclsid, REFIID riid,
3022 BOOL hostifnecessary, void **ppv)
3024 WCHAR dllpath[MAX_PATH+1];
3025 BOOL apartment_threaded;
3027 if (hostifnecessary)
3029 enum comclass_threadingmodel model = get_threading_model(regdata);
3031 if (model == ThreadingModel_Apartment)
3033 apartment_threaded = TRUE;
3034 if (apt->multi_threaded)
3035 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
3037 else if (model == ThreadingModel_Free)
3039 apartment_threaded = FALSE;
3040 if (!apt->multi_threaded)
3041 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
3043 /* everything except "Apartment", "Free" and "Both" */
3044 else if (model != ThreadingModel_Both)
3046 apartment_threaded = TRUE;
3047 /* everything else is main-threaded */
3048 if (model != ThreadingModel_No)
3049 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
3051 if (apt->multi_threaded || !apt->main)
3052 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
3054 else
3055 apartment_threaded = FALSE;
3057 else
3058 apartment_threaded = !apt->multi_threaded;
3060 if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath)))
3062 /* failure: CLSID is not found in registry */
3063 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
3064 return REGDB_E_CLASSNOTREG;
3067 return apartment_getclassobject(apt, dllpath, apartment_threaded,
3068 rclsid, riid, ppv);
3071 /***********************************************************************
3072 * CoGetClassObject [OLE32.@]
3074 * Creates an object of the specified class.
3076 * PARAMS
3077 * rclsid [I] Class ID to create an instance of.
3078 * dwClsContext [I] Flags to restrict the location of the created instance.
3079 * pServerInfo [I] Optional. Details for connecting to a remote server.
3080 * iid [I] The ID of the interface of the instance to return.
3081 * ppv [O] On returns, contains a pointer to the specified interface of the object.
3083 * RETURNS
3084 * Success: S_OK
3085 * Failure: HRESULT code.
3087 * NOTES
3088 * The dwClsContext parameter can be one or more of the following:
3089 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3090 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3091 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3092 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3094 * SEE ALSO
3095 * CoCreateInstance()
3097 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
3098 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
3099 REFIID iid, LPVOID *ppv)
3101 struct class_reg_data clsreg;
3102 IUnknown *regClassObject;
3103 HRESULT hres = E_UNEXPECTED;
3104 APARTMENT *apt;
3106 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
3108 if (!ppv)
3109 return E_INVALIDARG;
3111 *ppv = NULL;
3113 if (!(apt = apartment_get_current_or_mta()))
3115 ERR("apartment not initialised\n");
3116 return CO_E_NOTINITIALIZED;
3119 if (pServerInfo) {
3120 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3121 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
3124 if (CLSCTX_INPROC_SERVER & dwClsContext)
3126 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
3128 apartment_release(apt);
3129 return FTMarshalCF_Create(iid, ppv);
3131 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3132 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3135 if (CLSCTX_INPROC & dwClsContext)
3137 ACTCTX_SECTION_KEYED_DATA data;
3139 data.cbSize = sizeof(data);
3140 /* search activation context first */
3141 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3142 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3143 rclsid, &data))
3145 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3147 clsreg.u.actctx.hactctx = data.hActCtx;
3148 clsreg.u.actctx.data = data.lpData;
3149 clsreg.u.actctx.section = data.lpSectionBase;
3150 clsreg.hkey = FALSE;
3152 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3153 ReleaseActCtx(data.hActCtx);
3154 apartment_release(apt);
3155 return hres;
3160 * First, try and see if we can't match the class ID with one of the
3161 * registered classes.
3163 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3164 &regClassObject))
3166 /* Get the required interface from the retrieved pointer. */
3167 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3170 * Since QI got another reference on the pointer, we want to release the
3171 * one we already have. If QI was unsuccessful, this will release the object. This
3172 * is good since we are not returning it in the "out" parameter.
3174 IUnknown_Release(regClassObject);
3175 apartment_release(apt);
3176 return hres;
3179 /* First try in-process server */
3180 if (CLSCTX_INPROC_SERVER & dwClsContext)
3182 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3183 HKEY hkey;
3185 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3186 if (FAILED(hres))
3188 if (hres == REGDB_E_CLASSNOTREG)
3189 ERR("class %s not registered\n", debugstr_guid(rclsid));
3190 else if (hres == REGDB_E_KEYMISSING)
3192 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3193 hres = REGDB_E_CLASSNOTREG;
3197 if (SUCCEEDED(hres))
3199 clsreg.u.hkey = hkey;
3200 clsreg.hkey = TRUE;
3202 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3203 RegCloseKey(hkey);
3206 /* return if we got a class, otherwise fall through to one of the
3207 * other types */
3208 if (SUCCEEDED(hres))
3210 apartment_release(apt);
3211 return hres;
3215 /* Next try in-process handler */
3216 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3218 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3219 HKEY hkey;
3221 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3222 if (FAILED(hres))
3224 if (hres == REGDB_E_CLASSNOTREG)
3225 ERR("class %s not registered\n", debugstr_guid(rclsid));
3226 else if (hres == REGDB_E_KEYMISSING)
3228 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3229 hres = REGDB_E_CLASSNOTREG;
3233 if (SUCCEEDED(hres))
3235 clsreg.u.hkey = hkey;
3236 clsreg.hkey = TRUE;
3238 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3239 RegCloseKey(hkey);
3242 /* return if we got a class, otherwise fall through to one of the
3243 * other types */
3244 if (SUCCEEDED(hres))
3246 apartment_release(apt);
3247 return hres;
3250 apartment_release(apt);
3252 /* Next try out of process */
3253 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3255 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3256 if (SUCCEEDED(hres))
3257 return hres;
3260 /* Finally try remote: this requires networked DCOM (a lot of work) */
3261 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3263 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3264 hres = REGDB_E_CLASSNOTREG;
3267 if (FAILED(hres))
3268 ERR("no class object %s could be created for context 0x%x\n",
3269 debugstr_guid(rclsid), dwClsContext);
3270 return hres;
3273 /***********************************************************************
3274 * CoResumeClassObjects (OLE32.@)
3276 * Resumes all class objects registered with REGCLS_SUSPENDED.
3278 * RETURNS
3279 * Success: S_OK.
3280 * Failure: HRESULT code.
3282 HRESULT WINAPI CoResumeClassObjects(void)
3284 FIXME("stub\n");
3285 return S_OK;
3288 /***********************************************************************
3289 * CoCreateInstance [OLE32.@]
3291 * Creates an instance of the specified class.
3293 * PARAMS
3294 * rclsid [I] Class ID to create an instance of.
3295 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3296 * dwClsContext [I] Flags to restrict the location of the created instance.
3297 * iid [I] The ID of the interface of the instance to return.
3298 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3300 * RETURNS
3301 * Success: S_OK
3302 * Failure: HRESULT code.
3304 * NOTES
3305 * The dwClsContext parameter can be one or more of the following:
3306 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3307 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3308 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3309 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3311 * Aggregation is the concept of deferring the IUnknown of an object to another
3312 * object. This allows a separate object to behave as though it was part of
3313 * the object and to allow this the pUnkOuter parameter can be set. Note that
3314 * not all objects support having an outer of unknown.
3316 * SEE ALSO
3317 * CoGetClassObject()
3319 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3320 REFCLSID rclsid,
3321 LPUNKNOWN pUnkOuter,
3322 DWORD dwClsContext,
3323 REFIID iid,
3324 LPVOID *ppv)
3326 MULTI_QI multi_qi = { iid };
3327 HRESULT hres;
3329 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3330 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3332 if (ppv==0)
3333 return E_POINTER;
3335 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3336 *ppv = multi_qi.pItf;
3337 return hres;
3340 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3342 ULONG i;
3344 for (i = 0; i < count; i++)
3346 mqi[i].pItf = NULL;
3347 mqi[i].hr = hr;
3351 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3353 ULONG index = 0, fetched = 0;
3355 if (include_unk)
3357 mqi[0].hr = S_OK;
3358 mqi[0].pItf = unk;
3359 index = fetched = 1;
3362 for (; index < count; index++)
3364 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3365 if (mqi[index].hr == S_OK)
3366 fetched++;
3369 if (!include_unk)
3370 IUnknown_Release(unk);
3372 if (fetched == 0)
3373 return E_NOINTERFACE;
3375 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3378 /***********************************************************************
3379 * CoCreateInstanceEx [OLE32.@]
3381 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3382 REFCLSID rclsid,
3383 LPUNKNOWN pUnkOuter,
3384 DWORD dwClsContext,
3385 COSERVERINFO* pServerInfo,
3386 ULONG cmq,
3387 MULTI_QI* pResults)
3389 IUnknown *unk = NULL;
3390 IClassFactory *cf;
3391 APARTMENT *apt;
3392 CLSID clsid;
3393 HRESULT hres;
3395 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3397 if (!cmq || !pResults)
3398 return E_INVALIDARG;
3400 if (pServerInfo)
3401 FIXME("() non-NULL pServerInfo not supported!\n");
3403 init_multi_qi(cmq, pResults, E_NOINTERFACE);
3405 hres = CoGetTreatAsClass(rclsid, &clsid);
3406 if(FAILED(hres))
3407 clsid = *rclsid;
3409 if (!(apt = apartment_get_current_or_mta()))
3411 ERR("apartment not initialised\n");
3412 return CO_E_NOTINITIALIZED;
3414 apartment_release(apt);
3417 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3419 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3421 IGlobalInterfaceTable *git = get_std_git();
3422 TRACE("Retrieving GIT\n");
3423 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3426 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3427 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3428 if (FAILED(hres))
3429 return hres;
3430 return return_multi_qi(unk, cmq, pResults, TRUE);
3434 * Get a class factory to construct the object we want.
3436 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3437 if (FAILED(hres))
3438 return hres;
3441 * Create the object and don't forget to release the factory
3443 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3444 IClassFactory_Release(cf);
3445 if (FAILED(hres))
3447 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3448 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3449 else
3450 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3451 debugstr_guid(pResults[0].pIID),
3452 debugstr_guid(&clsid),hres);
3453 return hres;
3456 return return_multi_qi(unk, cmq, pResults, TRUE);
3459 /***********************************************************************
3460 * CoGetInstanceFromFile [OLE32.@]
3462 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3463 COSERVERINFO *server_info,
3464 CLSID *rclsid,
3465 IUnknown *outer,
3466 DWORD cls_context,
3467 DWORD grfmode,
3468 OLECHAR *filename,
3469 DWORD count,
3470 MULTI_QI *results
3473 IPersistFile *pf = NULL;
3474 IUnknown* unk = NULL;
3475 CLSID clsid;
3476 HRESULT hr;
3478 if (count == 0 || !results)
3479 return E_INVALIDARG;
3481 if (server_info)
3482 FIXME("() non-NULL server_info not supported\n");
3484 init_multi_qi(count, results, E_NOINTERFACE);
3486 /* optionally get CLSID from a file */
3487 if (!rclsid)
3489 hr = GetClassFile(filename, &clsid);
3490 if (FAILED(hr))
3492 ERR("failed to get CLSID from a file\n");
3493 return hr;
3496 rclsid = &clsid;
3499 hr = CoCreateInstance(rclsid,
3500 outer,
3501 cls_context,
3502 &IID_IUnknown,
3503 (void**)&unk);
3505 if (hr != S_OK)
3507 init_multi_qi(count, results, hr);
3508 return hr;
3511 /* init from file */
3512 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3513 if (FAILED(hr))
3515 init_multi_qi(count, results, hr);
3516 IUnknown_Release(unk);
3517 return hr;
3520 hr = IPersistFile_Load(pf, filename, grfmode);
3521 IPersistFile_Release(pf);
3522 if (SUCCEEDED(hr))
3523 return return_multi_qi(unk, count, results, FALSE);
3524 else
3526 init_multi_qi(count, results, hr);
3527 IUnknown_Release(unk);
3528 return hr;
3532 /***********************************************************************
3533 * CoGetInstanceFromIStorage [OLE32.@]
3535 HRESULT WINAPI CoGetInstanceFromIStorage(
3536 COSERVERINFO *server_info,
3537 CLSID *rclsid,
3538 IUnknown *outer,
3539 DWORD cls_context,
3540 IStorage *storage,
3541 DWORD count,
3542 MULTI_QI *results
3545 IPersistStorage *ps = NULL;
3546 IUnknown* unk = NULL;
3547 STATSTG stat;
3548 HRESULT hr;
3550 if (count == 0 || !results || !storage)
3551 return E_INVALIDARG;
3553 if (server_info)
3554 FIXME("() non-NULL server_info not supported\n");
3556 init_multi_qi(count, results, E_NOINTERFACE);
3558 /* optionally get CLSID from a file */
3559 if (!rclsid)
3561 memset(&stat.clsid, 0, sizeof(stat.clsid));
3562 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3563 if (FAILED(hr))
3565 ERR("failed to get CLSID from a file\n");
3566 return hr;
3569 rclsid = &stat.clsid;
3572 hr = CoCreateInstance(rclsid,
3573 outer,
3574 cls_context,
3575 &IID_IUnknown,
3576 (void**)&unk);
3578 if (hr != S_OK)
3579 return hr;
3581 /* init from IStorage */
3582 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3583 if (FAILED(hr))
3584 ERR("failed to get IPersistStorage\n");
3586 if (ps)
3588 IPersistStorage_Load(ps, storage);
3589 IPersistStorage_Release(ps);
3592 return return_multi_qi(unk, count, results, FALSE);
3595 /***********************************************************************
3596 * CoLoadLibrary (OLE32.@)
3598 * Loads a library.
3600 * PARAMS
3601 * lpszLibName [I] Path to library.
3602 * bAutoFree [I] Whether the library should automatically be freed.
3604 * RETURNS
3605 * Success: Handle to loaded library.
3606 * Failure: NULL.
3608 * SEE ALSO
3609 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3611 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3613 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3615 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3618 /***********************************************************************
3619 * CoFreeLibrary [OLE32.@]
3621 * Unloads a library from memory.
3623 * PARAMS
3624 * hLibrary [I] Handle to library to unload.
3626 * RETURNS
3627 * Nothing
3629 * SEE ALSO
3630 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3632 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3634 FreeLibrary(hLibrary);
3638 /***********************************************************************
3639 * CoFreeAllLibraries [OLE32.@]
3641 * Function for backwards compatibility only. Does nothing.
3643 * RETURNS
3644 * Nothing.
3646 * SEE ALSO
3647 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3649 void WINAPI CoFreeAllLibraries(void)
3651 /* NOP */
3654 /***********************************************************************
3655 * CoFreeUnusedLibrariesEx [OLE32.@]
3657 * Frees any previously unused libraries whose delay has expired and marks
3658 * currently unused libraries for unloading. Unused are identified as those that
3659 * return S_OK from their DllCanUnloadNow function.
3661 * PARAMS
3662 * dwUnloadDelay [I] Unload delay in milliseconds.
3663 * dwReserved [I] Reserved. Set to 0.
3665 * RETURNS
3666 * Nothing.
3668 * SEE ALSO
3669 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3671 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3673 struct apartment *apt = COM_CurrentApt();
3674 if (!apt)
3676 ERR("apartment not initialised\n");
3677 return;
3680 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3683 /***********************************************************************
3684 * CoFreeUnusedLibraries [OLE32.@]
3686 * Frees any unused libraries. Unused are identified as those that return
3687 * S_OK from their DllCanUnloadNow function.
3689 * RETURNS
3690 * Nothing.
3692 * SEE ALSO
3693 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3695 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3697 CoFreeUnusedLibrariesEx(INFINITE, 0);
3700 /***********************************************************************
3701 * CoFileTimeNow [OLE32.@]
3703 * Retrieves the current time in FILETIME format.
3705 * PARAMS
3706 * lpFileTime [O] The current time.
3708 * RETURNS
3709 * S_OK.
3711 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3713 GetSystemTimeAsFileTime( lpFileTime );
3714 return S_OK;
3717 /******************************************************************************
3718 * CoLockObjectExternal [OLE32.@]
3720 * Increments or decrements the external reference count of a stub object.
3722 * PARAMS
3723 * pUnk [I] Stub object.
3724 * fLock [I] If TRUE then increments the external ref-count,
3725 * otherwise decrements.
3726 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3727 * calling CoDisconnectObject.
3729 * RETURNS
3730 * Success: S_OK.
3731 * Failure: HRESULT code.
3733 * NOTES
3734 * If fLock is TRUE and an object is passed in that doesn't have a stub
3735 * manager then a new stub manager is created for the object.
3737 HRESULT WINAPI CoLockObjectExternal(
3738 LPUNKNOWN pUnk,
3739 BOOL fLock,
3740 BOOL fLastUnlockReleases)
3742 struct stub_manager *stubmgr;
3743 struct apartment *apt;
3745 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3746 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3748 if (!(apt = apartment_get_current_or_mta()))
3750 ERR("apartment not initialised\n");
3751 return CO_E_NOTINITIALIZED;
3754 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3755 if (!stubmgr)
3757 WARN("stub object not found %p\n", pUnk);
3758 /* Note: native is pretty broken here because it just silently
3759 * fails, without returning an appropriate error code, making apps
3760 * think that the object was disconnected, when it actually wasn't */
3761 apartment_release(apt);
3762 return S_OK;
3765 if (fLock)
3766 stub_manager_ext_addref(stubmgr, 1, FALSE);
3767 else
3768 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3770 stub_manager_int_release(stubmgr);
3771 apartment_release(apt);
3772 return S_OK;
3775 /***********************************************************************
3776 * CoInitializeWOW (OLE32.@)
3778 * WOW equivalent of CoInitialize?
3780 * PARAMS
3781 * x [I] Unknown.
3782 * y [I] Unknown.
3784 * RETURNS
3785 * Unknown.
3787 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3789 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3790 return 0;
3793 /***********************************************************************
3794 * CoGetState [OLE32.@]
3796 * Retrieves the thread state object previously stored by CoSetState().
3798 * PARAMS
3799 * ppv [I] Address where pointer to object will be stored.
3801 * RETURNS
3802 * Success: S_OK.
3803 * Failure: E_OUTOFMEMORY.
3805 * NOTES
3806 * Crashes on all invalid ppv addresses, including NULL.
3807 * If the function returns a non-NULL object then the caller must release its
3808 * reference on the object when the object is no longer required.
3810 * SEE ALSO
3811 * CoSetState().
3813 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3815 struct oletls *info = COM_CurrentInfo();
3816 if (!info) return E_OUTOFMEMORY;
3818 *ppv = NULL;
3820 if (info->state)
3822 IUnknown_AddRef(info->state);
3823 *ppv = info->state;
3824 TRACE("apt->state=%p\n", info->state);
3827 return S_OK;
3830 /***********************************************************************
3831 * CoSetState [OLE32.@]
3833 * Sets the thread state object.
3835 * PARAMS
3836 * pv [I] Pointer to state object to be stored.
3838 * NOTES
3839 * The system keeps a reference on the object while the object stored.
3841 * RETURNS
3842 * Success: S_OK.
3843 * Failure: E_OUTOFMEMORY.
3845 HRESULT WINAPI CoSetState(IUnknown * pv)
3847 struct oletls *info = COM_CurrentInfo();
3848 if (!info) return E_OUTOFMEMORY;
3850 if (pv) IUnknown_AddRef(pv);
3852 if (info->state)
3854 TRACE("-- release %p now\n", info->state);
3855 IUnknown_Release(info->state);
3858 info->state = pv;
3860 return S_OK;
3864 /******************************************************************************
3865 * CoTreatAsClass [OLE32.@]
3867 * Sets the TreatAs value of a class.
3869 * PARAMS
3870 * clsidOld [I] Class to set TreatAs value on.
3871 * clsidNew [I] The class the clsidOld should be treated as.
3873 * RETURNS
3874 * Success: S_OK.
3875 * Failure: HRESULT code.
3877 * SEE ALSO
3878 * CoGetTreatAsClass
3880 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3882 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3883 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3884 HKEY hkey = NULL;
3885 WCHAR szClsidNew[CHARS_IN_GUID];
3886 HRESULT res = S_OK;
3887 WCHAR auto_treat_as[CHARS_IN_GUID];
3888 LONG auto_treat_as_size = sizeof(auto_treat_as);
3889 CLSID id;
3891 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3892 if (FAILED(res))
3893 goto done;
3895 if (IsEqualGUID( clsidOld, clsidNew ))
3897 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3898 CLSIDFromString(auto_treat_as, &id) == S_OK)
3900 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3902 res = REGDB_E_WRITEREGDB;
3903 goto done;
3906 else
3908 if(RegDeleteKeyW(hkey, wszTreatAs))
3909 res = REGDB_E_WRITEREGDB;
3910 goto done;
3913 else
3915 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3916 RegDeleteKeyW(hkey, wszTreatAs);
3917 }else{
3918 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAY_SIZE(szClsidNew))){
3919 WARN("StringFromGUID2 failed\n");
3920 res = E_FAIL;
3921 goto done;
3924 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3925 WARN("RegSetValue failed\n");
3926 res = REGDB_E_WRITEREGDB;
3927 goto done;
3932 done:
3933 if (hkey) RegCloseKey(hkey);
3934 return res;
3937 /******************************************************************************
3938 * CoGetTreatAsClass [OLE32.@]
3940 * Gets the TreatAs value of a class.
3942 * PARAMS
3943 * clsidOld [I] Class to get the TreatAs value of.
3944 * clsidNew [I] The class the clsidOld should be treated as.
3946 * RETURNS
3947 * Success: S_OK.
3948 * Failure: HRESULT code.
3950 * SEE ALSO
3951 * CoSetTreatAsClass
3953 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3955 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3956 HKEY hkey = NULL;
3957 WCHAR szClsidNew[CHARS_IN_GUID];
3958 HRESULT res = S_OK;
3959 LONG len = sizeof(szClsidNew);
3961 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3963 if (!clsidOld || !clsidNew)
3964 return E_INVALIDARG;
3966 *clsidNew = *clsidOld; /* copy over old value */
3968 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3969 if (FAILED(res))
3971 res = S_FALSE;
3972 goto done;
3974 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3976 res = S_FALSE;
3977 goto done;
3979 res = CLSIDFromString(szClsidNew,clsidNew);
3980 if (FAILED(res))
3981 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3982 done:
3983 if (hkey) RegCloseKey(hkey);
3984 return res;
3987 /******************************************************************************
3988 * CoGetCurrentProcess [OLE32.@]
3990 * Gets the current process ID.
3992 * RETURNS
3993 * The current process ID.
3995 * NOTES
3996 * Is DWORD really the correct return type for this function?
3998 DWORD WINAPI CoGetCurrentProcess(void)
4000 return GetCurrentProcessId();
4003 /***********************************************************************
4004 * CoGetCurrentLogicalThreadId [OLE32.@]
4006 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
4008 TRACE("(%p)\n", id);
4010 if (!id)
4011 return E_INVALIDARG;
4013 *id = COM_CurrentCausalityId();
4014 return S_OK;
4017 /******************************************************************************
4018 * CoRegisterMessageFilter [OLE32.@]
4020 * Registers a message filter.
4022 * PARAMS
4023 * lpMessageFilter [I] Pointer to interface.
4024 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
4026 * RETURNS
4027 * Success: S_OK.
4028 * Failure: HRESULT code.
4030 * NOTES
4031 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
4032 * lpMessageFilter removes the message filter.
4034 * If lplpMessageFilter is not NULL the previous message filter will be
4035 * returned in the memory pointer to this parameter and the caller is
4036 * responsible for releasing the object.
4038 * The current thread be in an apartment otherwise the function will crash.
4040 HRESULT WINAPI CoRegisterMessageFilter(
4041 LPMESSAGEFILTER lpMessageFilter,
4042 LPMESSAGEFILTER *lplpMessageFilter)
4044 struct apartment *apt;
4045 IMessageFilter *lpOldMessageFilter;
4047 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
4049 apt = COM_CurrentApt();
4051 /* can't set a message filter in a multi-threaded apartment */
4052 if (!apt || apt->multi_threaded)
4054 WARN("can't set message filter in MTA or uninitialized apt\n");
4055 return CO_E_NOT_SUPPORTED;
4058 if (lpMessageFilter)
4059 IMessageFilter_AddRef(lpMessageFilter);
4061 EnterCriticalSection(&apt->cs);
4063 lpOldMessageFilter = apt->filter;
4064 apt->filter = lpMessageFilter;
4066 LeaveCriticalSection(&apt->cs);
4068 if (lplpMessageFilter)
4069 *lplpMessageFilter = lpOldMessageFilter;
4070 else if (lpOldMessageFilter)
4071 IMessageFilter_Release(lpOldMessageFilter);
4073 return S_OK;
4076 /***********************************************************************
4077 * CoIsOle1Class [OLE32.@]
4079 * Determines whether the specified class an OLE v1 class.
4081 * PARAMS
4082 * clsid [I] Class to test.
4084 * RETURNS
4085 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
4087 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
4089 FIXME("%s\n", debugstr_guid(clsid));
4090 return FALSE;
4093 /***********************************************************************
4094 * IsEqualGUID [OLE32.@]
4096 * Compares two Unique Identifiers.
4098 * PARAMS
4099 * rguid1 [I] The first GUID to compare.
4100 * rguid2 [I] The other GUID to compare.
4102 * RETURNS
4103 * TRUE if equal
4105 #undef IsEqualGUID
4106 BOOL WINAPI IsEqualGUID(
4107 REFGUID rguid1,
4108 REFGUID rguid2)
4110 return !memcmp(rguid1,rguid2,sizeof(GUID));
4113 /***********************************************************************
4114 * CoInitializeSecurity [OLE32.@]
4116 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
4117 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
4118 void* pReserved1, DWORD dwAuthnLevel,
4119 DWORD dwImpLevel, void* pReserved2,
4120 DWORD dwCapabilities, void* pReserved3)
4122 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
4123 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
4124 dwCapabilities, pReserved3);
4125 return S_OK;
4128 /***********************************************************************
4129 * CoSuspendClassObjects [OLE32.@]
4131 * Suspends all registered class objects to prevent further requests coming in
4132 * for those objects.
4134 * RETURNS
4135 * Success: S_OK.
4136 * Failure: HRESULT code.
4138 HRESULT WINAPI CoSuspendClassObjects(void)
4140 FIXME("\n");
4141 return S_OK;
4144 /***********************************************************************
4145 * CoAddRefServerProcess [OLE32.@]
4147 * Helper function for incrementing the reference count of a local-server
4148 * process.
4150 * RETURNS
4151 * New reference count.
4153 * SEE ALSO
4154 * CoReleaseServerProcess().
4156 ULONG WINAPI CoAddRefServerProcess(void)
4158 ULONG refs;
4160 TRACE("\n");
4162 EnterCriticalSection(&csRegisteredClassList);
4163 refs = ++s_COMServerProcessReferences;
4164 LeaveCriticalSection(&csRegisteredClassList);
4166 TRACE("refs before: %d\n", refs - 1);
4168 return refs;
4171 /***********************************************************************
4172 * CoReleaseServerProcess [OLE32.@]
4174 * Helper function for decrementing the reference count of a local-server
4175 * process.
4177 * RETURNS
4178 * New reference count.
4180 * NOTES
4181 * When reference count reaches 0, this function suspends all registered
4182 * classes so no new connections are accepted.
4184 * SEE ALSO
4185 * CoAddRefServerProcess(), CoSuspendClassObjects().
4187 ULONG WINAPI CoReleaseServerProcess(void)
4189 ULONG refs;
4191 TRACE("\n");
4193 EnterCriticalSection(&csRegisteredClassList);
4195 refs = --s_COMServerProcessReferences;
4196 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4198 LeaveCriticalSection(&csRegisteredClassList);
4200 TRACE("refs after: %d\n", refs);
4202 return refs;
4205 /***********************************************************************
4206 * CoIsHandlerConnected [OLE32.@]
4208 * Determines whether a proxy is connected to a remote stub.
4210 * PARAMS
4211 * pUnk [I] Pointer to object that may or may not be connected.
4213 * RETURNS
4214 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4215 * FALSE otherwise.
4217 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4219 FIXME("%p\n", pUnk);
4221 return TRUE;
4224 /***********************************************************************
4225 * CoAllowSetForegroundWindow [OLE32.@]
4228 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4230 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4231 return S_OK;
4234 /***********************************************************************
4235 * CoQueryProxyBlanket [OLE32.@]
4237 * Retrieves the security settings being used by a proxy.
4239 * PARAMS
4240 * pProxy [I] Pointer to the proxy object.
4241 * pAuthnSvc [O] The type of authentication service.
4242 * pAuthzSvc [O] The type of authorization service.
4243 * ppServerPrincName [O] Optional. The server prinicple name.
4244 * pAuthnLevel [O] The authentication level.
4245 * pImpLevel [O] The impersonation level.
4246 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4247 * pCapabilities [O] Flags affecting the security behaviour.
4249 * RETURNS
4250 * Success: S_OK.
4251 * Failure: HRESULT code.
4253 * SEE ALSO
4254 * CoCopyProxy, CoSetProxyBlanket.
4256 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4257 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4258 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4260 IClientSecurity *pCliSec;
4261 HRESULT hr;
4263 TRACE("%p\n", pProxy);
4265 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4266 if (SUCCEEDED(hr))
4268 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4269 pAuthzSvc, ppServerPrincName,
4270 pAuthnLevel, pImpLevel, ppAuthInfo,
4271 pCapabilities);
4272 IClientSecurity_Release(pCliSec);
4275 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4276 return hr;
4279 /***********************************************************************
4280 * CoSetProxyBlanket [OLE32.@]
4282 * Sets the security settings for a proxy.
4284 * PARAMS
4285 * pProxy [I] Pointer to the proxy object.
4286 * AuthnSvc [I] The type of authentication service.
4287 * AuthzSvc [I] The type of authorization service.
4288 * pServerPrincName [I] The server prinicple name.
4289 * AuthnLevel [I] The authentication level.
4290 * ImpLevel [I] The impersonation level.
4291 * pAuthInfo [I] Information specific to the authorization/authentication service.
4292 * Capabilities [I] Flags affecting the security behaviour.
4294 * RETURNS
4295 * Success: S_OK.
4296 * Failure: HRESULT code.
4298 * SEE ALSO
4299 * CoQueryProxyBlanket, CoCopyProxy.
4301 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4302 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4303 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4305 IClientSecurity *pCliSec;
4306 HRESULT hr;
4308 TRACE("%p\n", pProxy);
4310 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4311 if (SUCCEEDED(hr))
4313 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4314 AuthzSvc, pServerPrincName,
4315 AuthnLevel, ImpLevel, pAuthInfo,
4316 Capabilities);
4317 IClientSecurity_Release(pCliSec);
4320 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4321 return hr;
4324 /***********************************************************************
4325 * CoCopyProxy [OLE32.@]
4327 * Copies a proxy.
4329 * PARAMS
4330 * pProxy [I] Pointer to the proxy object.
4331 * ppCopy [O] Copy of the proxy.
4333 * RETURNS
4334 * Success: S_OK.
4335 * Failure: HRESULT code.
4337 * SEE ALSO
4338 * CoQueryProxyBlanket, CoSetProxyBlanket.
4340 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4342 IClientSecurity *pCliSec;
4343 HRESULT hr;
4345 TRACE("%p\n", pProxy);
4347 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4348 if (SUCCEEDED(hr))
4350 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4351 IClientSecurity_Release(pCliSec);
4354 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4355 return hr;
4359 /***********************************************************************
4360 * CoGetCallContext [OLE32.@]
4362 * Gets the context of the currently executing server call in the current
4363 * thread.
4365 * PARAMS
4366 * riid [I] Context interface to return.
4367 * ppv [O] Pointer to memory that will receive the context on return.
4369 * RETURNS
4370 * Success: S_OK.
4371 * Failure: HRESULT code.
4373 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4375 struct oletls *info = COM_CurrentInfo();
4377 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4379 if (!info)
4380 return E_OUTOFMEMORY;
4382 if (!info->call_state)
4383 return RPC_E_CALL_COMPLETE;
4385 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4388 /***********************************************************************
4389 * CoSwitchCallContext [OLE32.@]
4391 * Switches the context of the currently executing server call in the current
4392 * thread.
4394 * PARAMS
4395 * pObject [I] Pointer to new context object
4396 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4398 * RETURNS
4399 * Success: S_OK.
4400 * Failure: HRESULT code.
4402 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4404 struct oletls *info = COM_CurrentInfo();
4406 TRACE("(%p, %p)\n", pObject, ppOldObject);
4408 if (!info)
4409 return E_OUTOFMEMORY;
4411 *ppOldObject = info->call_state;
4412 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4414 return S_OK;
4417 /***********************************************************************
4418 * CoQueryClientBlanket [OLE32.@]
4420 * Retrieves the authentication information about the client of the currently
4421 * executing server call in the current thread.
4423 * PARAMS
4424 * pAuthnSvc [O] Optional. The type of authentication service.
4425 * pAuthzSvc [O] Optional. The type of authorization service.
4426 * pServerPrincName [O] Optional. The server prinicple name.
4427 * pAuthnLevel [O] Optional. The authentication level.
4428 * pImpLevel [O] Optional. The impersonation level.
4429 * pPrivs [O] Optional. Information about the privileges of the client.
4430 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4432 * RETURNS
4433 * Success: S_OK.
4434 * Failure: HRESULT code.
4436 * SEE ALSO
4437 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4439 HRESULT WINAPI CoQueryClientBlanket(
4440 DWORD *pAuthnSvc,
4441 DWORD *pAuthzSvc,
4442 OLECHAR **pServerPrincName,
4443 DWORD *pAuthnLevel,
4444 DWORD *pImpLevel,
4445 RPC_AUTHZ_HANDLE *pPrivs,
4446 DWORD *pCapabilities)
4448 IServerSecurity *pSrvSec;
4449 HRESULT hr;
4451 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4452 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4453 pPrivs, pCapabilities);
4455 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4456 if (SUCCEEDED(hr))
4458 hr = IServerSecurity_QueryBlanket(
4459 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4460 pImpLevel, pPrivs, pCapabilities);
4461 IServerSecurity_Release(pSrvSec);
4464 return hr;
4467 /***********************************************************************
4468 * CoImpersonateClient [OLE32.@]
4470 * Impersonates the client of the currently executing server call in the
4471 * current thread.
4473 * PARAMS
4474 * None.
4476 * RETURNS
4477 * Success: S_OK.
4478 * Failure: HRESULT code.
4480 * NOTES
4481 * If this function fails then the current thread will not be impersonating
4482 * the client and all actions will take place on behalf of the server.
4483 * Therefore, it is important to check the return value from this function.
4485 * SEE ALSO
4486 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4488 HRESULT WINAPI CoImpersonateClient(void)
4490 IServerSecurity *pSrvSec;
4491 HRESULT hr;
4493 TRACE("\n");
4495 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4496 if (SUCCEEDED(hr))
4498 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4499 IServerSecurity_Release(pSrvSec);
4502 return hr;
4505 /***********************************************************************
4506 * CoRevertToSelf [OLE32.@]
4508 * Ends the impersonation of the client of the currently executing server
4509 * call in the current thread.
4511 * PARAMS
4512 * None.
4514 * RETURNS
4515 * Success: S_OK.
4516 * Failure: HRESULT code.
4518 * SEE ALSO
4519 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4521 HRESULT WINAPI CoRevertToSelf(void)
4523 IServerSecurity *pSrvSec;
4524 HRESULT hr;
4526 TRACE("\n");
4528 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4529 if (SUCCEEDED(hr))
4531 hr = IServerSecurity_RevertToSelf(pSrvSec);
4532 IServerSecurity_Release(pSrvSec);
4535 return hr;
4538 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4540 /* first try to retrieve messages for incoming COM calls to the apartment window */
4541 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4542 /* next retrieve other messages necessary for the app to remain responsive */
4543 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4544 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4547 /***********************************************************************
4548 * CoWaitForMultipleHandles [OLE32.@]
4550 * Waits for one or more handles to become signaled.
4552 * PARAMS
4553 * dwFlags [I] Flags. See notes.
4554 * dwTimeout [I] Timeout in milliseconds.
4555 * cHandles [I] Number of handles pointed to by pHandles.
4556 * pHandles [I] Handles to wait for.
4557 * lpdwindex [O] Index of handle that was signaled.
4559 * RETURNS
4560 * Success: S_OK.
4561 * Failure: RPC_S_CALLPENDING on timeout.
4563 * NOTES
4565 * The dwFlags parameter can be zero or more of the following:
4566 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4567 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4569 * SEE ALSO
4570 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4572 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4573 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4575 HRESULT hr = S_OK;
4576 DWORD start_time = GetTickCount();
4577 APARTMENT *apt = COM_CurrentApt();
4578 BOOL message_loop = apt && !apt->multi_threaded;
4579 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4580 BOOL post_quit = FALSE;
4581 UINT exit_code;
4583 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4584 pHandles, lpdwindex);
4586 if (!lpdwindex)
4587 return E_INVALIDARG;
4589 *lpdwindex = 0;
4591 if (!pHandles)
4592 return E_INVALIDARG;
4594 if (!cHandles)
4595 return RPC_E_NO_SYNC;
4597 while (TRUE)
4599 DWORD now = GetTickCount();
4600 DWORD res;
4602 if (now - start_time > dwTimeout)
4604 hr = RPC_S_CALLPENDING;
4605 break;
4608 if (message_loop)
4610 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4611 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4613 TRACE("waiting for rpc completion or window message\n");
4615 res = WAIT_TIMEOUT;
4617 if (check_apc)
4619 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4620 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4621 check_apc = FALSE;
4624 if (res == WAIT_TIMEOUT)
4625 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4626 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4627 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4629 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4631 MSG msg;
4632 int count = 0;
4634 /* call message filter */
4636 if (COM_CurrentApt()->filter)
4638 PENDINGTYPE pendingtype =
4639 COM_CurrentInfo()->pending_call_count_server ?
4640 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4641 DWORD be_handled = IMessageFilter_MessagePending(
4642 COM_CurrentApt()->filter, 0 /* FIXME */,
4643 now - start_time, pendingtype);
4644 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4645 switch (be_handled)
4647 case PENDINGMSG_CANCELCALL:
4648 WARN("call canceled\n");
4649 hr = RPC_E_CALL_CANCELED;
4650 break;
4651 case PENDINGMSG_WAITNOPROCESS:
4652 case PENDINGMSG_WAITDEFPROCESS:
4653 default:
4654 /* FIXME: MSDN is very vague about the difference
4655 * between WAITNOPROCESS and WAITDEFPROCESS - there
4656 * appears to be none, so it is possibly a left-over
4657 * from the 16-bit world. */
4658 break;
4662 if (!apt->win)
4664 /* If window is NULL on apartment, peek at messages so that it will not trigger
4665 * MsgWaitForMultipleObjects next time. */
4666 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
4668 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4669 * so after processing 100 messages we go back to checking the wait handles */
4670 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4672 if (msg.message == WM_QUIT)
4674 TRACE("received WM_QUIT message\n");
4675 post_quit = TRUE;
4676 exit_code = msg.wParam;
4678 else
4680 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4681 TranslateMessage(&msg);
4682 DispatchMessageW(&msg);
4685 continue;
4688 else
4690 TRACE("waiting for rpc completion\n");
4692 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4693 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4694 (dwFlags & COWAIT_ALERTABLE) != 0);
4697 switch (res)
4699 case WAIT_TIMEOUT:
4700 hr = RPC_S_CALLPENDING;
4701 break;
4702 case WAIT_FAILED:
4703 hr = HRESULT_FROM_WIN32( GetLastError() );
4704 break;
4705 default:
4706 *lpdwindex = res;
4707 break;
4709 break;
4711 if (post_quit) PostQuitMessage(exit_code);
4712 TRACE("-- 0x%08x\n", hr);
4713 return hr;
4717 /***********************************************************************
4718 * CoGetObject [OLE32.@]
4720 * Gets the object named by converting the name to a moniker and binding to it.
4722 * PARAMS
4723 * pszName [I] String representing the object.
4724 * pBindOptions [I] Parameters affecting the binding to the named object.
4725 * riid [I] Interface to bind to on the objecct.
4726 * ppv [O] On output, the interface riid of the object represented
4727 * by pszName.
4729 * RETURNS
4730 * Success: S_OK.
4731 * Failure: HRESULT code.
4733 * SEE ALSO
4734 * MkParseDisplayName.
4736 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4737 REFIID riid, void **ppv)
4739 IBindCtx *pbc;
4740 HRESULT hr;
4742 *ppv = NULL;
4744 hr = CreateBindCtx(0, &pbc);
4745 if (SUCCEEDED(hr))
4747 if (pBindOptions)
4748 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4750 if (SUCCEEDED(hr))
4752 ULONG chEaten;
4753 IMoniker *pmk;
4755 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4756 if (SUCCEEDED(hr))
4758 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4759 IMoniker_Release(pmk);
4763 IBindCtx_Release(pbc);
4765 return hr;
4768 /***********************************************************************
4769 * CoRegisterChannelHook [OLE32.@]
4771 * Registers a process-wide hook that is called during ORPC calls.
4773 * PARAMS
4774 * guidExtension [I] GUID of the channel hook to register.
4775 * pChannelHook [I] Channel hook object to register.
4777 * RETURNS
4778 * Success: S_OK.
4779 * Failure: HRESULT code.
4781 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4783 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4785 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4788 typedef struct Context
4790 IComThreadingInfo IComThreadingInfo_iface;
4791 IContextCallback IContextCallback_iface;
4792 IObjContext IObjContext_iface;
4793 LONG refs;
4794 } Context;
4796 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4798 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4801 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4803 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4806 static inline Context *impl_from_IObjContext( IObjContext *iface )
4808 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4811 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4813 *ppv = NULL;
4815 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4816 IsEqualIID(riid, &IID_IUnknown))
4818 *ppv = &iface->IComThreadingInfo_iface;
4820 else if (IsEqualIID(riid, &IID_IContextCallback))
4822 *ppv = &iface->IContextCallback_iface;
4824 else if (IsEqualIID(riid, &IID_IObjContext))
4826 *ppv = &iface->IObjContext_iface;
4829 if (*ppv)
4831 IUnknown_AddRef((IUnknown*)*ppv);
4832 return S_OK;
4835 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4836 return E_NOINTERFACE;
4839 static ULONG Context_AddRef(Context *This)
4841 return InterlockedIncrement(&This->refs);
4844 static ULONG Context_Release(Context *This)
4846 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4847 releasing context while refcount is at 0 destroys it. */
4848 if (!This->refs)
4850 HeapFree(GetProcessHeap(), 0, This);
4851 return 0;
4854 return InterlockedDecrement(&This->refs);
4857 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4859 Context *This = impl_from_IComThreadingInfo(iface);
4860 return Context_QueryInterface(This, riid, ppv);
4863 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4865 Context *This = impl_from_IComThreadingInfo(iface);
4866 return Context_AddRef(This);
4869 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4871 Context *This = impl_from_IComThreadingInfo(iface);
4872 return Context_Release(This);
4875 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4877 APTTYPEQUALIFIER qualifier;
4879 TRACE("(%p)\n", apttype);
4881 return CoGetApartmentType(apttype, &qualifier);
4884 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4886 APTTYPEQUALIFIER qualifier;
4887 APTTYPE apttype;
4888 HRESULT hr;
4890 hr = CoGetApartmentType(&apttype, &qualifier);
4891 if (FAILED(hr))
4892 return hr;
4894 TRACE("(%p)\n", thdtype);
4896 switch (apttype)
4898 case APTTYPE_STA:
4899 case APTTYPE_MAINSTA:
4900 *thdtype = THDTYPE_PROCESSMESSAGES;
4901 break;
4902 default:
4903 *thdtype = THDTYPE_BLOCKMESSAGES;
4904 break;
4906 return S_OK;
4909 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4911 TRACE("(%p)\n", logical_thread_id);
4912 return CoGetCurrentLogicalThreadId(logical_thread_id);
4915 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4917 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4918 return E_NOTIMPL;
4921 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4923 Context_CTI_QueryInterface,
4924 Context_CTI_AddRef,
4925 Context_CTI_Release,
4926 Context_CTI_GetCurrentApartmentType,
4927 Context_CTI_GetCurrentThreadType,
4928 Context_CTI_GetCurrentLogicalThreadId,
4929 Context_CTI_SetCurrentLogicalThreadId
4932 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4934 Context *This = impl_from_IContextCallback(iface);
4935 return Context_QueryInterface(This, riid, ppv);
4938 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4940 Context *This = impl_from_IContextCallback(iface);
4941 return Context_AddRef(This);
4944 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4946 Context *This = impl_from_IContextCallback(iface);
4947 return Context_Release(This);
4950 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4951 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4953 Context *This = impl_from_IContextCallback(iface);
4955 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4956 return E_NOTIMPL;
4959 static const IContextCallbackVtbl Context_Callback_Vtbl =
4961 Context_CC_QueryInterface,
4962 Context_CC_AddRef,
4963 Context_CC_Release,
4964 Context_CC_ContextCallback
4967 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4969 Context *This = impl_from_IObjContext(iface);
4970 return Context_QueryInterface(This, riid, ppv);
4973 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4975 Context *This = impl_from_IObjContext(iface);
4976 return Context_AddRef(This);
4979 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4981 Context *This = impl_from_IObjContext(iface);
4982 return Context_Release(This);
4985 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4987 Context *This = impl_from_IObjContext(iface);
4989 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4990 return E_NOTIMPL;
4993 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4995 Context *This = impl_from_IObjContext(iface);
4997 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4998 return E_NOTIMPL;
5001 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
5003 Context *This = impl_from_IObjContext(iface);
5005 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
5006 return E_NOTIMPL;
5009 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
5011 Context *This = impl_from_IObjContext(iface);
5013 FIXME("(%p/%p)->(%p)\n", This, iface, props);
5014 return E_NOTIMPL;
5017 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
5019 Context *This = impl_from_IObjContext(iface);
5020 FIXME("(%p/%p)\n", This, iface);
5023 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
5025 Context *This = impl_from_IObjContext(iface);
5026 FIXME("(%p/%p)\n", This, iface);
5029 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
5031 Context *This = impl_from_IObjContext(iface);
5032 FIXME("(%p/%p)\n", This, iface);
5035 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
5037 Context *This = impl_from_IObjContext(iface);
5038 FIXME("(%p/%p)\n", This, iface);
5041 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
5043 Context *This = impl_from_IObjContext(iface);
5044 FIXME("(%p/%p)\n", This, iface);
5047 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
5049 Context *This = impl_from_IObjContext(iface);
5050 FIXME("(%p/%p)\n", This, iface);
5053 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
5055 Context *This = impl_from_IObjContext(iface);
5056 FIXME("(%p/%p)\n", This, iface);
5059 static const IObjContextVtbl Context_Object_Vtbl =
5061 Context_OC_QueryInterface,
5062 Context_OC_AddRef,
5063 Context_OC_Release,
5064 Context_OC_SetProperty,
5065 Context_OC_RemoveProperty,
5066 Context_OC_GetProperty,
5067 Context_OC_EnumContextProps,
5068 Context_OC_Reserved1,
5069 Context_OC_Reserved2,
5070 Context_OC_Reserved3,
5071 Context_OC_Reserved4,
5072 Context_OC_Reserved5,
5073 Context_OC_Reserved6,
5074 Context_OC_Reserved7
5077 /***********************************************************************
5078 * CoGetObjectContext [OLE32.@]
5080 * Retrieves an object associated with the current context (i.e. apartment).
5082 * PARAMS
5083 * riid [I] ID of the interface of the object to retrieve.
5084 * ppv [O] Address where object will be stored on return.
5086 * RETURNS
5087 * Success: S_OK.
5088 * Failure: HRESULT code.
5090 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
5092 IObjContext *context;
5093 HRESULT hr;
5095 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
5097 *ppv = NULL;
5098 hr = CoGetContextToken((ULONG_PTR*)&context);
5099 if (FAILED(hr))
5100 return hr;
5102 return IObjContext_QueryInterface(context, riid, ppv);
5105 /***********************************************************************
5106 * CoGetContextToken [OLE32.@]
5108 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
5110 struct oletls *info = COM_CurrentInfo();
5111 APARTMENT *apt;
5113 TRACE("(%p)\n", token);
5115 if (!info)
5116 return E_OUTOFMEMORY;
5118 if (!(apt = apartment_get_current_or_mta()))
5120 ERR("apartment not initialised\n");
5121 return CO_E_NOTINITIALIZED;
5123 apartment_release(apt);
5125 if (!token)
5126 return E_POINTER;
5128 if (!info->context_token)
5130 Context *context;
5132 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
5133 if (!context)
5134 return E_OUTOFMEMORY;
5136 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
5137 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
5138 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
5139 /* Context token does not take a reference, it's always zero until the
5140 interface is explicitly requested with CoGetObjectContext(). */
5141 context->refs = 0;
5143 info->context_token = &context->IObjContext_iface;
5146 *token = (ULONG_PTR)info->context_token;
5147 TRACE("context_token=%p\n", info->context_token);
5149 return S_OK;
5152 /***********************************************************************
5153 * CoGetDefaultContext [OLE32.@]
5155 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5157 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5158 return E_NOINTERFACE;
5161 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5163 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5164 HKEY hkey;
5165 HRESULT hres;
5167 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5168 if (SUCCEEDED(hres))
5170 struct class_reg_data regdata;
5171 WCHAR dllpath[MAX_PATH+1];
5173 regdata.u.hkey = hkey;
5174 regdata.hkey = TRUE;
5176 if (get_object_dll_path(&regdata, dllpath, ARRAY_SIZE(dllpath)))
5178 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5179 if (!wcsicmp(dllpath, wszOle32))
5181 RegCloseKey(hkey);
5182 return HandlerCF_Create(rclsid, riid, ppv);
5185 else
5186 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5187 RegCloseKey(hkey);
5190 return CLASS_E_CLASSNOTAVAILABLE;
5193 /***********************************************************************
5194 * CoGetApartmentType [OLE32.@]
5196 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5198 struct oletls *info = COM_CurrentInfo();
5199 APARTMENT *apt;
5201 TRACE("(%p, %p)\n", type, qualifier);
5203 if (!type || !qualifier)
5204 return E_INVALIDARG;
5206 if (!info)
5207 return E_OUTOFMEMORY;
5209 if (!info->apt)
5210 *type = APTTYPE_CURRENT;
5211 else if (info->apt->multi_threaded)
5212 *type = APTTYPE_MTA;
5213 else if (info->apt->main)
5214 *type = APTTYPE_MAINSTA;
5215 else
5216 *type = APTTYPE_STA;
5218 *qualifier = APTTYPEQUALIFIER_NONE;
5220 if (!info->apt && (apt = apartment_find_mta()))
5222 apartment_release(apt);
5223 *type = APTTYPE_MTA;
5224 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
5227 return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5230 /***********************************************************************
5231 * CoDisableCallCancellation [OLE32.@]
5233 HRESULT WINAPI CoDisableCallCancellation(void *reserved)
5235 FIXME("(%p): stub\n", reserved);
5237 return E_NOTIMPL;
5240 /***********************************************************************
5241 * CoEnableCallCancellation [OLE32.@]
5243 HRESULT WINAPI CoEnableCallCancellation(void *reserved)
5245 FIXME("(%p): stub\n", reserved);
5247 return E_NOTIMPL;
5250 /***********************************************************************
5251 * CoRegisterSurrogate [OLE32.@]
5253 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5255 FIXME("(%p): stub\n", surrogate);
5257 return E_NOTIMPL;
5260 /***********************************************************************
5261 * CoRegisterSurrogateEx [OLE32.@]
5263 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5265 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5267 return E_NOTIMPL;
5270 typedef struct {
5271 IGlobalOptions IGlobalOptions_iface;
5272 LONG ref;
5273 } GlobalOptions;
5275 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5277 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5280 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5282 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5284 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5286 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5288 *ppv = iface;
5290 else
5292 *ppv = NULL;
5293 return E_NOINTERFACE;
5296 IUnknown_AddRef((IUnknown*)*ppv);
5297 return S_OK;
5300 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5302 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5303 LONG ref = InterlockedIncrement(&This->ref);
5305 TRACE("(%p) ref=%d\n", This, ref);
5307 return ref;
5310 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5312 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5313 LONG ref = InterlockedDecrement(&This->ref);
5315 TRACE("(%p) ref=%d\n", This, ref);
5317 if (!ref)
5318 heap_free(This);
5320 return ref;
5323 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5325 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5326 FIXME("(%p)->(%u %lx)\n", This, property, value);
5327 return S_OK;
5330 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5332 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5333 FIXME("(%p)->(%u %p)\n", This, property, value);
5334 return E_NOTIMPL;
5337 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5338 GlobalOptions_QueryInterface,
5339 GlobalOptions_AddRef,
5340 GlobalOptions_Release,
5341 GlobalOptions_Set,
5342 GlobalOptions_Query
5345 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5347 GlobalOptions *global_options;
5348 HRESULT hres;
5350 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5352 if (outer)
5353 return E_INVALIDARG;
5355 global_options = heap_alloc(sizeof(*global_options));
5356 if (!global_options)
5357 return E_OUTOFMEMORY;
5358 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5359 global_options->ref = 1;
5361 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5362 IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5363 return hres;
5366 /***********************************************************************
5367 * DllMain (OLE32.@)
5369 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5371 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5373 switch(fdwReason) {
5374 case DLL_PROCESS_ATTACH:
5375 hProxyDll = hinstDLL;
5376 break;
5378 case DLL_PROCESS_DETACH:
5379 if (reserved) break;
5380 release_std_git();
5381 if(apt_win_class)
5382 UnregisterClassW( (const WCHAR*)MAKEINTATOM(apt_win_class), hProxyDll );
5383 RPC_UnregisterAllChannelHooks();
5384 COMPOBJ_DllList_Free();
5385 DeleteCriticalSection(&csRegisteredClassList);
5386 DeleteCriticalSection(&csApartment);
5387 break;
5389 case DLL_THREAD_DETACH:
5390 COM_TlsDestroy();
5391 break;
5393 return TRUE;
5396 /***********************************************************************
5397 * DllRegisterServer (OLE32.@)
5399 HRESULT WINAPI DllRegisterServer(void)
5401 return OLE32_DllRegisterServer();
5404 /***********************************************************************
5405 * DllUnregisterServer (OLE32.@)
5407 HRESULT WINAPI DllUnregisterServer(void)
5409 return OLE32_DllUnregisterServer();