kernel32/tests: Add a test to check some fields in fake dlls.
[wine.git] / dlls / ole32 / compobj.c
bloba28ff799244e3a6efe5e01258c236e5c7aa95f87
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
49 #include "ntstatus.h"
50 #define WIN32_NO_STATUS
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winuser.h"
56 #define USE_COM_CONTEXT_DEF
57 #include "objbase.h"
58 #include "ole2.h"
59 #include "ole2ver.h"
60 #include "ctxtcall.h"
61 #include "dde.h"
62 #include "servprov.h"
64 #include "initguid.h"
65 #include "compobj_private.h"
66 #include "moniker.h"
68 #include "wine/unicode.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(ole);
73 /****************************************************************************
74 * This section defines variables internal to the COM module.
77 static APARTMENT *MTA; /* protected by csApartment */
78 static APARTMENT *MainApartment; /* the first STA apartment */
79 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
81 static CRITICAL_SECTION csApartment;
82 static CRITICAL_SECTION_DEBUG critsect_debug =
84 0, 0, &csApartment,
85 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
88 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
90 enum comclass_threadingmodel
92 ThreadingModel_Apartment = 1,
93 ThreadingModel_Free = 2,
94 ThreadingModel_No = 3,
95 ThreadingModel_Both = 4,
96 ThreadingModel_Neutral = 5
99 enum comclass_miscfields
101 MiscStatus = 1,
102 MiscStatusIcon = 2,
103 MiscStatusContent = 4,
104 MiscStatusThumbnail = 8,
105 MiscStatusDocPrint = 16
108 struct comclassredirect_data
110 ULONG size;
111 BYTE res;
112 BYTE miscmask;
113 BYTE res1[2];
114 DWORD model;
115 GUID clsid;
116 GUID alias;
117 GUID clsid2;
118 GUID tlbid;
119 ULONG name_len;
120 ULONG name_offset;
121 ULONG progid_len;
122 ULONG progid_offset;
123 ULONG clrdata_len;
124 ULONG clrdata_offset;
125 DWORD miscstatus;
126 DWORD miscstatuscontent;
127 DWORD miscstatusthumbnail;
128 DWORD miscstatusicon;
129 DWORD miscstatusdocprint;
132 struct ifacepsredirect_data
134 ULONG size;
135 DWORD mask;
136 GUID iid;
137 ULONG nummethods;
138 GUID tlbid;
139 GUID base;
140 ULONG name_len;
141 ULONG name_offset;
144 struct progidredirect_data
146 ULONG size;
147 DWORD reserved;
148 ULONG clsid_offset;
151 struct class_reg_data
153 union
155 struct
157 struct comclassredirect_data *data;
158 void *section;
159 HANDLE hactctx;
160 } actctx;
161 HKEY hkey;
162 } u;
163 BOOL hkey;
166 struct registered_psclsid
168 struct list entry;
169 IID iid;
170 CLSID clsid;
173 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list);
175 static CRITICAL_SECTION cs_registered_psclsid_list;
176 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
178 0, 0, &cs_registered_psclsid_list,
179 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
180 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
182 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
185 * This is a marshallable object exposing registered local servers.
186 * IServiceProvider is used only because it happens meet requirements
187 * and already has proxy/stub code. If more functionality is needed,
188 * a custom interface may be used instead.
190 struct LocalServer
192 IServiceProvider IServiceProvider_iface;
193 LONG ref;
194 APARTMENT *apt;
195 IStream *marshal_stream;
199 * This lock count counts the number of times CoInitialize is called. It is
200 * decreased every time CoUninitialize is called. When it hits 0, the COM
201 * libraries are freed
203 static LONG s_COMLockCount = 0;
204 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
205 static LONG s_COMServerProcessReferences = 0;
208 * This linked list contains the list of registered class objects. These
209 * are mostly used to register the factories for out-of-proc servers of OLE
210 * objects.
212 * TODO: Make this data structure aware of inter-process communication. This
213 * means that parts of this will be exported to rpcss.
215 typedef struct tagRegisteredClass
217 struct list entry;
218 CLSID classIdentifier;
219 OXID apartment_id;
220 LPUNKNOWN classObject;
221 DWORD runContext;
222 DWORD connectFlags;
223 DWORD dwCookie;
224 void *RpcRegistration;
225 } RegisteredClass;
227 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
229 static CRITICAL_SECTION csRegisteredClassList;
230 static CRITICAL_SECTION_DEBUG class_cs_debug =
232 0, 0, &csRegisteredClassList,
233 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
234 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
236 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
238 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
240 switch (aspect)
242 case DVASPECT_CONTENT:
243 return MiscStatusContent;
244 case DVASPECT_THUMBNAIL:
245 return MiscStatusThumbnail;
246 case DVASPECT_ICON:
247 return MiscStatusIcon;
248 case DVASPECT_DOCPRINT:
249 return MiscStatusDocPrint;
250 default:
251 return MiscStatus;
255 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
257 ACTCTX_SECTION_KEYED_DATA data;
259 data.cbSize = sizeof(data);
260 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
261 clsid, &data))
263 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
264 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
266 if (!(comclass->miscmask & misc))
268 if (!(comclass->miscmask & MiscStatus))
270 *status = 0;
271 return TRUE;
273 misc = MiscStatus;
276 switch (misc)
278 case MiscStatus:
279 *status = comclass->miscstatus;
280 break;
281 case MiscStatusIcon:
282 *status = comclass->miscstatusicon;
283 break;
284 case MiscStatusContent:
285 *status = comclass->miscstatuscontent;
286 break;
287 case MiscStatusThumbnail:
288 *status = comclass->miscstatusthumbnail;
289 break;
290 case MiscStatusDocPrint:
291 *status = comclass->miscstatusdocprint;
292 break;
293 default:
297 return TRUE;
299 else
300 return FALSE;
303 /* wrapper for NtCreateKey that creates the key recursively if necessary */
304 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
306 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
308 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
310 HANDLE subkey, root = attr->RootDirectory;
311 WCHAR *buffer = attr->ObjectName->Buffer;
312 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
313 UNICODE_STRING str;
315 while (i < len && buffer[i] != '\\') i++;
316 if (i == len) return status;
318 attrs = attr->Attributes;
319 attr->ObjectName = &str;
321 while (i < len)
323 str.Buffer = buffer + pos;
324 str.Length = (i - pos) * sizeof(WCHAR);
325 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
326 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
327 if (status) return status;
328 attr->RootDirectory = subkey;
329 while (i < len && buffer[i] == '\\') i++;
330 pos = i;
331 while (i < len && buffer[i] != '\\') i++;
333 str.Buffer = buffer + pos;
334 str.Length = (i - pos) * sizeof(WCHAR);
335 attr->Attributes = attrs;
336 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
337 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
339 return status;
342 static const WCHAR classes_rootW[] =
343 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
344 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
346 static HKEY classes_root_hkey;
348 /* create the special HKEY_CLASSES_ROOT key */
349 static HKEY create_classes_root_hkey(DWORD access)
351 HKEY hkey, ret = 0;
352 OBJECT_ATTRIBUTES attr;
353 UNICODE_STRING name;
355 attr.Length = sizeof(attr);
356 attr.RootDirectory = 0;
357 attr.ObjectName = &name;
358 attr.Attributes = 0;
359 attr.SecurityDescriptor = NULL;
360 attr.SecurityQualityOfService = NULL;
361 RtlInitUnicodeString( &name, classes_rootW );
362 if (create_key( &hkey, access, &attr )) return 0;
363 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
365 if (!(access & KEY_WOW64_64KEY))
367 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
368 ret = hkey;
369 else
370 NtClose( hkey ); /* somebody beat us to it */
372 else
373 ret = hkey;
374 return ret;
377 /* map the hkey from special root to normal key if necessary */
378 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
380 HKEY ret = hkey;
381 const BOOL is_win64 = sizeof(void*) > sizeof(int);
382 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
384 if (hkey == HKEY_CLASSES_ROOT &&
385 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
386 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
387 if (force_wow32 && ret && ret == classes_root_hkey)
389 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
390 access &= ~KEY_WOW64_32KEY;
391 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
392 return 0;
393 ret = hkey;
396 return ret;
399 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
401 OBJECT_ATTRIBUTES attr;
402 UNICODE_STRING nameW;
404 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
406 attr.Length = sizeof(attr);
407 attr.RootDirectory = hkey;
408 attr.ObjectName = &nameW;
409 attr.Attributes = 0;
410 attr.SecurityDescriptor = NULL;
411 attr.SecurityQualityOfService = NULL;
412 RtlInitUnicodeString( &nameW, name );
414 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
417 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
419 OBJECT_ATTRIBUTES attr;
420 UNICODE_STRING nameW;
422 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
424 attr.Length = sizeof(attr);
425 attr.RootDirectory = hkey;
426 attr.ObjectName = &nameW;
427 attr.Attributes = 0;
428 attr.SecurityDescriptor = NULL;
429 attr.SecurityQualityOfService = NULL;
430 RtlInitUnicodeString( &nameW, name );
432 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
435 /*****************************************************************************
436 * This section contains OpenDllList definitions
438 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
439 * other functions that do LoadLibrary _without_ giving back a HMODULE.
440 * Without this list these handles would never be freed.
442 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
443 * next unload-call but not before 600 sec.
446 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
447 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
449 typedef struct tagOpenDll
451 LONG refs;
452 LPWSTR library_name;
453 HANDLE library;
454 DllGetClassObjectFunc DllGetClassObject;
455 DllCanUnloadNowFunc DllCanUnloadNow;
456 struct list entry;
457 } OpenDll;
459 static struct list openDllList = LIST_INIT(openDllList);
461 static CRITICAL_SECTION csOpenDllList;
462 static CRITICAL_SECTION_DEBUG dll_cs_debug =
464 0, 0, &csOpenDllList,
465 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
466 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
468 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
470 struct apartment_loaded_dll
472 struct list entry;
473 OpenDll *dll;
474 DWORD unload_time;
475 BOOL multi_threaded;
478 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};
480 static ATOM apt_win_class;
482 /*****************************************************************************
483 * This section contains OpenDllList implementation
486 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
488 OpenDll *ptr;
489 OpenDll *ret = NULL;
490 EnterCriticalSection(&csOpenDllList);
491 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
493 if (!strcmpiW(library_name, ptr->library_name) &&
494 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
496 ret = ptr;
497 break;
500 LeaveCriticalSection(&csOpenDllList);
501 return ret;
504 /* caller must ensure that library_name is not already in the open dll list */
505 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
507 OpenDll *entry;
508 int len;
509 HRESULT hr = S_OK;
510 HANDLE hLibrary;
511 DllCanUnloadNowFunc DllCanUnloadNow;
512 DllGetClassObjectFunc DllGetClassObject;
514 TRACE("%s\n", debugstr_w(library_name));
516 *ret = COMPOBJ_DllList_Get(library_name);
517 if (*ret) return S_OK;
519 /* do this outside the csOpenDllList to avoid creating a lock dependency on
520 * the loader lock */
521 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
522 if (!hLibrary)
524 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
525 /* failure: DLL could not be loaded */
526 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
529 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
530 /* Note: failing to find DllCanUnloadNow is not a failure */
531 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
532 if (!DllGetClassObject)
534 /* failure: the dll did not export DllGetClassObject */
535 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
536 FreeLibrary(hLibrary);
537 return CO_E_DLLNOTFOUND;
540 EnterCriticalSection( &csOpenDllList );
542 *ret = COMPOBJ_DllList_Get(library_name);
543 if (*ret)
545 /* another caller to this function already added the dll while we
546 * weren't in the critical section */
547 FreeLibrary(hLibrary);
549 else
551 len = strlenW(library_name);
552 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
553 if (entry)
554 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
555 if (entry && entry->library_name)
557 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
558 entry->library = hLibrary;
559 entry->refs = 1;
560 entry->DllCanUnloadNow = DllCanUnloadNow;
561 entry->DllGetClassObject = DllGetClassObject;
562 list_add_tail(&openDllList, &entry->entry);
563 *ret = entry;
565 else
567 HeapFree(GetProcessHeap(), 0, entry);
568 hr = E_OUTOFMEMORY;
569 FreeLibrary(hLibrary);
573 LeaveCriticalSection( &csOpenDllList );
575 return hr;
578 /* pass FALSE for free_entry to release a reference without destroying the
579 * entry if it reaches zero or TRUE otherwise */
580 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
582 if (!InterlockedDecrement(&entry->refs) && free_entry)
584 EnterCriticalSection(&csOpenDllList);
585 list_remove(&entry->entry);
586 LeaveCriticalSection(&csOpenDllList);
588 TRACE("freeing %p\n", entry->library);
589 FreeLibrary(entry->library);
591 HeapFree(GetProcessHeap(), 0, entry->library_name);
592 HeapFree(GetProcessHeap(), 0, entry);
596 /* frees memory associated with active dll list */
597 static void COMPOBJ_DllList_Free(void)
599 OpenDll *entry, *cursor2;
600 EnterCriticalSection(&csOpenDllList);
601 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
603 list_remove(&entry->entry);
605 HeapFree(GetProcessHeap(), 0, entry->library_name);
606 HeapFree(GetProcessHeap(), 0, entry);
608 LeaveCriticalSection(&csOpenDllList);
609 DeleteCriticalSection(&csOpenDllList);
612 /******************************************************************************
613 * Manage apartments.
616 static DWORD apartment_addref(struct apartment *apt)
618 DWORD refs = InterlockedIncrement(&apt->refs);
619 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
620 return refs;
623 /* allocates memory and fills in the necessary fields for a new apartment
624 * object. must be called inside apartment cs */
625 static APARTMENT *apartment_construct(DWORD model)
627 APARTMENT *apt;
629 TRACE("creating new apartment, model=%d\n", model);
631 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
632 apt->tid = GetCurrentThreadId();
634 list_init(&apt->proxies);
635 list_init(&apt->stubmgrs);
636 list_init(&apt->loaded_dlls);
637 apt->ipidc = 0;
638 apt->refs = 1;
639 apt->remunk_exported = FALSE;
640 apt->oidc = 1;
641 InitializeCriticalSection(&apt->cs);
642 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
644 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
646 if (apt->multi_threaded)
648 /* FIXME: should be randomly generated by in an RPC call to rpcss */
649 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
651 else
653 /* FIXME: should be randomly generated by in an RPC call to rpcss */
654 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
657 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
659 list_add_head(&apts, &apt->entry);
661 return apt;
664 /* gets and existing apartment if one exists or otherwise creates an apartment
665 * structure which stores OLE apartment-local information and stores a pointer
666 * to it in the thread-local storage */
667 static APARTMENT *apartment_get_or_create(DWORD model)
669 APARTMENT *apt = COM_CurrentApt();
671 if (!apt)
673 if (model & COINIT_APARTMENTTHREADED)
675 EnterCriticalSection(&csApartment);
677 apt = apartment_construct(model);
678 if (!MainApartment)
680 MainApartment = apt;
681 apt->main = TRUE;
682 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
685 LeaveCriticalSection(&csApartment);
687 if (apt->main)
688 apartment_createwindowifneeded(apt);
690 else
692 EnterCriticalSection(&csApartment);
694 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
695 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
696 * in a process */
697 if (MTA)
699 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
700 apartment_addref(MTA);
702 else
703 MTA = apartment_construct(model);
705 apt = MTA;
707 LeaveCriticalSection(&csApartment);
709 COM_CurrentInfo()->apt = apt;
712 return apt;
715 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
717 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
720 /* gets the multi-threaded apartment if it exists. The caller must
721 * release the reference from the apartment as soon as the apartment pointer
722 * is no longer required. */
723 static APARTMENT *apartment_find_mta(void)
725 APARTMENT *apt;
727 EnterCriticalSection(&csApartment);
729 if ((apt = MTA))
730 apartment_addref(apt);
732 LeaveCriticalSection(&csApartment);
734 return apt;
737 /* Return the current apartment if it exists, or, failing that, the MTA. Caller
738 * must free the returned apartment in either case. */
739 APARTMENT *apartment_get_current_or_mta(void)
741 APARTMENT *apt = COM_CurrentApt();
742 if (apt)
744 apartment_addref(apt);
745 return apt;
747 return apartment_find_mta();
750 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
752 list_remove(&curClass->entry);
754 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
755 RPC_StopLocalServer(curClass->RpcRegistration);
757 IUnknown_Release(curClass->classObject);
758 HeapFree(GetProcessHeap(), 0, curClass);
761 static void COM_RevokeAllClasses(const struct apartment *apt)
763 RegisteredClass *curClass, *cursor;
765 EnterCriticalSection( &csRegisteredClassList );
767 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
769 if (curClass->apartment_id == apt->oxid)
770 COM_RevokeRegisteredClassObject(curClass);
773 LeaveCriticalSection( &csRegisteredClassList );
776 static void revoke_registered_psclsids(void)
778 struct registered_psclsid *psclsid, *psclsid2;
780 EnterCriticalSection( &cs_registered_psclsid_list );
782 LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, &registered_psclsid_list, struct registered_psclsid, entry)
784 list_remove(&psclsid->entry);
785 HeapFree(GetProcessHeap(), 0, psclsid);
788 LeaveCriticalSection( &cs_registered_psclsid_list );
791 /******************************************************************************
792 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
795 typedef struct ManualResetEvent {
796 ISynchronize ISynchronize_iface;
797 ISynchronizeHandle ISynchronizeHandle_iface;
798 LONG ref;
799 HANDLE event;
800 } MREImpl;
802 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
804 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
807 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
809 MREImpl *This = impl_from_ISynchronize(iface);
811 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
813 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
814 *ppv = &This->ISynchronize_iface;
815 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
816 *ppv = &This->ISynchronizeHandle_iface;
817 }else {
818 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
819 *ppv = NULL;
820 return E_NOINTERFACE;
823 IUnknown_AddRef((IUnknown*)*ppv);
824 return S_OK;
827 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
829 MREImpl *This = impl_from_ISynchronize(iface);
830 LONG ref = InterlockedIncrement(&This->ref);
831 TRACE("%p - ref %d\n", This, ref);
833 return ref;
836 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
838 MREImpl *This = impl_from_ISynchronize(iface);
839 LONG ref = InterlockedDecrement(&This->ref);
840 TRACE("%p - ref %d\n", This, ref);
842 if(!ref)
844 CloseHandle(This->event);
845 HeapFree(GetProcessHeap(), 0, This);
848 return ref;
851 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
853 MREImpl *This = impl_from_ISynchronize(iface);
854 UINT index;
855 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
856 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
859 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
861 MREImpl *This = impl_from_ISynchronize(iface);
862 TRACE("%p\n", This);
863 SetEvent(This->event);
864 return S_OK;
867 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
869 MREImpl *This = impl_from_ISynchronize(iface);
870 TRACE("%p\n", This);
871 ResetEvent(This->event);
872 return S_OK;
875 static ISynchronizeVtbl vt_ISynchronize = {
876 ISynchronize_fnQueryInterface,
877 ISynchronize_fnAddRef,
878 ISynchronize_fnRelease,
879 ISynchronize_fnWait,
880 ISynchronize_fnSignal,
881 ISynchronize_fnReset
884 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
886 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
889 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
891 MREImpl *This = impl_from_ISynchronizeHandle(iface);
892 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
895 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
897 MREImpl *This = impl_from_ISynchronizeHandle(iface);
898 return ISynchronize_AddRef(&This->ISynchronize_iface);
901 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
903 MREImpl *This = impl_from_ISynchronizeHandle(iface);
904 return ISynchronize_Release(&This->ISynchronize_iface);
907 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
909 MREImpl *This = impl_from_ISynchronizeHandle(iface);
911 *ph = This->event;
912 return S_OK;
915 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
916 SynchronizeHandle_QueryInterface,
917 SynchronizeHandle_AddRef,
918 SynchronizeHandle_Release,
919 SynchronizeHandle_GetHandle
922 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
924 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
925 HRESULT hr;
927 if(punkouter)
928 FIXME("Aggregation not implemented.\n");
930 This->ref = 1;
931 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
932 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
933 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
935 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
936 ISynchronize_Release(&This->ISynchronize_iface);
937 return hr;
940 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
942 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
945 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
947 LocalServer *This = impl_from_IServiceProvider(iface);
949 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
951 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
952 *ppv = &This->IServiceProvider_iface;
953 }else {
954 *ppv = NULL;
955 return E_NOINTERFACE;
958 IUnknown_AddRef((IUnknown*)*ppv);
959 return S_OK;
962 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
964 LocalServer *This = impl_from_IServiceProvider(iface);
965 LONG ref = InterlockedIncrement(&This->ref);
967 TRACE("(%p) ref=%d\n", This, ref);
969 return ref;
972 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
974 LocalServer *This = impl_from_IServiceProvider(iface);
975 LONG ref = InterlockedDecrement(&This->ref);
977 TRACE("(%p) ref=%d\n", This, ref);
979 if(!ref) {
980 assert(!This->apt);
981 HeapFree(GetProcessHeap(), 0, This);
984 return ref;
987 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
989 LocalServer *This = impl_from_IServiceProvider(iface);
990 APARTMENT *apt = COM_CurrentApt();
991 RegisteredClass *iter;
992 HRESULT hres = E_FAIL;
994 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
996 if(!This->apt)
997 return E_UNEXPECTED;
999 EnterCriticalSection(&csRegisteredClassList);
1001 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
1002 if(iter->apartment_id == apt->oxid
1003 && (iter->runContext & CLSCTX_LOCAL_SERVER)
1004 && IsEqualGUID(&iter->classIdentifier, guid)) {
1005 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
1006 break;
1010 LeaveCriticalSection( &csRegisteredClassList );
1012 return hres;
1015 static const IServiceProviderVtbl LocalServerVtbl = {
1016 LocalServer_QueryInterface,
1017 LocalServer_AddRef,
1018 LocalServer_Release,
1019 LocalServer_QueryService
1022 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
1024 HRESULT hres = S_OK;
1026 EnterCriticalSection(&apt->cs);
1028 if(!apt->local_server) {
1029 LocalServer *obj;
1031 obj = heap_alloc(sizeof(*obj));
1032 if(obj) {
1033 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
1034 obj->ref = 1;
1035 obj->apt = apt;
1037 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
1038 if(SUCCEEDED(hres)) {
1039 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
1040 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1041 if(FAILED(hres))
1042 IStream_Release(obj->marshal_stream);
1045 if(SUCCEEDED(hres))
1046 apt->local_server = obj;
1047 else
1048 heap_free(obj);
1049 }else {
1050 hres = E_OUTOFMEMORY;
1054 if(SUCCEEDED(hres))
1055 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1057 LeaveCriticalSection(&apt->cs);
1059 if(FAILED(hres))
1060 ERR("Failed: %08x\n", hres);
1061 return hres;
1064 /***********************************************************************
1065 * CoRevokeClassObject [OLE32.@]
1067 * Removes a class object from the class registry.
1069 * PARAMS
1070 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1072 * RETURNS
1073 * Success: S_OK.
1074 * Failure: HRESULT code.
1076 * NOTES
1077 * Must be called from the same apartment that called CoRegisterClassObject(),
1078 * otherwise it will fail with RPC_E_WRONG_THREAD.
1080 * SEE ALSO
1081 * CoRegisterClassObject
1083 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
1084 DWORD dwRegister)
1086 HRESULT hr = E_INVALIDARG;
1087 RegisteredClass *curClass;
1088 APARTMENT *apt;
1090 TRACE("(%08x)\n",dwRegister);
1092 if (!(apt = apartment_get_current_or_mta()))
1094 ERR("COM was not initialized\n");
1095 return CO_E_NOTINITIALIZED;
1098 EnterCriticalSection( &csRegisteredClassList );
1100 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1103 * Check if we have a match on the cookie.
1105 if (curClass->dwCookie == dwRegister)
1107 if (curClass->apartment_id == apt->oxid)
1109 COM_RevokeRegisteredClassObject(curClass);
1110 hr = S_OK;
1112 else
1114 ERR("called from wrong apartment, should be called from %s\n",
1115 wine_dbgstr_longlong(curClass->apartment_id));
1116 hr = RPC_E_WRONG_THREAD;
1118 break;
1122 LeaveCriticalSection( &csRegisteredClassList );
1123 apartment_release(apt);
1124 return hr;
1127 /* frees unused libraries loaded by apartment_getclassobject by calling the
1128 * DLL's DllCanUnloadNow entry point */
1129 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1131 struct apartment_loaded_dll *entry, *next;
1132 EnterCriticalSection(&apt->cs);
1133 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1135 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1137 DWORD real_delay = delay;
1139 if (real_delay == INFINITE)
1141 /* DLLs that return multi-threaded objects aren't unloaded
1142 * straight away to cope for programs that have races between
1143 * last object destruction and threads in the DLLs that haven't
1144 * finished, despite DllCanUnloadNow returning S_OK */
1145 if (entry->multi_threaded)
1146 real_delay = 10 * 60 * 1000; /* 10 minutes */
1147 else
1148 real_delay = 0;
1151 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1153 list_remove(&entry->entry);
1154 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1155 HeapFree(GetProcessHeap(), 0, entry);
1157 else
1159 entry->unload_time = GetTickCount() + real_delay;
1160 if (!entry->unload_time) entry->unload_time = 1;
1163 else if (entry->unload_time)
1164 entry->unload_time = 0;
1166 LeaveCriticalSection(&apt->cs);
1169 DWORD apartment_release(struct apartment *apt)
1171 DWORD ret;
1173 EnterCriticalSection(&csApartment);
1175 ret = InterlockedDecrement(&apt->refs);
1176 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1178 if (apt->being_destroyed)
1180 LeaveCriticalSection(&csApartment);
1181 return ret;
1184 /* destruction stuff that needs to happen under csApartment CS */
1185 if (ret == 0)
1187 apt->being_destroyed = TRUE;
1188 if (apt == MTA) MTA = NULL;
1189 else if (apt == MainApartment) MainApartment = NULL;
1190 list_remove(&apt->entry);
1193 LeaveCriticalSection(&csApartment);
1195 if (ret == 0)
1197 struct list *cursor, *cursor2;
1199 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1201 if(apt->local_server) {
1202 LocalServer *local_server = apt->local_server;
1203 LARGE_INTEGER zero;
1205 memset(&zero, 0, sizeof(zero));
1206 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1207 CoReleaseMarshalData(local_server->marshal_stream);
1208 IStream_Release(local_server->marshal_stream);
1209 local_server->marshal_stream = NULL;
1211 apt->local_server = NULL;
1212 local_server->apt = NULL;
1213 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1216 /* Release the references to the registered class objects */
1217 COM_RevokeAllClasses(apt);
1219 /* no locking is needed for this apartment, because no other thread
1220 * can access it at this point */
1222 apartment_disconnectproxies(apt);
1224 if (apt->win) DestroyWindow(apt->win);
1225 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1227 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1229 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1230 /* release the implicit reference given by the fact that the
1231 * stub has external references (it must do since it is in the
1232 * stub manager list in the apartment and all non-apartment users
1233 * must have a ref on the apartment and so it cannot be destroyed).
1235 stub_manager_int_release(stubmgr);
1238 /* if this assert fires, then another thread took a reference to a
1239 * stub manager without taking a reference to the containing
1240 * apartment, which it must do. */
1241 assert(list_empty(&apt->stubmgrs));
1243 if (apt->filter) IMessageFilter_Release(apt->filter);
1245 /* free as many unused libraries as possible... */
1246 apartment_freeunusedlibraries(apt, 0);
1248 /* ... and free the memory for the apartment loaded dll entry and
1249 * release the dll list reference without freeing the library for the
1250 * rest */
1251 while ((cursor = list_head(&apt->loaded_dlls)))
1253 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1254 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1255 list_remove(cursor);
1256 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1259 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1260 DeleteCriticalSection(&apt->cs);
1262 HeapFree(GetProcessHeap(), 0, apt);
1265 return ret;
1268 /* The given OXID must be local to this process:
1270 * The ref parameter is here mostly to ensure people remember that
1271 * they get one, you should normally take a ref for thread safety.
1273 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1275 APARTMENT *result = NULL;
1276 struct list *cursor;
1278 EnterCriticalSection(&csApartment);
1279 LIST_FOR_EACH( cursor, &apts )
1281 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1282 if (apt->oxid == oxid)
1284 result = apt;
1285 if (ref) apartment_addref(result);
1286 break;
1289 LeaveCriticalSection(&csApartment);
1291 return result;
1294 /* gets the apartment which has a given creator thread ID. The caller must
1295 * release the reference from the apartment as soon as the apartment pointer
1296 * is no longer required. */
1297 APARTMENT *apartment_findfromtid(DWORD tid)
1299 APARTMENT *result = NULL;
1300 struct list *cursor;
1302 EnterCriticalSection(&csApartment);
1303 LIST_FOR_EACH( cursor, &apts )
1305 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1306 if (apt->tid == tid)
1308 result = apt;
1309 apartment_addref(result);
1310 break;
1313 LeaveCriticalSection(&csApartment);
1315 return result;
1318 /* gets the main apartment if it exists. The caller must
1319 * release the reference from the apartment as soon as the apartment pointer
1320 * is no longer required. */
1321 static APARTMENT *apartment_findmain(void)
1323 APARTMENT *result;
1325 EnterCriticalSection(&csApartment);
1327 result = MainApartment;
1328 if (result) apartment_addref(result);
1330 LeaveCriticalSection(&csApartment);
1332 return result;
1335 /* gets the specified class object by loading the appropriate DLL, if
1336 * necessary and calls the DllGetClassObject function for the DLL */
1337 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1338 BOOL apartment_threaded,
1339 REFCLSID rclsid, REFIID riid, void **ppv)
1341 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1342 HRESULT hr = S_OK;
1343 BOOL found = FALSE;
1344 struct apartment_loaded_dll *apartment_loaded_dll;
1346 if (!strcmpiW(dllpath, wszOle32))
1348 /* we don't need to control the lifetime of this dll, so use the local
1349 * implementation of DllGetClassObject directly */
1350 TRACE("calling ole32!DllGetClassObject\n");
1351 hr = DllGetClassObject(rclsid, riid, ppv);
1353 if (hr != S_OK)
1354 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1356 return hr;
1359 EnterCriticalSection(&apt->cs);
1361 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1362 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1364 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1365 found = TRUE;
1366 break;
1369 if (!found)
1371 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1372 if (!apartment_loaded_dll)
1373 hr = E_OUTOFMEMORY;
1374 if (SUCCEEDED(hr))
1376 apartment_loaded_dll->unload_time = 0;
1377 apartment_loaded_dll->multi_threaded = FALSE;
1378 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1379 if (FAILED(hr))
1380 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1382 if (SUCCEEDED(hr))
1384 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1385 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1389 LeaveCriticalSection(&apt->cs);
1391 if (SUCCEEDED(hr))
1393 /* one component being multi-threaded overrides any number of
1394 * apartment-threaded components */
1395 if (!apartment_threaded)
1396 apartment_loaded_dll->multi_threaded = TRUE;
1398 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1399 /* OK: get the ClassObject */
1400 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1402 if (hr != S_OK)
1403 ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath));
1406 return hr;
1409 /* Returns expanded dll path from the registry or activation context. */
1410 static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1412 DWORD ret;
1414 if (regdata->hkey)
1416 DWORD keytype;
1417 WCHAR src[MAX_PATH];
1418 DWORD dwLength = dstlen * sizeof(WCHAR);
1420 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1421 if (keytype == REG_EXPAND_SZ) {
1422 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1423 } else {
1424 const WCHAR *quote_start;
1425 quote_start = strchrW(src, '\"');
1426 if (quote_start) {
1427 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1428 if (quote_end) {
1429 memmove(src, quote_start + 1,
1430 (quote_end - quote_start - 1) * sizeof(WCHAR));
1431 src[quote_end - quote_start - 1] = '\0';
1434 lstrcpynW(dst, src, dstlen);
1437 return !ret;
1439 else
1441 static const WCHAR dllW[] = {'.','d','l','l',0};
1442 ULONG_PTR cookie;
1443 WCHAR *nameW;
1445 *dst = 0;
1446 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1447 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1448 ret = SearchPathW(NULL, nameW, dllW, dstlen, dst, NULL);
1449 DeactivateActCtx(0, cookie);
1450 return *dst != 0;
1454 struct host_object_params
1456 struct class_reg_data regdata;
1457 CLSID clsid; /* clsid of object to marshal */
1458 IID iid; /* interface to marshal */
1459 HANDLE event; /* event signalling when ready for multi-threaded case */
1460 HRESULT hr; /* result for multi-threaded case */
1461 IStream *stream; /* stream that the object will be marshaled into */
1462 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1465 static HRESULT apartment_hostobject(struct apartment *apt,
1466 const struct host_object_params *params)
1468 IUnknown *object;
1469 HRESULT hr;
1470 static const LARGE_INTEGER llZero;
1471 WCHAR dllpath[MAX_PATH+1];
1473 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1475 if (!get_object_dll_path(&params->regdata, dllpath, ARRAY_SIZE(dllpath)))
1477 /* failure: CLSID is not found in registry */
1478 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1479 return REGDB_E_CLASSNOTREG;
1482 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1483 &params->clsid, &params->iid, (void **)&object);
1484 if (FAILED(hr))
1485 return hr;
1487 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1488 if (FAILED(hr))
1489 IUnknown_Release(object);
1490 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1492 return hr;
1495 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1497 switch (msg)
1499 case DM_EXECUTERPC:
1500 RPC_ExecuteCall((struct dispatch_params *)lParam);
1501 return 0;
1502 case DM_HOSTOBJECT:
1503 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1504 default:
1505 return DefWindowProcW(hWnd, msg, wParam, lParam);
1509 struct host_thread_params
1511 COINIT threading_model;
1512 HANDLE ready_event;
1513 HWND apartment_hwnd;
1516 /* thread for hosting an object to allow an object to appear to be created in
1517 * an apartment with an incompatible threading model */
1518 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1520 struct host_thread_params *params = p;
1521 MSG msg;
1522 HRESULT hr;
1523 struct apartment *apt;
1525 TRACE("\n");
1527 hr = CoInitializeEx(NULL, params->threading_model);
1528 if (FAILED(hr)) return hr;
1530 apt = COM_CurrentApt();
1531 if (params->threading_model == COINIT_APARTMENTTHREADED)
1533 apartment_createwindowifneeded(apt);
1534 params->apartment_hwnd = apartment_getwindow(apt);
1536 else
1537 params->apartment_hwnd = NULL;
1539 /* force the message queue to be created before signaling parent thread */
1540 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1542 SetEvent(params->ready_event);
1543 params = NULL; /* can't touch params after here as it may be invalid */
1545 while (GetMessageW(&msg, NULL, 0, 0))
1547 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1549 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1550 obj_params->hr = apartment_hostobject(apt, obj_params);
1551 SetEvent(obj_params->event);
1553 else
1555 TranslateMessage(&msg);
1556 DispatchMessageW(&msg);
1560 TRACE("exiting\n");
1562 CoUninitialize();
1564 return S_OK;
1567 /* finds or creates a host apartment, creates the object inside it and returns
1568 * a proxy to it so that the object can be used in the apartment of the
1569 * caller of this function */
1570 static HRESULT apartment_hostobject_in_hostapt(
1571 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1572 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1574 struct host_object_params params;
1575 HWND apartment_hwnd = NULL;
1576 DWORD apartment_tid = 0;
1577 HRESULT hr;
1579 if (!multi_threaded && main_apartment)
1581 APARTMENT *host_apt = apartment_findmain();
1582 if (host_apt)
1584 apartment_hwnd = apartment_getwindow(host_apt);
1585 apartment_release(host_apt);
1589 if (!apartment_hwnd)
1591 EnterCriticalSection(&apt->cs);
1593 if (!apt->host_apt_tid)
1595 struct host_thread_params thread_params;
1596 HANDLE handles[2];
1597 DWORD wait_value;
1599 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1600 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1601 thread_params.apartment_hwnd = NULL;
1602 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1603 if (!handles[1])
1605 CloseHandle(handles[0]);
1606 LeaveCriticalSection(&apt->cs);
1607 return E_OUTOFMEMORY;
1609 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1610 CloseHandle(handles[0]);
1611 CloseHandle(handles[1]);
1612 if (wait_value == WAIT_OBJECT_0)
1613 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1614 else
1616 LeaveCriticalSection(&apt->cs);
1617 return E_OUTOFMEMORY;
1621 if (multi_threaded || !main_apartment)
1623 apartment_hwnd = apt->host_apt_hwnd;
1624 apartment_tid = apt->host_apt_tid;
1627 LeaveCriticalSection(&apt->cs);
1630 /* another thread may have become the main apartment in the time it took
1631 * us to create the thread for the host apartment */
1632 if (!apartment_hwnd && !multi_threaded && main_apartment)
1634 APARTMENT *host_apt = apartment_findmain();
1635 if (host_apt)
1637 apartment_hwnd = apartment_getwindow(host_apt);
1638 apartment_release(host_apt);
1642 params.regdata = *regdata;
1643 params.clsid = *rclsid;
1644 params.iid = *riid;
1645 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1646 if (FAILED(hr))
1647 return hr;
1648 params.apartment_threaded = !multi_threaded;
1649 if (multi_threaded)
1651 params.hr = S_OK;
1652 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1653 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1654 hr = E_OUTOFMEMORY;
1655 else
1657 WaitForSingleObject(params.event, INFINITE);
1658 hr = params.hr;
1660 CloseHandle(params.event);
1662 else
1664 if (!apartment_hwnd)
1666 ERR("host apartment didn't create window\n");
1667 hr = E_OUTOFMEMORY;
1669 else
1670 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1672 if (SUCCEEDED(hr))
1673 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1674 IStream_Release(params.stream);
1675 return hr;
1678 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1680 WNDCLASSW wclass;
1682 /* Dispatching to the correct thread in an apartment is done through
1683 * window messages rather than RPC transports. When an interface is
1684 * marshalled into another apartment in the same process, a window of the
1685 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1686 * application) is responsible for pumping the message loop in that thread.
1687 * The WM_USER messages which point to the RPCs are then dispatched to
1688 * apartment_wndproc by the user's code from the apartment in which the
1689 * interface was unmarshalled.
1691 memset(&wclass, 0, sizeof(wclass));
1692 wclass.lpfnWndProc = apartment_wndproc;
1693 wclass.hInstance = hProxyDll;
1694 wclass.lpszClassName = wszAptWinClass;
1695 apt_win_class = RegisterClassW(&wclass);
1696 return TRUE;
1699 /* create a window for the apartment or return the current one if one has
1700 * already been created */
1701 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1703 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1705 if (apt->multi_threaded)
1706 return S_OK;
1708 if (!apt->win)
1710 HWND hwnd;
1712 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1714 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1715 HWND_MESSAGE, 0, hProxyDll, NULL);
1716 if (!hwnd)
1718 ERR("CreateWindow failed with error %d\n", GetLastError());
1719 return HRESULT_FROM_WIN32(GetLastError());
1721 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1722 /* someone beat us to it */
1723 DestroyWindow(hwnd);
1726 return S_OK;
1729 /* retrieves the window for the main- or apartment-threaded apartment */
1730 HWND apartment_getwindow(const struct apartment *apt)
1732 assert(!apt->multi_threaded);
1733 return apt->win;
1736 static void COM_TlsDestroy(void)
1738 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1739 if (info)
1741 struct init_spy *cursor, *cursor2;
1743 if (info->apt) apartment_release(info->apt);
1744 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1745 if (info->state) IUnknown_Release(info->state);
1747 LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &info->spies, struct init_spy, entry)
1749 list_remove(&cursor->entry);
1750 IInitializeSpy_Release(cursor->spy);
1751 heap_free(cursor);
1754 if (info->context_token) IObjContext_Release(info->context_token);
1756 HeapFree(GetProcessHeap(), 0, info);
1757 NtCurrentTeb()->ReservedForOle = NULL;
1761 /******************************************************************************
1762 * CoBuildVersion [OLE32.@]
1764 * Gets the build version of the DLL.
1766 * PARAMS
1768 * RETURNS
1769 * Current build version, hiword is majornumber, loword is minornumber
1771 DWORD WINAPI CoBuildVersion(void)
1773 TRACE("Returning version %d, build %d.\n", rmm, rup);
1774 return (rmm<<16)+rup;
1777 static struct init_spy *get_spy_entry(struct oletls *info, unsigned int id)
1779 struct init_spy *spy;
1781 LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry)
1783 if (id == spy->id)
1784 return spy;
1787 return NULL;
1790 /******************************************************************************
1791 * CoRegisterInitializeSpy [OLE32.@]
1793 * Add a Spy that watches CoInitializeEx calls
1795 * PARAMS
1796 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1797 * cookie [II] cookie receiver
1799 * RETURNS
1800 * Success: S_OK if not already initialized, S_FALSE otherwise.
1801 * Failure: HRESULT code.
1803 * SEE ALSO
1804 * CoInitializeEx
1806 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1808 struct oletls *info = COM_CurrentInfo();
1809 struct init_spy *entry;
1810 unsigned int id;
1811 HRESULT hr;
1813 TRACE("(%p, %p)\n", spy, cookie);
1815 if (!spy || !cookie || !info)
1817 if (!info)
1818 WARN("Could not allocate tls\n");
1819 return E_INVALIDARG;
1822 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy);
1823 if (FAILED(hr))
1824 return hr;
1826 entry = heap_alloc(sizeof(*entry));
1827 if (!entry)
1829 IInitializeSpy_Release(spy);
1830 return E_OUTOFMEMORY;
1833 entry->spy = spy;
1835 id = 0;
1836 while (get_spy_entry(info, id) != NULL)
1838 id++;
1841 entry->id = id;
1842 list_add_head(&info->spies, &entry->entry);
1844 cookie->HighPart = GetCurrentThreadId();
1845 cookie->LowPart = entry->id;
1847 return S_OK;
1850 /******************************************************************************
1851 * CoRevokeInitializeSpy [OLE32.@]
1853 * Remove a spy that previously watched CoInitializeEx calls
1855 * PARAMS
1856 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1858 * RETURNS
1859 * Success: S_OK if a spy is removed
1860 * Failure: E_INVALIDARG
1862 * SEE ALSO
1863 * CoInitializeEx
1865 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1867 struct oletls *info = COM_CurrentInfo();
1868 struct init_spy *spy;
1870 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1872 if (!info || cookie.HighPart != GetCurrentThreadId())
1873 return E_INVALIDARG;
1875 if ((spy = get_spy_entry(info, cookie.LowPart)))
1877 IInitializeSpy_Release(spy->spy);
1878 list_remove(&spy->entry);
1879 heap_free(spy);
1881 return S_OK;
1884 return E_INVALIDARG;
1887 HRESULT enter_apartment( struct oletls *info, DWORD model )
1889 HRESULT hr = S_OK;
1891 if (!info->apt)
1893 if (!apartment_get_or_create( model ))
1894 return E_OUTOFMEMORY;
1896 else if (!apartment_is_model( info->apt, model ))
1898 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1899 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1900 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1901 return RPC_E_CHANGED_MODE;
1903 else
1904 hr = S_FALSE;
1906 info->inits++;
1908 return hr;
1911 void leave_apartment( struct oletls *info )
1913 if (!--info->inits)
1915 if (info->ole_inits)
1916 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1917 apartment_release( info->apt );
1918 info->apt = NULL;
1922 /******************************************************************************
1923 * CoInitialize [OLE32.@]
1925 * Initializes the COM libraries by calling CoInitializeEx with
1926 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1928 * PARAMS
1929 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1931 * RETURNS
1932 * Success: S_OK if not already initialized, S_FALSE otherwise.
1933 * Failure: HRESULT code.
1935 * SEE ALSO
1936 * CoInitializeEx
1938 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1941 * Just delegate to the newer method.
1943 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1946 /******************************************************************************
1947 * CoInitializeEx [OLE32.@]
1949 * Initializes the COM libraries.
1951 * PARAMS
1952 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1953 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1955 * RETURNS
1956 * S_OK if successful,
1957 * S_FALSE if this function was called already.
1958 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1959 * threading model.
1961 * NOTES
1963 * The behavior used to set the IMalloc used for memory management is
1964 * obsolete.
1965 * The dwCoInit parameter must specify one of the following apartment
1966 * threading models:
1967 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1968 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1969 * The parameter may also specify zero or more of the following flags:
1970 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1971 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1973 * SEE ALSO
1974 * CoUninitialize
1976 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1978 struct oletls *info = COM_CurrentInfo();
1979 struct init_spy *cursor;
1980 HRESULT hr;
1982 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1984 if (lpReserved!=NULL)
1986 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1990 * Check the lock count. If this is the first time going through the initialize
1991 * process, we have to initialize the libraries.
1993 * And crank-up that lock count.
1995 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1998 * Initialize the various COM libraries and data structures.
2000 TRACE("() - Initializing the COM libraries\n");
2002 /* we may need to defer this until after apartment initialisation */
2003 RunningObjectTableImpl_Initialize();
2006 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2008 IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits);
2011 hr = enter_apartment( info, dwCoInit );
2013 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2015 hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits);
2018 return hr;
2021 /***********************************************************************
2022 * CoUninitialize [OLE32.@]
2024 * This method will decrement the refcount on the current apartment, freeing
2025 * the resources associated with it if it is the last thread in the apartment.
2026 * If the last apartment is freed, the function will additionally release
2027 * any COM resources associated with the process.
2029 * PARAMS
2031 * RETURNS
2032 * Nothing.
2034 * SEE ALSO
2035 * CoInitializeEx
2037 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
2039 struct oletls * info = COM_CurrentInfo();
2040 struct init_spy *cursor;
2041 LONG lCOMRefCnt;
2043 TRACE("()\n");
2045 /* will only happen on OOM */
2046 if (!info) return;
2048 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2050 IInitializeSpy_PreUninitialize(cursor->spy, info->inits);
2053 /* sanity check */
2054 if (!info->inits)
2056 ERR("Mismatched CoUninitialize\n");
2058 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2060 IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2063 return;
2066 leave_apartment( info );
2069 * Decrease the reference count.
2070 * If we are back to 0 locks on the COM library, make sure we free
2071 * all the associated data structures.
2073 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2074 if (lCOMRefCnt==1)
2076 TRACE("() - Releasing the COM libraries\n");
2078 revoke_registered_psclsids();
2079 RunningObjectTableImpl_UnInitialize();
2081 else if (lCOMRefCnt<1) {
2082 ERR( "CoUninitialize() - not CoInitialized.\n" );
2083 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2086 LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry)
2088 IInitializeSpy_PostUninitialize(cursor->spy, info->inits);
2092 /******************************************************************************
2093 * CoDisconnectObject [OLE32.@]
2095 * Disconnects all connections to this object from remote processes. Dispatches
2096 * pending RPCs while blocking new RPCs from occurring, and then calls
2097 * IMarshal::DisconnectObject on the given object.
2099 * Typically called when the object server is forced to shut down, for instance by
2100 * the user.
2102 * PARAMS
2103 * lpUnk [I] The object whose stub should be disconnected.
2104 * reserved [I] Reserved. Should be set to 0.
2106 * RETURNS
2107 * Success: S_OK.
2108 * Failure: HRESULT code.
2110 * SEE ALSO
2111 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2113 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2115 struct stub_manager *manager;
2116 HRESULT hr;
2117 IMarshal *marshal;
2118 APARTMENT *apt;
2120 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2122 if (!lpUnk) return E_INVALIDARG;
2124 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2125 if (hr == S_OK)
2127 hr = IMarshal_DisconnectObject(marshal, reserved);
2128 IMarshal_Release(marshal);
2129 return hr;
2132 if (!(apt = apartment_get_current_or_mta()))
2134 ERR("apartment not initialised\n");
2135 return CO_E_NOTINITIALIZED;
2138 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2139 if (manager) {
2140 stub_manager_disconnect(manager);
2141 /* Release stub manager twice, to remove the apartment reference. */
2142 stub_manager_int_release(manager);
2143 stub_manager_int_release(manager);
2146 /* Note: native is pretty broken here because it just silently
2147 * fails, without returning an appropriate error code if the object was
2148 * not found, making apps think that the object was disconnected, when
2149 * it actually wasn't */
2151 apartment_release(apt);
2152 return S_OK;
2155 /******************************************************************************
2156 * CoCreateGuid [OLE32.@]
2158 * Simply forwards to UuidCreate in RPCRT4.
2160 * PARAMS
2161 * pguid [O] Points to the GUID to initialize.
2163 * RETURNS
2164 * Success: S_OK.
2165 * Failure: HRESULT code.
2167 * SEE ALSO
2168 * UuidCreate
2170 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2172 DWORD status;
2174 if(!pguid) return E_INVALIDARG;
2176 status = UuidCreate(pguid);
2177 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2178 return HRESULT_FROM_WIN32( status );
2181 static inline BOOL is_valid_hex(WCHAR c)
2183 if (!(((c >= '0') && (c <= '9')) ||
2184 ((c >= 'a') && (c <= 'f')) ||
2185 ((c >= 'A') && (c <= 'F'))))
2186 return FALSE;
2187 return TRUE;
2190 static const BYTE guid_conv_table[256] =
2192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2195 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2196 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2197 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2198 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2201 /* conversion helper for CLSIDFromString/IIDFromString */
2202 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2204 int i;
2206 if (!s || s[0]!='{') {
2207 memset( id, 0, sizeof (CLSID) );
2208 if(!s) return TRUE;
2209 return FALSE;
2212 TRACE("%s -> %p\n", debugstr_w(s), id);
2214 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2216 id->Data1 = 0;
2217 for (i = 1; i < 9; i++) {
2218 if (!is_valid_hex(s[i])) return FALSE;
2219 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2221 if (s[9]!='-') return FALSE;
2223 id->Data2 = 0;
2224 for (i = 10; i < 14; i++) {
2225 if (!is_valid_hex(s[i])) return FALSE;
2226 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2228 if (s[14]!='-') return FALSE;
2230 id->Data3 = 0;
2231 for (i = 15; i < 19; i++) {
2232 if (!is_valid_hex(s[i])) return FALSE;
2233 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2235 if (s[19]!='-') return FALSE;
2237 for (i = 20; i < 37; i+=2) {
2238 if (i == 24) {
2239 if (s[i]!='-') return FALSE;
2240 i++;
2242 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2243 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2246 if (s[37] == '}' && s[38] == '\0')
2247 return TRUE;
2249 return FALSE;
2252 /*****************************************************************************/
2254 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2256 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2257 WCHAR buf2[CHARS_IN_GUID];
2258 LONG buf2len = sizeof(buf2);
2259 HKEY xhkey;
2260 WCHAR *buf;
2262 memset(clsid, 0, sizeof(*clsid));
2263 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2264 if (!buf) return E_OUTOFMEMORY;
2265 strcpyW( buf, progid );
2266 strcatW( buf, clsidW );
2267 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2269 HeapFree(GetProcessHeap(),0,buf);
2270 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2271 return CO_E_CLASSSTRING;
2273 HeapFree(GetProcessHeap(),0,buf);
2275 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2277 RegCloseKey(xhkey);
2278 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2279 return CO_E_CLASSSTRING;
2281 RegCloseKey(xhkey);
2282 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2285 /******************************************************************************
2286 * CLSIDFromString [OLE32.@]
2288 * Converts a unique identifier from its string representation into
2289 * the GUID struct.
2291 * PARAMS
2292 * idstr [I] The string representation of the GUID.
2293 * id [O] GUID converted from the string.
2295 * RETURNS
2296 * S_OK on success
2297 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2299 * SEE ALSO
2300 * StringFromCLSID
2302 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2304 HRESULT ret = CO_E_CLASSSTRING;
2305 CLSID tmp_id;
2307 if (!id)
2308 return E_INVALIDARG;
2310 if (guid_from_string(idstr, id))
2311 return S_OK;
2313 /* It appears a ProgID is also valid */
2314 ret = clsid_from_string_reg(idstr, &tmp_id);
2315 if(SUCCEEDED(ret))
2316 *id = tmp_id;
2318 return ret;
2321 /******************************************************************************
2322 * IIDFromString [OLE32.@]
2324 * Converts an interface identifier from its string representation to
2325 * the IID struct.
2327 * PARAMS
2328 * idstr [I] The string representation of the GUID.
2329 * id [O] IID converted from the string.
2331 * RETURNS
2332 * S_OK on success
2333 * CO_E_IIDSTRING if idstr is not a valid IID
2335 * SEE ALSO
2336 * StringFromIID
2338 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2340 TRACE("%s -> %p\n", debugstr_w(s), iid);
2342 if (!s)
2344 memset(iid, 0, sizeof(*iid));
2345 return S_OK;
2348 /* length mismatch is a special case */
2349 if (strlenW(s) + 1 != CHARS_IN_GUID)
2350 return E_INVALIDARG;
2352 if (s[0] != '{')
2353 return CO_E_IIDSTRING;
2355 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2358 /******************************************************************************
2359 * StringFromCLSID [OLE32.@]
2360 * StringFromIID [OLE32.@]
2362 * Converts a GUID into the respective string representation.
2363 * The target string is allocated using the OLE IMalloc.
2365 * PARAMS
2366 * id [I] the GUID to be converted.
2367 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2369 * RETURNS
2370 * S_OK
2371 * E_FAIL
2373 * SEE ALSO
2374 * StringFromGUID2, CLSIDFromString
2376 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2378 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2379 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2380 return S_OK;
2383 /******************************************************************************
2384 * StringFromGUID2 [OLE32.@]
2386 * Modified version of StringFromCLSID that allows you to specify max
2387 * buffer size.
2389 * PARAMS
2390 * id [I] GUID to convert to string.
2391 * str [O] Buffer where the result will be stored.
2392 * cmax [I] Size of the buffer in characters.
2394 * RETURNS
2395 * Success: The length of the resulting string in characters.
2396 * Failure: 0.
2398 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2400 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2401 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2402 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2403 '%','0','2','X','%','0','2','X','}',0 };
2404 if (!id || cmax < CHARS_IN_GUID) return 0;
2405 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2406 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2407 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2408 return CHARS_IN_GUID;
2411 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2412 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2414 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2415 WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(wszCLSIDSlash) - 1];
2416 LONG res;
2417 HKEY key;
2419 strcpyW(path, wszCLSIDSlash);
2420 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2421 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2422 if (res == ERROR_FILE_NOT_FOUND)
2423 return REGDB_E_CLASSNOTREG;
2424 else if (res != ERROR_SUCCESS)
2425 return REGDB_E_READREGDB;
2427 if (!keyname)
2429 *subkey = key;
2430 return S_OK;
2433 res = open_classes_key(key, keyname, access, subkey);
2434 RegCloseKey(key);
2435 if (res == ERROR_FILE_NOT_FOUND)
2436 return REGDB_E_KEYMISSING;
2437 else if (res != ERROR_SUCCESS)
2438 return REGDB_E_READREGDB;
2440 return S_OK;
2443 /* open HKCR\\AppId\\{string form of appid clsid} key */
2444 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2446 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2447 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2448 DWORD res;
2449 WCHAR buf[CHARS_IN_GUID];
2450 WCHAR keyname[ARRAY_SIZE(szAppIdKey) + CHARS_IN_GUID];
2451 DWORD size;
2452 HKEY hkey;
2453 DWORD type;
2454 HRESULT hr;
2456 /* read the AppID value under the class's key */
2457 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2458 if (FAILED(hr))
2459 return hr;
2461 size = sizeof(buf);
2462 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2463 RegCloseKey(hkey);
2464 if (res == ERROR_FILE_NOT_FOUND)
2465 return REGDB_E_KEYMISSING;
2466 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2467 return REGDB_E_READREGDB;
2469 strcpyW(keyname, szAppIdKey);
2470 strcatW(keyname, buf);
2471 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2472 if (res == ERROR_FILE_NOT_FOUND)
2473 return REGDB_E_KEYMISSING;
2474 else if (res != ERROR_SUCCESS)
2475 return REGDB_E_READREGDB;
2477 return S_OK;
2480 /******************************************************************************
2481 * ProgIDFromCLSID [OLE32.@]
2483 * Converts a class id into the respective program ID.
2485 * PARAMS
2486 * clsid [I] Class ID, as found in registry.
2487 * ppszProgID [O] Associated ProgID.
2489 * RETURNS
2490 * S_OK
2491 * E_OUTOFMEMORY
2492 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2494 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2496 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2497 ACTCTX_SECTION_KEYED_DATA data;
2498 HKEY hkey;
2499 HRESULT ret;
2500 LONG progidlen = 0;
2502 if (!ppszProgID)
2503 return E_INVALIDARG;
2505 *ppszProgID = NULL;
2507 data.cbSize = sizeof(data);
2508 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2509 clsid, &data))
2511 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2512 if (comclass->progid_len)
2514 WCHAR *ptrW;
2516 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2517 if (!*ppszProgID) return E_OUTOFMEMORY;
2519 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2520 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2521 return S_OK;
2523 else
2524 return REGDB_E_CLASSNOTREG;
2527 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2528 if (FAILED(ret))
2529 return ret;
2531 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2532 ret = REGDB_E_CLASSNOTREG;
2534 if (ret == S_OK)
2536 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2537 if (*ppszProgID)
2539 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2540 ret = REGDB_E_CLASSNOTREG;
2541 CoTaskMemFree(*ppszProgID);
2542 *ppszProgID = NULL;
2545 else
2546 ret = E_OUTOFMEMORY;
2549 RegCloseKey(hkey);
2550 return ret;
2553 /******************************************************************************
2554 * CLSIDFromProgID [OLE32.@]
2556 * Converts a program id into the respective GUID.
2558 * PARAMS
2559 * progid [I] Unicode program ID, as found in registry.
2560 * clsid [O] Associated CLSID.
2562 * RETURNS
2563 * Success: S_OK
2564 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2566 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2568 ACTCTX_SECTION_KEYED_DATA data;
2570 if (!progid || !clsid)
2571 return E_INVALIDARG;
2573 data.cbSize = sizeof(data);
2574 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2575 progid, &data))
2577 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2578 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2579 *clsid = *alias;
2580 return S_OK;
2583 return clsid_from_string_reg(progid, clsid);
2586 /******************************************************************************
2587 * CLSIDFromProgIDEx [OLE32.@]
2589 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2591 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2593 return CLSIDFromProgID(progid, clsid);
2596 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2598 HKEY hkey;
2599 WCHAR value[CHARS_IN_GUID];
2600 DWORD len;
2602 access |= KEY_READ;
2604 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2605 return REGDB_E_IIDNOTREG;
2607 len = sizeof(value);
2608 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2609 return REGDB_E_IIDNOTREG;
2610 RegCloseKey(hkey);
2612 if (CLSIDFromString(value, pclsid) != NOERROR)
2613 return REGDB_E_IIDNOTREG;
2615 return S_OK;
2618 /*****************************************************************************
2619 * CoGetPSClsid [OLE32.@]
2621 * Retrieves the CLSID of the proxy/stub factory that implements
2622 * IPSFactoryBuffer for the specified interface.
2624 * PARAMS
2625 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2626 * pclsid [O] Where to store returned proxy/stub CLSID.
2628 * RETURNS
2629 * S_OK
2630 * E_OUTOFMEMORY
2631 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2633 * NOTES
2635 * The standard marshaller activates the object with the CLSID
2636 * returned and uses the CreateProxy and CreateStub methods on its
2637 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2638 * given object.
2640 * CoGetPSClsid determines this CLSID by searching the
2641 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2642 * in the registry and any interface id registered by
2643 * CoRegisterPSClsid within the current process.
2645 * BUGS
2647 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2648 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2649 * considered a bug in native unless an application depends on this (unlikely).
2651 * SEE ALSO
2652 * CoRegisterPSClsid.
2654 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2656 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2657 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2658 WCHAR path[ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAY_SIZE(wszPSC)];
2659 APARTMENT *apt;
2660 struct registered_psclsid *registered_psclsid;
2661 ACTCTX_SECTION_KEYED_DATA data;
2662 HRESULT hr;
2663 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2664 BOOL is_wow64;
2666 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2668 if (!(apt = apartment_get_current_or_mta()))
2670 ERR("apartment not initialised\n");
2671 return CO_E_NOTINITIALIZED;
2673 apartment_release(apt);
2675 if (!pclsid)
2676 return E_INVALIDARG;
2678 EnterCriticalSection(&cs_registered_psclsid_list);
2680 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2681 if (IsEqualIID(&registered_psclsid->iid, riid))
2683 *pclsid = registered_psclsid->clsid;
2684 LeaveCriticalSection(&cs_registered_psclsid_list);
2685 return S_OK;
2688 LeaveCriticalSection(&cs_registered_psclsid_list);
2690 data.cbSize = sizeof(data);
2691 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2692 riid, &data))
2694 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2695 *pclsid = ifaceps->iid;
2696 return S_OK;
2699 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2700 strcpyW(path, wszInterface);
2701 StringFromGUID2(riid, path + ARRAY_SIZE(wszInterface) - 1, CHARS_IN_GUID);
2702 strcpyW(path + ARRAY_SIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2704 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2705 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2706 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2707 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2709 if (hr == S_OK)
2710 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2711 else
2712 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2714 return hr;
2717 /*****************************************************************************
2718 * CoRegisterPSClsid [OLE32.@]
2720 * Register a proxy/stub CLSID for the given interface in the current process
2721 * only.
2723 * PARAMS
2724 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2725 * rclsid [I] CLSID of the proxy/stub.
2727 * RETURNS
2728 * Success: S_OK
2729 * Failure: E_OUTOFMEMORY
2731 * NOTES
2733 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2734 * will be returned from other apartments in the same process.
2736 * This function does not add anything to the registry and the effects are
2737 * limited to the lifetime of the current process.
2739 * SEE ALSO
2740 * CoGetPSClsid.
2742 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2744 APARTMENT *apt;
2745 struct registered_psclsid *registered_psclsid;
2747 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2749 if (!(apt = apartment_get_current_or_mta()))
2751 ERR("apartment not initialised\n");
2752 return CO_E_NOTINITIALIZED;
2754 apartment_release(apt);
2756 EnterCriticalSection(&cs_registered_psclsid_list);
2758 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2759 if (IsEqualIID(&registered_psclsid->iid, riid))
2761 registered_psclsid->clsid = *rclsid;
2762 LeaveCriticalSection(&cs_registered_psclsid_list);
2763 return S_OK;
2766 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2767 if (!registered_psclsid)
2769 LeaveCriticalSection(&cs_registered_psclsid_list);
2770 return E_OUTOFMEMORY;
2773 registered_psclsid->iid = *riid;
2774 registered_psclsid->clsid = *rclsid;
2775 list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2777 LeaveCriticalSection(&cs_registered_psclsid_list);
2779 return S_OK;
2783 /***
2784 * COM_GetRegisteredClassObject
2786 * This internal method is used to scan the registered class list to
2787 * find a class object.
2789 * Params:
2790 * rclsid Class ID of the class to find.
2791 * dwClsContext Class context to match.
2792 * ppv [out] returns a pointer to the class object. Complying
2793 * to normal COM usage, this method will increase the
2794 * reference count on this object.
2796 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2797 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2799 HRESULT hr = S_FALSE;
2800 RegisteredClass *curClass;
2802 EnterCriticalSection( &csRegisteredClassList );
2804 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2807 * Check if we have a match on the class ID and context.
2809 if ((apt->oxid == curClass->apartment_id) &&
2810 (dwClsContext & curClass->runContext) &&
2811 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2814 * We have a match, return the pointer to the class object.
2816 *ppUnk = curClass->classObject;
2818 IUnknown_AddRef(curClass->classObject);
2820 hr = S_OK;
2821 break;
2825 LeaveCriticalSection( &csRegisteredClassList );
2827 return hr;
2830 /******************************************************************************
2831 * CoRegisterClassObject [OLE32.@]
2833 * Registers the class object for a given class ID. Servers housed in EXE
2834 * files use this method instead of exporting DllGetClassObject to allow
2835 * other code to connect to their objects.
2837 * PARAMS
2838 * rclsid [I] CLSID of the object to register.
2839 * pUnk [I] IUnknown of the object.
2840 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2841 * flags [I] REGCLS flags indicating how connections are made.
2842 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2844 * RETURNS
2845 * S_OK on success,
2846 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2847 * CO_E_OBJISREG if the object is already registered. We should not return this.
2849 * SEE ALSO
2850 * CoRevokeClassObject, CoGetClassObject
2852 * NOTES
2853 * In-process objects are only registered for the current apartment.
2854 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2855 * in other apartments.
2857 * BUGS
2858 * MSDN claims that multiple interface registrations are legal, but we
2859 * can't do that with our current implementation.
2861 HRESULT WINAPI CoRegisterClassObject(
2862 REFCLSID rclsid,
2863 LPUNKNOWN pUnk,
2864 DWORD dwClsContext,
2865 DWORD flags,
2866 LPDWORD lpdwRegister)
2868 static LONG next_cookie;
2869 RegisteredClass* newClass;
2870 LPUNKNOWN foundObject;
2871 HRESULT hr;
2872 APARTMENT *apt;
2874 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2875 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2877 if ( (lpdwRegister==0) || (pUnk==0) )
2878 return E_INVALIDARG;
2880 if (!(apt = apartment_get_current_or_mta()))
2882 ERR("COM was not initialized\n");
2883 return CO_E_NOTINITIALIZED;
2886 *lpdwRegister = 0;
2888 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2889 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2890 if (flags & REGCLS_MULTIPLEUSE)
2891 dwClsContext |= CLSCTX_INPROC_SERVER;
2894 * First, check if the class is already registered.
2895 * If it is, this should cause an error.
2897 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2898 if (hr == S_OK) {
2899 if (flags & REGCLS_MULTIPLEUSE) {
2900 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2901 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2902 IUnknown_Release(foundObject);
2903 apartment_release(apt);
2904 return hr;
2906 IUnknown_Release(foundObject);
2907 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2908 apartment_release(apt);
2909 return CO_E_OBJISREG;
2912 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2913 if ( newClass == NULL )
2915 apartment_release(apt);
2916 return E_OUTOFMEMORY;
2919 newClass->classIdentifier = *rclsid;
2920 newClass->apartment_id = apt->oxid;
2921 newClass->runContext = dwClsContext;
2922 newClass->connectFlags = flags;
2923 newClass->RpcRegistration = NULL;
2925 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2926 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2929 * Since we're making a copy of the object pointer, we have to increase its
2930 * reference count.
2932 newClass->classObject = pUnk;
2933 IUnknown_AddRef(newClass->classObject);
2935 EnterCriticalSection( &csRegisteredClassList );
2936 list_add_tail(&RegisteredClassList, &newClass->entry);
2937 LeaveCriticalSection( &csRegisteredClassList );
2939 *lpdwRegister = newClass->dwCookie;
2941 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2942 IStream *marshal_stream;
2944 hr = get_local_server_stream(apt, &marshal_stream);
2945 if(FAILED(hr))
2947 apartment_release(apt);
2948 return hr;
2951 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2952 marshal_stream,
2953 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2954 &newClass->RpcRegistration);
2955 IStream_Release(marshal_stream);
2957 apartment_release(apt);
2958 return S_OK;
2961 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2963 if (data->hkey)
2965 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2966 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2967 static const WCHAR wszFree[] = {'F','r','e','e',0};
2968 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2969 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2970 DWORD dwLength = sizeof(threading_model);
2971 DWORD keytype;
2972 DWORD ret;
2974 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2975 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2976 threading_model[0] = '\0';
2978 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2979 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2980 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2982 /* there's not specific handling for this case */
2983 if (threading_model[0]) return ThreadingModel_Neutral;
2984 return ThreadingModel_No;
2986 else
2987 return data->u.actctx.data->model;
2990 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2991 REFCLSID rclsid, REFIID riid,
2992 BOOL hostifnecessary, void **ppv)
2994 WCHAR dllpath[MAX_PATH+1];
2995 BOOL apartment_threaded;
2997 if (hostifnecessary)
2999 enum comclass_threadingmodel model = get_threading_model(regdata);
3001 if (model == ThreadingModel_Apartment)
3003 apartment_threaded = TRUE;
3004 if (apt->multi_threaded)
3005 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
3007 else if (model == ThreadingModel_Free)
3009 apartment_threaded = FALSE;
3010 if (!apt->multi_threaded)
3011 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
3013 /* everything except "Apartment", "Free" and "Both" */
3014 else if (model != ThreadingModel_Both)
3016 apartment_threaded = TRUE;
3017 /* everything else is main-threaded */
3018 if (model != ThreadingModel_No)
3019 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
3021 if (apt->multi_threaded || !apt->main)
3022 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
3024 else
3025 apartment_threaded = FALSE;
3027 else
3028 apartment_threaded = !apt->multi_threaded;
3030 if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath)))
3032 /* failure: CLSID is not found in registry */
3033 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
3034 return REGDB_E_CLASSNOTREG;
3037 return apartment_getclassobject(apt, dllpath, apartment_threaded,
3038 rclsid, riid, ppv);
3041 /***********************************************************************
3042 * CoGetClassObject [OLE32.@]
3044 * Creates an object of the specified class.
3046 * PARAMS
3047 * rclsid [I] Class ID to create an instance of.
3048 * dwClsContext [I] Flags to restrict the location of the created instance.
3049 * pServerInfo [I] Optional. Details for connecting to a remote server.
3050 * iid [I] The ID of the interface of the instance to return.
3051 * ppv [O] On returns, contains a pointer to the specified interface of the object.
3053 * RETURNS
3054 * Success: S_OK
3055 * Failure: HRESULT code.
3057 * NOTES
3058 * The dwClsContext parameter can be one or more of the following:
3059 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3060 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3061 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3062 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3064 * SEE ALSO
3065 * CoCreateInstance()
3067 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
3068 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
3069 REFIID iid, LPVOID *ppv)
3071 struct class_reg_data clsreg;
3072 IUnknown *regClassObject;
3073 HRESULT hres = E_UNEXPECTED;
3074 APARTMENT *apt;
3076 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
3078 if (!ppv)
3079 return E_INVALIDARG;
3081 *ppv = NULL;
3083 if (!(apt = apartment_get_current_or_mta()))
3085 ERR("apartment not initialised\n");
3086 return CO_E_NOTINITIALIZED;
3089 if (pServerInfo) {
3090 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3091 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
3094 if (CLSCTX_INPROC_SERVER & dwClsContext)
3096 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
3098 apartment_release(apt);
3099 return FTMarshalCF_Create(iid, ppv);
3101 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3102 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3105 if (CLSCTX_INPROC & dwClsContext)
3107 ACTCTX_SECTION_KEYED_DATA data;
3109 data.cbSize = sizeof(data);
3110 /* search activation context first */
3111 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3112 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3113 rclsid, &data))
3115 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3117 clsreg.u.actctx.hactctx = data.hActCtx;
3118 clsreg.u.actctx.data = data.lpData;
3119 clsreg.u.actctx.section = data.lpSectionBase;
3120 clsreg.hkey = FALSE;
3122 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3123 ReleaseActCtx(data.hActCtx);
3124 apartment_release(apt);
3125 return hres;
3130 * First, try and see if we can't match the class ID with one of the
3131 * registered classes.
3133 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3134 &regClassObject))
3136 /* Get the required interface from the retrieved pointer. */
3137 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3140 * Since QI got another reference on the pointer, we want to release the
3141 * one we already have. If QI was unsuccessful, this will release the object. This
3142 * is good since we are not returning it in the "out" parameter.
3144 IUnknown_Release(regClassObject);
3145 apartment_release(apt);
3146 return hres;
3149 /* First try in-process server */
3150 if (CLSCTX_INPROC_SERVER & dwClsContext)
3152 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3153 HKEY hkey;
3155 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3156 if (FAILED(hres))
3158 if (hres == REGDB_E_CLASSNOTREG)
3159 ERR("class %s not registered\n", debugstr_guid(rclsid));
3160 else if (hres == REGDB_E_KEYMISSING)
3162 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3163 hres = REGDB_E_CLASSNOTREG;
3167 if (SUCCEEDED(hres))
3169 clsreg.u.hkey = hkey;
3170 clsreg.hkey = TRUE;
3172 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3173 RegCloseKey(hkey);
3176 /* return if we got a class, otherwise fall through to one of the
3177 * other types */
3178 if (SUCCEEDED(hres))
3180 apartment_release(apt);
3181 return hres;
3185 /* Next try in-process handler */
3186 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3188 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3189 HKEY hkey;
3191 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3192 if (FAILED(hres))
3194 if (hres == REGDB_E_CLASSNOTREG)
3195 ERR("class %s not registered\n", debugstr_guid(rclsid));
3196 else if (hres == REGDB_E_KEYMISSING)
3198 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3199 hres = REGDB_E_CLASSNOTREG;
3203 if (SUCCEEDED(hres))
3205 clsreg.u.hkey = hkey;
3206 clsreg.hkey = TRUE;
3208 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3209 RegCloseKey(hkey);
3212 /* return if we got a class, otherwise fall through to one of the
3213 * other types */
3214 if (SUCCEEDED(hres))
3216 apartment_release(apt);
3217 return hres;
3220 apartment_release(apt);
3222 /* Next try out of process */
3223 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3225 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3226 if (SUCCEEDED(hres))
3227 return hres;
3230 /* Finally try remote: this requires networked DCOM (a lot of work) */
3231 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3233 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3234 hres = REGDB_E_CLASSNOTREG;
3237 if (FAILED(hres))
3238 ERR("no class object %s could be created for context 0x%x\n",
3239 debugstr_guid(rclsid), dwClsContext);
3240 return hres;
3243 /***********************************************************************
3244 * CoResumeClassObjects (OLE32.@)
3246 * Resumes all class objects registered with REGCLS_SUSPENDED.
3248 * RETURNS
3249 * Success: S_OK.
3250 * Failure: HRESULT code.
3252 HRESULT WINAPI CoResumeClassObjects(void)
3254 FIXME("stub\n");
3255 return S_OK;
3258 /***********************************************************************
3259 * CoCreateInstance [OLE32.@]
3261 * Creates an instance of the specified class.
3263 * PARAMS
3264 * rclsid [I] Class ID to create an instance of.
3265 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3266 * dwClsContext [I] Flags to restrict the location of the created instance.
3267 * iid [I] The ID of the interface of the instance to return.
3268 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3270 * RETURNS
3271 * Success: S_OK
3272 * Failure: HRESULT code.
3274 * NOTES
3275 * The dwClsContext parameter can be one or more of the following:
3276 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3277 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3278 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3279 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3281 * Aggregation is the concept of deferring the IUnknown of an object to another
3282 * object. This allows a separate object to behave as though it was part of
3283 * the object and to allow this the pUnkOuter parameter can be set. Note that
3284 * not all objects support having an outer of unknown.
3286 * SEE ALSO
3287 * CoGetClassObject()
3289 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3290 REFCLSID rclsid,
3291 LPUNKNOWN pUnkOuter,
3292 DWORD dwClsContext,
3293 REFIID iid,
3294 LPVOID *ppv)
3296 MULTI_QI multi_qi = { iid };
3297 HRESULT hres;
3299 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3300 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3302 if (ppv==0)
3303 return E_POINTER;
3305 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3306 *ppv = multi_qi.pItf;
3307 return hres;
3310 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3312 ULONG i;
3314 for (i = 0; i < count; i++)
3316 mqi[i].pItf = NULL;
3317 mqi[i].hr = hr;
3321 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3323 ULONG index = 0, fetched = 0;
3325 if (include_unk)
3327 mqi[0].hr = S_OK;
3328 mqi[0].pItf = unk;
3329 index = fetched = 1;
3332 for (; index < count; index++)
3334 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3335 if (mqi[index].hr == S_OK)
3336 fetched++;
3339 if (!include_unk)
3340 IUnknown_Release(unk);
3342 if (fetched == 0)
3343 return E_NOINTERFACE;
3345 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3348 /***********************************************************************
3349 * CoCreateInstanceEx [OLE32.@]
3351 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3352 REFCLSID rclsid,
3353 LPUNKNOWN pUnkOuter,
3354 DWORD dwClsContext,
3355 COSERVERINFO* pServerInfo,
3356 ULONG cmq,
3357 MULTI_QI* pResults)
3359 IUnknown *unk = NULL;
3360 IClassFactory *cf;
3361 APARTMENT *apt;
3362 CLSID clsid;
3363 HRESULT hres;
3365 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3367 if (!cmq || !pResults)
3368 return E_INVALIDARG;
3370 if (pServerInfo)
3371 FIXME("() non-NULL pServerInfo not supported!\n");
3373 init_multi_qi(cmq, pResults, E_NOINTERFACE);
3375 hres = CoGetTreatAsClass(rclsid, &clsid);
3376 if(FAILED(hres))
3377 clsid = *rclsid;
3379 if (!(apt = apartment_get_current_or_mta()))
3381 ERR("apartment not initialised\n");
3382 return CO_E_NOTINITIALIZED;
3384 apartment_release(apt);
3387 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3389 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3391 IGlobalInterfaceTable *git = get_std_git();
3392 TRACE("Retrieving GIT\n");
3393 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3396 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3397 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3398 if (FAILED(hres))
3399 return hres;
3400 return return_multi_qi(unk, cmq, pResults, TRUE);
3404 * Get a class factory to construct the object we want.
3406 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3407 if (FAILED(hres))
3408 return hres;
3411 * Create the object and don't forget to release the factory
3413 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3414 IClassFactory_Release(cf);
3415 if (FAILED(hres))
3417 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3418 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3419 else
3420 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3421 debugstr_guid(pResults[0].pIID),
3422 debugstr_guid(&clsid),hres);
3423 return hres;
3426 return return_multi_qi(unk, cmq, pResults, TRUE);
3429 /***********************************************************************
3430 * CoGetInstanceFromFile [OLE32.@]
3432 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3433 COSERVERINFO *server_info,
3434 CLSID *rclsid,
3435 IUnknown *outer,
3436 DWORD cls_context,
3437 DWORD grfmode,
3438 OLECHAR *filename,
3439 DWORD count,
3440 MULTI_QI *results
3443 IPersistFile *pf = NULL;
3444 IUnknown* unk = NULL;
3445 CLSID clsid;
3446 HRESULT hr;
3448 if (count == 0 || !results)
3449 return E_INVALIDARG;
3451 if (server_info)
3452 FIXME("() non-NULL server_info not supported\n");
3454 init_multi_qi(count, results, E_NOINTERFACE);
3456 /* optionally get CLSID from a file */
3457 if (!rclsid)
3459 hr = GetClassFile(filename, &clsid);
3460 if (FAILED(hr))
3462 ERR("failed to get CLSID from a file\n");
3463 return hr;
3466 rclsid = &clsid;
3469 hr = CoCreateInstance(rclsid,
3470 outer,
3471 cls_context,
3472 &IID_IUnknown,
3473 (void**)&unk);
3475 if (hr != S_OK)
3477 init_multi_qi(count, results, hr);
3478 return hr;
3481 /* init from file */
3482 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3483 if (FAILED(hr))
3485 init_multi_qi(count, results, hr);
3486 IUnknown_Release(unk);
3487 return hr;
3490 hr = IPersistFile_Load(pf, filename, grfmode);
3491 IPersistFile_Release(pf);
3492 if (SUCCEEDED(hr))
3493 return return_multi_qi(unk, count, results, FALSE);
3494 else
3496 init_multi_qi(count, results, hr);
3497 IUnknown_Release(unk);
3498 return hr;
3502 /***********************************************************************
3503 * CoGetInstanceFromIStorage [OLE32.@]
3505 HRESULT WINAPI CoGetInstanceFromIStorage(
3506 COSERVERINFO *server_info,
3507 CLSID *rclsid,
3508 IUnknown *outer,
3509 DWORD cls_context,
3510 IStorage *storage,
3511 DWORD count,
3512 MULTI_QI *results
3515 IPersistStorage *ps = NULL;
3516 IUnknown* unk = NULL;
3517 STATSTG stat;
3518 HRESULT hr;
3520 if (count == 0 || !results || !storage)
3521 return E_INVALIDARG;
3523 if (server_info)
3524 FIXME("() non-NULL server_info not supported\n");
3526 init_multi_qi(count, results, E_NOINTERFACE);
3528 /* optionally get CLSID from a file */
3529 if (!rclsid)
3531 memset(&stat.clsid, 0, sizeof(stat.clsid));
3532 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3533 if (FAILED(hr))
3535 ERR("failed to get CLSID from a file\n");
3536 return hr;
3539 rclsid = &stat.clsid;
3542 hr = CoCreateInstance(rclsid,
3543 outer,
3544 cls_context,
3545 &IID_IUnknown,
3546 (void**)&unk);
3548 if (hr != S_OK)
3549 return hr;
3551 /* init from IStorage */
3552 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3553 if (FAILED(hr))
3554 ERR("failed to get IPersistStorage\n");
3556 if (ps)
3558 IPersistStorage_Load(ps, storage);
3559 IPersistStorage_Release(ps);
3562 return return_multi_qi(unk, count, results, FALSE);
3565 /***********************************************************************
3566 * CoLoadLibrary (OLE32.@)
3568 * Loads a library.
3570 * PARAMS
3571 * lpszLibName [I] Path to library.
3572 * bAutoFree [I] Whether the library should automatically be freed.
3574 * RETURNS
3575 * Success: Handle to loaded library.
3576 * Failure: NULL.
3578 * SEE ALSO
3579 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3581 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3583 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3585 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3588 /***********************************************************************
3589 * CoFreeLibrary [OLE32.@]
3591 * Unloads a library from memory.
3593 * PARAMS
3594 * hLibrary [I] Handle to library to unload.
3596 * RETURNS
3597 * Nothing
3599 * SEE ALSO
3600 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3602 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3604 FreeLibrary(hLibrary);
3608 /***********************************************************************
3609 * CoFreeAllLibraries [OLE32.@]
3611 * Function for backwards compatibility only. Does nothing.
3613 * RETURNS
3614 * Nothing.
3616 * SEE ALSO
3617 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3619 void WINAPI CoFreeAllLibraries(void)
3621 /* NOP */
3624 /***********************************************************************
3625 * CoFreeUnusedLibrariesEx [OLE32.@]
3627 * Frees any previously unused libraries whose delay has expired and marks
3628 * currently unused libraries for unloading. Unused are identified as those that
3629 * return S_OK from their DllCanUnloadNow function.
3631 * PARAMS
3632 * dwUnloadDelay [I] Unload delay in milliseconds.
3633 * dwReserved [I] Reserved. Set to 0.
3635 * RETURNS
3636 * Nothing.
3638 * SEE ALSO
3639 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3641 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3643 struct apartment *apt = COM_CurrentApt();
3644 if (!apt)
3646 ERR("apartment not initialised\n");
3647 return;
3650 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3653 /***********************************************************************
3654 * CoFreeUnusedLibraries [OLE32.@]
3656 * Frees any unused libraries. Unused are identified as those that return
3657 * S_OK from their DllCanUnloadNow function.
3659 * RETURNS
3660 * Nothing.
3662 * SEE ALSO
3663 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3665 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3667 CoFreeUnusedLibrariesEx(INFINITE, 0);
3670 /***********************************************************************
3671 * CoFileTimeNow [OLE32.@]
3673 * Retrieves the current time in FILETIME format.
3675 * PARAMS
3676 * lpFileTime [O] The current time.
3678 * RETURNS
3679 * S_OK.
3681 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3683 GetSystemTimeAsFileTime( lpFileTime );
3684 return S_OK;
3687 /******************************************************************************
3688 * CoLockObjectExternal [OLE32.@]
3690 * Increments or decrements the external reference count of a stub object.
3692 * PARAMS
3693 * pUnk [I] Stub object.
3694 * fLock [I] If TRUE then increments the external ref-count,
3695 * otherwise decrements.
3696 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3697 * calling CoDisconnectObject.
3699 * RETURNS
3700 * Success: S_OK.
3701 * Failure: HRESULT code.
3703 * NOTES
3704 * If fLock is TRUE and an object is passed in that doesn't have a stub
3705 * manager then a new stub manager is created for the object.
3707 HRESULT WINAPI CoLockObjectExternal(
3708 LPUNKNOWN pUnk,
3709 BOOL fLock,
3710 BOOL fLastUnlockReleases)
3712 struct stub_manager *stubmgr;
3713 struct apartment *apt;
3715 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3716 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3718 if (!(apt = apartment_get_current_or_mta()))
3720 ERR("apartment not initialised\n");
3721 return CO_E_NOTINITIALIZED;
3724 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3725 if (!stubmgr)
3727 WARN("stub object not found %p\n", pUnk);
3728 /* Note: native is pretty broken here because it just silently
3729 * fails, without returning an appropriate error code, making apps
3730 * think that the object was disconnected, when it actually wasn't */
3731 apartment_release(apt);
3732 return S_OK;
3735 if (fLock)
3736 stub_manager_ext_addref(stubmgr, 1, FALSE);
3737 else
3738 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3740 stub_manager_int_release(stubmgr);
3741 apartment_release(apt);
3742 return S_OK;
3745 /***********************************************************************
3746 * CoInitializeWOW (OLE32.@)
3748 * WOW equivalent of CoInitialize?
3750 * PARAMS
3751 * x [I] Unknown.
3752 * y [I] Unknown.
3754 * RETURNS
3755 * Unknown.
3757 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3759 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3760 return 0;
3763 /***********************************************************************
3764 * CoGetState [OLE32.@]
3766 * Retrieves the thread state object previously stored by CoSetState().
3768 * PARAMS
3769 * ppv [I] Address where pointer to object will be stored.
3771 * RETURNS
3772 * Success: S_OK.
3773 * Failure: E_OUTOFMEMORY.
3775 * NOTES
3776 * Crashes on all invalid ppv addresses, including NULL.
3777 * If the function returns a non-NULL object then the caller must release its
3778 * reference on the object when the object is no longer required.
3780 * SEE ALSO
3781 * CoSetState().
3783 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3785 struct oletls *info = COM_CurrentInfo();
3786 if (!info) return E_OUTOFMEMORY;
3788 *ppv = NULL;
3790 if (info->state)
3792 IUnknown_AddRef(info->state);
3793 *ppv = info->state;
3794 TRACE("apt->state=%p\n", info->state);
3797 return S_OK;
3800 /***********************************************************************
3801 * CoSetState [OLE32.@]
3803 * Sets the thread state object.
3805 * PARAMS
3806 * pv [I] Pointer to state object to be stored.
3808 * NOTES
3809 * The system keeps a reference on the object while the object stored.
3811 * RETURNS
3812 * Success: S_OK.
3813 * Failure: E_OUTOFMEMORY.
3815 HRESULT WINAPI CoSetState(IUnknown * pv)
3817 struct oletls *info = COM_CurrentInfo();
3818 if (!info) return E_OUTOFMEMORY;
3820 if (pv) IUnknown_AddRef(pv);
3822 if (info->state)
3824 TRACE("-- release %p now\n", info->state);
3825 IUnknown_Release(info->state);
3828 info->state = pv;
3830 return S_OK;
3834 /******************************************************************************
3835 * CoTreatAsClass [OLE32.@]
3837 * Sets the TreatAs value of a class.
3839 * PARAMS
3840 * clsidOld [I] Class to set TreatAs value on.
3841 * clsidNew [I] The class the clsidOld should be treated as.
3843 * RETURNS
3844 * Success: S_OK.
3845 * Failure: HRESULT code.
3847 * SEE ALSO
3848 * CoGetTreatAsClass
3850 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3852 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3853 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3854 HKEY hkey = NULL;
3855 WCHAR szClsidNew[CHARS_IN_GUID];
3856 HRESULT res = S_OK;
3857 WCHAR auto_treat_as[CHARS_IN_GUID];
3858 LONG auto_treat_as_size = sizeof(auto_treat_as);
3859 CLSID id;
3861 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3862 if (FAILED(res))
3863 goto done;
3865 if (IsEqualGUID( clsidOld, clsidNew ))
3867 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3868 CLSIDFromString(auto_treat_as, &id) == S_OK)
3870 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3872 res = REGDB_E_WRITEREGDB;
3873 goto done;
3876 else
3878 if(RegDeleteKeyW(hkey, wszTreatAs))
3879 res = REGDB_E_WRITEREGDB;
3880 goto done;
3883 else
3885 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3886 RegDeleteKeyW(hkey, wszTreatAs);
3887 }else{
3888 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAY_SIZE(szClsidNew))){
3889 WARN("StringFromGUID2 failed\n");
3890 res = E_FAIL;
3891 goto done;
3894 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3895 WARN("RegSetValue failed\n");
3896 res = REGDB_E_WRITEREGDB;
3897 goto done;
3902 done:
3903 if (hkey) RegCloseKey(hkey);
3904 return res;
3907 /******************************************************************************
3908 * CoGetTreatAsClass [OLE32.@]
3910 * Gets the TreatAs value of a class.
3912 * PARAMS
3913 * clsidOld [I] Class to get the TreatAs value of.
3914 * clsidNew [I] The class the clsidOld should be treated as.
3916 * RETURNS
3917 * Success: S_OK.
3918 * Failure: HRESULT code.
3920 * SEE ALSO
3921 * CoSetTreatAsClass
3923 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3925 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3926 HKEY hkey = NULL;
3927 WCHAR szClsidNew[CHARS_IN_GUID];
3928 HRESULT res = S_OK;
3929 LONG len = sizeof(szClsidNew);
3931 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3933 if (!clsidOld || !clsidNew)
3934 return E_INVALIDARG;
3936 *clsidNew = *clsidOld; /* copy over old value */
3938 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3939 if (FAILED(res))
3941 res = S_FALSE;
3942 goto done;
3944 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3946 res = S_FALSE;
3947 goto done;
3949 res = CLSIDFromString(szClsidNew,clsidNew);
3950 if (FAILED(res))
3951 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3952 done:
3953 if (hkey) RegCloseKey(hkey);
3954 return res;
3957 /******************************************************************************
3958 * CoGetCurrentProcess [OLE32.@]
3960 * Gets the current process ID.
3962 * RETURNS
3963 * The current process ID.
3965 * NOTES
3966 * Is DWORD really the correct return type for this function?
3968 DWORD WINAPI CoGetCurrentProcess(void)
3970 return GetCurrentProcessId();
3973 /***********************************************************************
3974 * CoGetCurrentLogicalThreadId [OLE32.@]
3976 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
3978 TRACE("(%p)\n", id);
3980 if (!id)
3981 return E_INVALIDARG;
3983 *id = COM_CurrentCausalityId();
3984 return S_OK;
3987 /******************************************************************************
3988 * CoRegisterMessageFilter [OLE32.@]
3990 * Registers a message filter.
3992 * PARAMS
3993 * lpMessageFilter [I] Pointer to interface.
3994 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3996 * RETURNS
3997 * Success: S_OK.
3998 * Failure: HRESULT code.
4000 * NOTES
4001 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
4002 * lpMessageFilter removes the message filter.
4004 * If lplpMessageFilter is not NULL the previous message filter will be
4005 * returned in the memory pointer to this parameter and the caller is
4006 * responsible for releasing the object.
4008 * The current thread be in an apartment otherwise the function will crash.
4010 HRESULT WINAPI CoRegisterMessageFilter(
4011 LPMESSAGEFILTER lpMessageFilter,
4012 LPMESSAGEFILTER *lplpMessageFilter)
4014 struct apartment *apt;
4015 IMessageFilter *lpOldMessageFilter;
4017 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
4019 apt = COM_CurrentApt();
4021 /* can't set a message filter in a multi-threaded apartment */
4022 if (!apt || apt->multi_threaded)
4024 WARN("can't set message filter in MTA or uninitialized apt\n");
4025 return CO_E_NOT_SUPPORTED;
4028 if (lpMessageFilter)
4029 IMessageFilter_AddRef(lpMessageFilter);
4031 EnterCriticalSection(&apt->cs);
4033 lpOldMessageFilter = apt->filter;
4034 apt->filter = lpMessageFilter;
4036 LeaveCriticalSection(&apt->cs);
4038 if (lplpMessageFilter)
4039 *lplpMessageFilter = lpOldMessageFilter;
4040 else if (lpOldMessageFilter)
4041 IMessageFilter_Release(lpOldMessageFilter);
4043 return S_OK;
4046 /***********************************************************************
4047 * CoIsOle1Class [OLE32.@]
4049 * Determines whether the specified class an OLE v1 class.
4051 * PARAMS
4052 * clsid [I] Class to test.
4054 * RETURNS
4055 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
4057 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
4059 FIXME("%s\n", debugstr_guid(clsid));
4060 return FALSE;
4063 /***********************************************************************
4064 * IsEqualGUID [OLE32.@]
4066 * Compares two Unique Identifiers.
4068 * PARAMS
4069 * rguid1 [I] The first GUID to compare.
4070 * rguid2 [I] The other GUID to compare.
4072 * RETURNS
4073 * TRUE if equal
4075 #undef IsEqualGUID
4076 BOOL WINAPI IsEqualGUID(
4077 REFGUID rguid1,
4078 REFGUID rguid2)
4080 return !memcmp(rguid1,rguid2,sizeof(GUID));
4083 /***********************************************************************
4084 * CoInitializeSecurity [OLE32.@]
4086 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
4087 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
4088 void* pReserved1, DWORD dwAuthnLevel,
4089 DWORD dwImpLevel, void* pReserved2,
4090 DWORD dwCapabilities, void* pReserved3)
4092 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
4093 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
4094 dwCapabilities, pReserved3);
4095 return S_OK;
4098 /***********************************************************************
4099 * CoSuspendClassObjects [OLE32.@]
4101 * Suspends all registered class objects to prevent further requests coming in
4102 * for those objects.
4104 * RETURNS
4105 * Success: S_OK.
4106 * Failure: HRESULT code.
4108 HRESULT WINAPI CoSuspendClassObjects(void)
4110 FIXME("\n");
4111 return S_OK;
4114 /***********************************************************************
4115 * CoAddRefServerProcess [OLE32.@]
4117 * Helper function for incrementing the reference count of a local-server
4118 * process.
4120 * RETURNS
4121 * New reference count.
4123 * SEE ALSO
4124 * CoReleaseServerProcess().
4126 ULONG WINAPI CoAddRefServerProcess(void)
4128 ULONG refs;
4130 TRACE("\n");
4132 EnterCriticalSection(&csRegisteredClassList);
4133 refs = ++s_COMServerProcessReferences;
4134 LeaveCriticalSection(&csRegisteredClassList);
4136 TRACE("refs before: %d\n", refs - 1);
4138 return refs;
4141 /***********************************************************************
4142 * CoReleaseServerProcess [OLE32.@]
4144 * Helper function for decrementing the reference count of a local-server
4145 * process.
4147 * RETURNS
4148 * New reference count.
4150 * NOTES
4151 * When reference count reaches 0, this function suspends all registered
4152 * classes so no new connections are accepted.
4154 * SEE ALSO
4155 * CoAddRefServerProcess(), CoSuspendClassObjects().
4157 ULONG WINAPI CoReleaseServerProcess(void)
4159 ULONG refs;
4161 TRACE("\n");
4163 EnterCriticalSection(&csRegisteredClassList);
4165 refs = --s_COMServerProcessReferences;
4166 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4168 LeaveCriticalSection(&csRegisteredClassList);
4170 TRACE("refs after: %d\n", refs);
4172 return refs;
4175 /***********************************************************************
4176 * CoIsHandlerConnected [OLE32.@]
4178 * Determines whether a proxy is connected to a remote stub.
4180 * PARAMS
4181 * pUnk [I] Pointer to object that may or may not be connected.
4183 * RETURNS
4184 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4185 * FALSE otherwise.
4187 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4189 FIXME("%p\n", pUnk);
4191 return TRUE;
4194 /***********************************************************************
4195 * CoAllowSetForegroundWindow [OLE32.@]
4198 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4200 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4201 return S_OK;
4204 /***********************************************************************
4205 * CoQueryProxyBlanket [OLE32.@]
4207 * Retrieves the security settings being used by a proxy.
4209 * PARAMS
4210 * pProxy [I] Pointer to the proxy object.
4211 * pAuthnSvc [O] The type of authentication service.
4212 * pAuthzSvc [O] The type of authorization service.
4213 * ppServerPrincName [O] Optional. The server prinicple name.
4214 * pAuthnLevel [O] The authentication level.
4215 * pImpLevel [O] The impersonation level.
4216 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4217 * pCapabilities [O] Flags affecting the security behaviour.
4219 * RETURNS
4220 * Success: S_OK.
4221 * Failure: HRESULT code.
4223 * SEE ALSO
4224 * CoCopyProxy, CoSetProxyBlanket.
4226 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4227 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4228 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4230 IClientSecurity *pCliSec;
4231 HRESULT hr;
4233 TRACE("%p\n", pProxy);
4235 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4236 if (SUCCEEDED(hr))
4238 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4239 pAuthzSvc, ppServerPrincName,
4240 pAuthnLevel, pImpLevel, ppAuthInfo,
4241 pCapabilities);
4242 IClientSecurity_Release(pCliSec);
4245 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4246 return hr;
4249 /***********************************************************************
4250 * CoSetProxyBlanket [OLE32.@]
4252 * Sets the security settings for a proxy.
4254 * PARAMS
4255 * pProxy [I] Pointer to the proxy object.
4256 * AuthnSvc [I] The type of authentication service.
4257 * AuthzSvc [I] The type of authorization service.
4258 * pServerPrincName [I] The server prinicple name.
4259 * AuthnLevel [I] The authentication level.
4260 * ImpLevel [I] The impersonation level.
4261 * pAuthInfo [I] Information specific to the authorization/authentication service.
4262 * Capabilities [I] Flags affecting the security behaviour.
4264 * RETURNS
4265 * Success: S_OK.
4266 * Failure: HRESULT code.
4268 * SEE ALSO
4269 * CoQueryProxyBlanket, CoCopyProxy.
4271 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4272 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4273 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4275 IClientSecurity *pCliSec;
4276 HRESULT hr;
4278 TRACE("%p\n", pProxy);
4280 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4281 if (SUCCEEDED(hr))
4283 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4284 AuthzSvc, pServerPrincName,
4285 AuthnLevel, ImpLevel, pAuthInfo,
4286 Capabilities);
4287 IClientSecurity_Release(pCliSec);
4290 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4291 return hr;
4294 /***********************************************************************
4295 * CoCopyProxy [OLE32.@]
4297 * Copies a proxy.
4299 * PARAMS
4300 * pProxy [I] Pointer to the proxy object.
4301 * ppCopy [O] Copy of the proxy.
4303 * RETURNS
4304 * Success: S_OK.
4305 * Failure: HRESULT code.
4307 * SEE ALSO
4308 * CoQueryProxyBlanket, CoSetProxyBlanket.
4310 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4312 IClientSecurity *pCliSec;
4313 HRESULT hr;
4315 TRACE("%p\n", pProxy);
4317 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4318 if (SUCCEEDED(hr))
4320 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4321 IClientSecurity_Release(pCliSec);
4324 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4325 return hr;
4329 /***********************************************************************
4330 * CoGetCallContext [OLE32.@]
4332 * Gets the context of the currently executing server call in the current
4333 * thread.
4335 * PARAMS
4336 * riid [I] Context interface to return.
4337 * ppv [O] Pointer to memory that will receive the context on return.
4339 * RETURNS
4340 * Success: S_OK.
4341 * Failure: HRESULT code.
4343 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4345 struct oletls *info = COM_CurrentInfo();
4347 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4349 if (!info)
4350 return E_OUTOFMEMORY;
4352 if (!info->call_state)
4353 return RPC_E_CALL_COMPLETE;
4355 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4358 /***********************************************************************
4359 * CoSwitchCallContext [OLE32.@]
4361 * Switches the context of the currently executing server call in the current
4362 * thread.
4364 * PARAMS
4365 * pObject [I] Pointer to new context object
4366 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4368 * RETURNS
4369 * Success: S_OK.
4370 * Failure: HRESULT code.
4372 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4374 struct oletls *info = COM_CurrentInfo();
4376 TRACE("(%p, %p)\n", pObject, ppOldObject);
4378 if (!info)
4379 return E_OUTOFMEMORY;
4381 *ppOldObject = info->call_state;
4382 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4384 return S_OK;
4387 /***********************************************************************
4388 * CoQueryClientBlanket [OLE32.@]
4390 * Retrieves the authentication information about the client of the currently
4391 * executing server call in the current thread.
4393 * PARAMS
4394 * pAuthnSvc [O] Optional. The type of authentication service.
4395 * pAuthzSvc [O] Optional. The type of authorization service.
4396 * pServerPrincName [O] Optional. The server prinicple name.
4397 * pAuthnLevel [O] Optional. The authentication level.
4398 * pImpLevel [O] Optional. The impersonation level.
4399 * pPrivs [O] Optional. Information about the privileges of the client.
4400 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4402 * RETURNS
4403 * Success: S_OK.
4404 * Failure: HRESULT code.
4406 * SEE ALSO
4407 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4409 HRESULT WINAPI CoQueryClientBlanket(
4410 DWORD *pAuthnSvc,
4411 DWORD *pAuthzSvc,
4412 OLECHAR **pServerPrincName,
4413 DWORD *pAuthnLevel,
4414 DWORD *pImpLevel,
4415 RPC_AUTHZ_HANDLE *pPrivs,
4416 DWORD *pCapabilities)
4418 IServerSecurity *pSrvSec;
4419 HRESULT hr;
4421 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4422 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4423 pPrivs, pCapabilities);
4425 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4426 if (SUCCEEDED(hr))
4428 hr = IServerSecurity_QueryBlanket(
4429 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4430 pImpLevel, pPrivs, pCapabilities);
4431 IServerSecurity_Release(pSrvSec);
4434 return hr;
4437 /***********************************************************************
4438 * CoImpersonateClient [OLE32.@]
4440 * Impersonates the client of the currently executing server call in the
4441 * current thread.
4443 * PARAMS
4444 * None.
4446 * RETURNS
4447 * Success: S_OK.
4448 * Failure: HRESULT code.
4450 * NOTES
4451 * If this function fails then the current thread will not be impersonating
4452 * the client and all actions will take place on behalf of the server.
4453 * Therefore, it is important to check the return value from this function.
4455 * SEE ALSO
4456 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4458 HRESULT WINAPI CoImpersonateClient(void)
4460 IServerSecurity *pSrvSec;
4461 HRESULT hr;
4463 TRACE("\n");
4465 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4466 if (SUCCEEDED(hr))
4468 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4469 IServerSecurity_Release(pSrvSec);
4472 return hr;
4475 /***********************************************************************
4476 * CoRevertToSelf [OLE32.@]
4478 * Ends the impersonation of the client of the currently executing server
4479 * call in the current thread.
4481 * PARAMS
4482 * None.
4484 * RETURNS
4485 * Success: S_OK.
4486 * Failure: HRESULT code.
4488 * SEE ALSO
4489 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4491 HRESULT WINAPI CoRevertToSelf(void)
4493 IServerSecurity *pSrvSec;
4494 HRESULT hr;
4496 TRACE("\n");
4498 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4499 if (SUCCEEDED(hr))
4501 hr = IServerSecurity_RevertToSelf(pSrvSec);
4502 IServerSecurity_Release(pSrvSec);
4505 return hr;
4508 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4510 /* first try to retrieve messages for incoming COM calls to the apartment window */
4511 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4512 /* next retrieve other messages necessary for the app to remain responsive */
4513 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4514 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4517 /***********************************************************************
4518 * CoWaitForMultipleHandles [OLE32.@]
4520 * Waits for one or more handles to become signaled.
4522 * PARAMS
4523 * dwFlags [I] Flags. See notes.
4524 * dwTimeout [I] Timeout in milliseconds.
4525 * cHandles [I] Number of handles pointed to by pHandles.
4526 * pHandles [I] Handles to wait for.
4527 * lpdwindex [O] Index of handle that was signaled.
4529 * RETURNS
4530 * Success: S_OK.
4531 * Failure: RPC_S_CALLPENDING on timeout.
4533 * NOTES
4535 * The dwFlags parameter can be zero or more of the following:
4536 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4537 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4539 * SEE ALSO
4540 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4542 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4543 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4545 HRESULT hr = S_OK;
4546 DWORD start_time = GetTickCount();
4547 APARTMENT *apt = COM_CurrentApt();
4548 BOOL message_loop = apt && !apt->multi_threaded;
4549 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4550 BOOL post_quit = FALSE;
4551 UINT exit_code;
4553 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4554 pHandles, lpdwindex);
4556 if (!lpdwindex)
4557 return E_INVALIDARG;
4559 *lpdwindex = 0;
4561 if (!pHandles)
4562 return E_INVALIDARG;
4564 if (!cHandles)
4565 return RPC_E_NO_SYNC;
4567 while (TRUE)
4569 DWORD now = GetTickCount();
4570 DWORD res;
4572 if (now - start_time > dwTimeout)
4574 hr = RPC_S_CALLPENDING;
4575 break;
4578 if (message_loop)
4580 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4581 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4583 TRACE("waiting for rpc completion or window message\n");
4585 res = WAIT_TIMEOUT;
4587 if (check_apc)
4589 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4590 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4591 check_apc = FALSE;
4594 if (res == WAIT_TIMEOUT)
4595 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4596 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4597 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4599 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4601 MSG msg;
4602 int count = 0;
4604 /* call message filter */
4606 if (COM_CurrentApt()->filter)
4608 PENDINGTYPE pendingtype =
4609 COM_CurrentInfo()->pending_call_count_server ?
4610 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4611 DWORD be_handled = IMessageFilter_MessagePending(
4612 COM_CurrentApt()->filter, 0 /* FIXME */,
4613 now - start_time, pendingtype);
4614 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4615 switch (be_handled)
4617 case PENDINGMSG_CANCELCALL:
4618 WARN("call canceled\n");
4619 hr = RPC_E_CALL_CANCELED;
4620 break;
4621 case PENDINGMSG_WAITNOPROCESS:
4622 case PENDINGMSG_WAITDEFPROCESS:
4623 default:
4624 /* FIXME: MSDN is very vague about the difference
4625 * between WAITNOPROCESS and WAITDEFPROCESS - there
4626 * appears to be none, so it is possibly a left-over
4627 * from the 16-bit world. */
4628 break;
4632 if (!apt->win)
4634 /* If window is NULL on apartment, peek at messages so that it will not trigger
4635 * MsgWaitForMultipleObjects next time. */
4636 PeekMessageW(NULL, NULL, 0, 0, PM_QS_POSTMESSAGE | PM_NOREMOVE | PM_NOYIELD);
4638 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4639 * so after processing 100 messages we go back to checking the wait handles */
4640 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4642 if (msg.message == WM_QUIT)
4644 TRACE("received WM_QUIT message\n");
4645 post_quit = TRUE;
4646 exit_code = msg.wParam;
4648 else
4650 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4651 TranslateMessage(&msg);
4652 DispatchMessageW(&msg);
4655 continue;
4658 else
4660 TRACE("waiting for rpc completion\n");
4662 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4663 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4664 (dwFlags & COWAIT_ALERTABLE) != 0);
4667 switch (res)
4669 case WAIT_TIMEOUT:
4670 hr = RPC_S_CALLPENDING;
4671 break;
4672 case WAIT_FAILED:
4673 hr = HRESULT_FROM_WIN32( GetLastError() );
4674 break;
4675 default:
4676 *lpdwindex = res;
4677 break;
4679 break;
4681 if (post_quit) PostQuitMessage(exit_code);
4682 TRACE("-- 0x%08x\n", hr);
4683 return hr;
4687 /***********************************************************************
4688 * CoGetObject [OLE32.@]
4690 * Gets the object named by converting the name to a moniker and binding to it.
4692 * PARAMS
4693 * pszName [I] String representing the object.
4694 * pBindOptions [I] Parameters affecting the binding to the named object.
4695 * riid [I] Interface to bind to on the objecct.
4696 * ppv [O] On output, the interface riid of the object represented
4697 * by pszName.
4699 * RETURNS
4700 * Success: S_OK.
4701 * Failure: HRESULT code.
4703 * SEE ALSO
4704 * MkParseDisplayName.
4706 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4707 REFIID riid, void **ppv)
4709 IBindCtx *pbc;
4710 HRESULT hr;
4712 *ppv = NULL;
4714 hr = CreateBindCtx(0, &pbc);
4715 if (SUCCEEDED(hr))
4717 if (pBindOptions)
4718 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4720 if (SUCCEEDED(hr))
4722 ULONG chEaten;
4723 IMoniker *pmk;
4725 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4726 if (SUCCEEDED(hr))
4728 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4729 IMoniker_Release(pmk);
4733 IBindCtx_Release(pbc);
4735 return hr;
4738 /***********************************************************************
4739 * CoRegisterChannelHook [OLE32.@]
4741 * Registers a process-wide hook that is called during ORPC calls.
4743 * PARAMS
4744 * guidExtension [I] GUID of the channel hook to register.
4745 * pChannelHook [I] Channel hook object to register.
4747 * RETURNS
4748 * Success: S_OK.
4749 * Failure: HRESULT code.
4751 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4753 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4755 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4758 typedef struct Context
4760 IComThreadingInfo IComThreadingInfo_iface;
4761 IContextCallback IContextCallback_iface;
4762 IObjContext IObjContext_iface;
4763 LONG refs;
4764 } Context;
4766 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4768 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4771 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4773 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4776 static inline Context *impl_from_IObjContext( IObjContext *iface )
4778 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4781 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4783 *ppv = NULL;
4785 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4786 IsEqualIID(riid, &IID_IUnknown))
4788 *ppv = &iface->IComThreadingInfo_iface;
4790 else if (IsEqualIID(riid, &IID_IContextCallback))
4792 *ppv = &iface->IContextCallback_iface;
4794 else if (IsEqualIID(riid, &IID_IObjContext))
4796 *ppv = &iface->IObjContext_iface;
4799 if (*ppv)
4801 IUnknown_AddRef((IUnknown*)*ppv);
4802 return S_OK;
4805 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4806 return E_NOINTERFACE;
4809 static ULONG Context_AddRef(Context *This)
4811 return InterlockedIncrement(&This->refs);
4814 static ULONG Context_Release(Context *This)
4816 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4817 releasing context while refcount is at 0 destroys it. */
4818 if (!This->refs)
4820 HeapFree(GetProcessHeap(), 0, This);
4821 return 0;
4824 return InterlockedDecrement(&This->refs);
4827 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4829 Context *This = impl_from_IComThreadingInfo(iface);
4830 return Context_QueryInterface(This, riid, ppv);
4833 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4835 Context *This = impl_from_IComThreadingInfo(iface);
4836 return Context_AddRef(This);
4839 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4841 Context *This = impl_from_IComThreadingInfo(iface);
4842 return Context_Release(This);
4845 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4847 APTTYPEQUALIFIER qualifier;
4849 TRACE("(%p)\n", apttype);
4851 return CoGetApartmentType(apttype, &qualifier);
4854 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4856 APTTYPEQUALIFIER qualifier;
4857 APTTYPE apttype;
4858 HRESULT hr;
4860 hr = CoGetApartmentType(&apttype, &qualifier);
4861 if (FAILED(hr))
4862 return hr;
4864 TRACE("(%p)\n", thdtype);
4866 switch (apttype)
4868 case APTTYPE_STA:
4869 case APTTYPE_MAINSTA:
4870 *thdtype = THDTYPE_PROCESSMESSAGES;
4871 break;
4872 default:
4873 *thdtype = THDTYPE_BLOCKMESSAGES;
4874 break;
4876 return S_OK;
4879 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4881 TRACE("(%p)\n", logical_thread_id);
4882 return CoGetCurrentLogicalThreadId(logical_thread_id);
4885 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4887 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4888 return E_NOTIMPL;
4891 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4893 Context_CTI_QueryInterface,
4894 Context_CTI_AddRef,
4895 Context_CTI_Release,
4896 Context_CTI_GetCurrentApartmentType,
4897 Context_CTI_GetCurrentThreadType,
4898 Context_CTI_GetCurrentLogicalThreadId,
4899 Context_CTI_SetCurrentLogicalThreadId
4902 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4904 Context *This = impl_from_IContextCallback(iface);
4905 return Context_QueryInterface(This, riid, ppv);
4908 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4910 Context *This = impl_from_IContextCallback(iface);
4911 return Context_AddRef(This);
4914 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4916 Context *This = impl_from_IContextCallback(iface);
4917 return Context_Release(This);
4920 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4921 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4923 Context *This = impl_from_IContextCallback(iface);
4925 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4926 return E_NOTIMPL;
4929 static const IContextCallbackVtbl Context_Callback_Vtbl =
4931 Context_CC_QueryInterface,
4932 Context_CC_AddRef,
4933 Context_CC_Release,
4934 Context_CC_ContextCallback
4937 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4939 Context *This = impl_from_IObjContext(iface);
4940 return Context_QueryInterface(This, riid, ppv);
4943 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4945 Context *This = impl_from_IObjContext(iface);
4946 return Context_AddRef(This);
4949 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4951 Context *This = impl_from_IObjContext(iface);
4952 return Context_Release(This);
4955 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4957 Context *This = impl_from_IObjContext(iface);
4959 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4960 return E_NOTIMPL;
4963 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4965 Context *This = impl_from_IObjContext(iface);
4967 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4968 return E_NOTIMPL;
4971 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4973 Context *This = impl_from_IObjContext(iface);
4975 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4976 return E_NOTIMPL;
4979 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4981 Context *This = impl_from_IObjContext(iface);
4983 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4984 return E_NOTIMPL;
4987 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4989 Context *This = impl_from_IObjContext(iface);
4990 FIXME("(%p/%p)\n", This, iface);
4993 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4995 Context *This = impl_from_IObjContext(iface);
4996 FIXME("(%p/%p)\n", This, iface);
4999 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
5001 Context *This = impl_from_IObjContext(iface);
5002 FIXME("(%p/%p)\n", This, iface);
5005 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
5007 Context *This = impl_from_IObjContext(iface);
5008 FIXME("(%p/%p)\n", This, iface);
5011 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
5013 Context *This = impl_from_IObjContext(iface);
5014 FIXME("(%p/%p)\n", This, iface);
5017 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
5019 Context *This = impl_from_IObjContext(iface);
5020 FIXME("(%p/%p)\n", This, iface);
5023 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
5025 Context *This = impl_from_IObjContext(iface);
5026 FIXME("(%p/%p)\n", This, iface);
5029 static const IObjContextVtbl Context_Object_Vtbl =
5031 Context_OC_QueryInterface,
5032 Context_OC_AddRef,
5033 Context_OC_Release,
5034 Context_OC_SetProperty,
5035 Context_OC_RemoveProperty,
5036 Context_OC_GetProperty,
5037 Context_OC_EnumContextProps,
5038 Context_OC_Reserved1,
5039 Context_OC_Reserved2,
5040 Context_OC_Reserved3,
5041 Context_OC_Reserved4,
5042 Context_OC_Reserved5,
5043 Context_OC_Reserved6,
5044 Context_OC_Reserved7
5047 /***********************************************************************
5048 * CoGetObjectContext [OLE32.@]
5050 * Retrieves an object associated with the current context (i.e. apartment).
5052 * PARAMS
5053 * riid [I] ID of the interface of the object to retrieve.
5054 * ppv [O] Address where object will be stored on return.
5056 * RETURNS
5057 * Success: S_OK.
5058 * Failure: HRESULT code.
5060 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
5062 IObjContext *context;
5063 HRESULT hr;
5065 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
5067 *ppv = NULL;
5068 hr = CoGetContextToken((ULONG_PTR*)&context);
5069 if (FAILED(hr))
5070 return hr;
5072 return IObjContext_QueryInterface(context, riid, ppv);
5075 /***********************************************************************
5076 * CoGetContextToken [OLE32.@]
5078 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
5080 struct oletls *info = COM_CurrentInfo();
5081 APARTMENT *apt;
5083 TRACE("(%p)\n", token);
5085 if (!info)
5086 return E_OUTOFMEMORY;
5088 if (!(apt = apartment_get_current_or_mta()))
5090 ERR("apartment not initialised\n");
5091 return CO_E_NOTINITIALIZED;
5093 apartment_release(apt);
5095 if (!token)
5096 return E_POINTER;
5098 if (!info->context_token)
5100 Context *context;
5102 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
5103 if (!context)
5104 return E_OUTOFMEMORY;
5106 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
5107 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
5108 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
5109 /* Context token does not take a reference, it's always zero until the
5110 interface is explicitly requested with CoGetObjectContext(). */
5111 context->refs = 0;
5113 info->context_token = &context->IObjContext_iface;
5116 *token = (ULONG_PTR)info->context_token;
5117 TRACE("context_token=%p\n", info->context_token);
5119 return S_OK;
5122 /***********************************************************************
5123 * CoGetDefaultContext [OLE32.@]
5125 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5127 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5128 return E_NOINTERFACE;
5131 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5133 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5134 HKEY hkey;
5135 HRESULT hres;
5137 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5138 if (SUCCEEDED(hres))
5140 struct class_reg_data regdata;
5141 WCHAR dllpath[MAX_PATH+1];
5143 regdata.u.hkey = hkey;
5144 regdata.hkey = TRUE;
5146 if (get_object_dll_path(&regdata, dllpath, ARRAY_SIZE(dllpath)))
5148 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5149 if (!strcmpiW(dllpath, wszOle32))
5151 RegCloseKey(hkey);
5152 return HandlerCF_Create(rclsid, riid, ppv);
5155 else
5156 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5157 RegCloseKey(hkey);
5160 return CLASS_E_CLASSNOTAVAILABLE;
5163 /***********************************************************************
5164 * CoGetApartmentType [OLE32.@]
5166 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5168 struct oletls *info = COM_CurrentInfo();
5169 APARTMENT *apt;
5171 TRACE("(%p, %p)\n", type, qualifier);
5173 if (!type || !qualifier)
5174 return E_INVALIDARG;
5176 if (!info)
5177 return E_OUTOFMEMORY;
5179 if (!info->apt)
5180 *type = APTTYPE_CURRENT;
5181 else if (info->apt->multi_threaded)
5182 *type = APTTYPE_MTA;
5183 else if (info->apt->main)
5184 *type = APTTYPE_MAINSTA;
5185 else
5186 *type = APTTYPE_STA;
5188 *qualifier = APTTYPEQUALIFIER_NONE;
5190 if (!info->apt && (apt = apartment_find_mta()))
5192 apartment_release(apt);
5193 *type = APTTYPE_MTA;
5194 *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
5197 return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5200 /***********************************************************************
5201 * CoRegisterSurrogate [OLE32.@]
5203 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5205 FIXME("(%p): stub\n", surrogate);
5207 return E_NOTIMPL;
5210 /***********************************************************************
5211 * CoRegisterSurrogateEx [OLE32.@]
5213 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5215 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5217 return E_NOTIMPL;
5220 typedef struct {
5221 IGlobalOptions IGlobalOptions_iface;
5222 LONG ref;
5223 } GlobalOptions;
5225 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5227 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5230 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5232 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5234 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5236 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5238 *ppv = iface;
5240 else
5242 *ppv = NULL;
5243 return E_NOINTERFACE;
5246 IUnknown_AddRef((IUnknown*)*ppv);
5247 return S_OK;
5250 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5252 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5253 LONG ref = InterlockedIncrement(&This->ref);
5255 TRACE("(%p) ref=%d\n", This, ref);
5257 return ref;
5260 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5262 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5263 LONG ref = InterlockedDecrement(&This->ref);
5265 TRACE("(%p) ref=%d\n", This, ref);
5267 if (!ref)
5268 heap_free(This);
5270 return ref;
5273 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5275 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5276 FIXME("(%p)->(%u %lx)\n", This, property, value);
5277 return S_OK;
5280 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5282 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5283 FIXME("(%p)->(%u %p)\n", This, property, value);
5284 return E_NOTIMPL;
5287 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5288 GlobalOptions_QueryInterface,
5289 GlobalOptions_AddRef,
5290 GlobalOptions_Release,
5291 GlobalOptions_Set,
5292 GlobalOptions_Query
5295 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5297 GlobalOptions *global_options;
5298 HRESULT hres;
5300 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5302 if (outer)
5303 return E_INVALIDARG;
5305 global_options = heap_alloc(sizeof(*global_options));
5306 if (!global_options)
5307 return E_OUTOFMEMORY;
5308 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5309 global_options->ref = 1;
5311 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5312 IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5313 return hres;
5316 /***********************************************************************
5317 * DllMain (OLE32.@)
5319 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5321 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5323 switch(fdwReason) {
5324 case DLL_PROCESS_ATTACH:
5325 hProxyDll = hinstDLL;
5326 break;
5328 case DLL_PROCESS_DETACH:
5329 if (reserved) break;
5330 release_std_git();
5331 if(apt_win_class)
5332 UnregisterClassW( (const WCHAR*)MAKEINTATOM(apt_win_class), hProxyDll );
5333 RPC_UnregisterAllChannelHooks();
5334 COMPOBJ_DllList_Free();
5335 DeleteCriticalSection(&csRegisteredClassList);
5336 DeleteCriticalSection(&csApartment);
5337 break;
5339 case DLL_THREAD_DETACH:
5340 COM_TlsDestroy();
5341 break;
5343 return TRUE;
5346 /***********************************************************************
5347 * DllRegisterServer (OLE32.@)
5349 HRESULT WINAPI DllRegisterServer(void)
5351 return OLE32_DllRegisterServer();
5354 /***********************************************************************
5355 * DllUnregisterServer (OLE32.@)
5357 HRESULT WINAPI DllUnregisterServer(void)
5359 return OLE32_DllUnregisterServer();