ddraw/tests: Mark GetDC() failures on VMware as broken.
[wine.git] / dlls / ole32 / compobj.c
blobd136ee623a274175af20d3cfce9a915b85c3593a
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 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
75 /****************************************************************************
76 * This section defines variables internal to the COM module.
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
86 0, 0, &csApartment,
87 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
92 enum comclass_threadingmodel
94 ThreadingModel_Apartment = 1,
95 ThreadingModel_Free = 2,
96 ThreadingModel_No = 3,
97 ThreadingModel_Both = 4,
98 ThreadingModel_Neutral = 5
101 enum comclass_miscfields
103 MiscStatus = 1,
104 MiscStatusIcon = 2,
105 MiscStatusContent = 4,
106 MiscStatusThumbnail = 8,
107 MiscStatusDocPrint = 16
110 struct comclassredirect_data
112 ULONG size;
113 BYTE res;
114 BYTE miscmask;
115 BYTE res1[2];
116 DWORD model;
117 GUID clsid;
118 GUID alias;
119 GUID clsid2;
120 GUID tlbid;
121 ULONG name_len;
122 ULONG name_offset;
123 ULONG progid_len;
124 ULONG progid_offset;
125 ULONG clrdata_len;
126 ULONG clrdata_offset;
127 DWORD miscstatus;
128 DWORD miscstatuscontent;
129 DWORD miscstatusthumbnail;
130 DWORD miscstatusicon;
131 DWORD miscstatusdocprint;
134 struct ifacepsredirect_data
136 ULONG size;
137 DWORD mask;
138 GUID iid;
139 ULONG nummethods;
140 GUID tlbid;
141 GUID base;
142 ULONG name_len;
143 ULONG name_offset;
146 struct progidredirect_data
148 ULONG size;
149 DWORD reserved;
150 ULONG clsid_offset;
153 struct class_reg_data
155 union
157 struct
159 struct comclassredirect_data *data;
160 void *section;
161 HANDLE hactctx;
162 } actctx;
163 HKEY hkey;
164 } u;
165 BOOL hkey;
168 struct registered_psclsid
170 struct list entry;
171 IID iid;
172 CLSID clsid;
175 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list);
177 static CRITICAL_SECTION cs_registered_psclsid_list;
178 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
180 0, 0, &cs_registered_psclsid_list,
181 { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
182 0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
184 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
187 * This is a marshallable object exposing registered local servers.
188 * IServiceProvider is used only because it happens meet requirements
189 * and already has proxy/stub code. If more functionality is needed,
190 * a custom interface may be used instead.
192 struct LocalServer
194 IServiceProvider IServiceProvider_iface;
195 LONG ref;
196 APARTMENT *apt;
197 IStream *marshal_stream;
201 * This lock count counts the number of times CoInitialize is called. It is
202 * decreased every time CoUninitialize is called. When it hits 0, the COM
203 * libraries are freed
205 static LONG s_COMLockCount = 0;
206 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
207 static LONG s_COMServerProcessReferences = 0;
210 * This linked list contains the list of registered class objects. These
211 * are mostly used to register the factories for out-of-proc servers of OLE
212 * objects.
214 * TODO: Make this data structure aware of inter-process communication. This
215 * means that parts of this will be exported to rpcss.
217 typedef struct tagRegisteredClass
219 struct list entry;
220 CLSID classIdentifier;
221 OXID apartment_id;
222 LPUNKNOWN classObject;
223 DWORD runContext;
224 DWORD connectFlags;
225 DWORD dwCookie;
226 void *RpcRegistration;
227 } RegisteredClass;
229 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
231 static CRITICAL_SECTION csRegisteredClassList;
232 static CRITICAL_SECTION_DEBUG class_cs_debug =
234 0, 0, &csRegisteredClassList,
235 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
236 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
238 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
240 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
242 switch (aspect)
244 case DVASPECT_CONTENT:
245 return MiscStatusContent;
246 case DVASPECT_THUMBNAIL:
247 return MiscStatusThumbnail;
248 case DVASPECT_ICON:
249 return MiscStatusIcon;
250 case DVASPECT_DOCPRINT:
251 return MiscStatusDocPrint;
252 default:
253 return MiscStatus;
257 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
259 ACTCTX_SECTION_KEYED_DATA data;
261 data.cbSize = sizeof(data);
262 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
263 clsid, &data))
265 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
266 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
268 if (!(comclass->miscmask & misc))
270 if (!(comclass->miscmask & MiscStatus))
272 *status = 0;
273 return TRUE;
275 misc = MiscStatus;
278 switch (misc)
280 case MiscStatus:
281 *status = comclass->miscstatus;
282 break;
283 case MiscStatusIcon:
284 *status = comclass->miscstatusicon;
285 break;
286 case MiscStatusContent:
287 *status = comclass->miscstatuscontent;
288 break;
289 case MiscStatusThumbnail:
290 *status = comclass->miscstatusthumbnail;
291 break;
292 case MiscStatusDocPrint:
293 *status = comclass->miscstatusdocprint;
294 break;
295 default:
299 return TRUE;
301 else
302 return FALSE;
305 /* wrapper for NtCreateKey that creates the key recursively if necessary */
306 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
308 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
310 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
312 HANDLE subkey, root = attr->RootDirectory;
313 WCHAR *buffer = attr->ObjectName->Buffer;
314 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
315 UNICODE_STRING str;
317 while (i < len && buffer[i] != '\\') i++;
318 if (i == len) return status;
320 attrs = attr->Attributes;
321 attr->ObjectName = &str;
323 while (i < len)
325 str.Buffer = buffer + pos;
326 str.Length = (i - pos) * sizeof(WCHAR);
327 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
328 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
329 if (status) return status;
330 attr->RootDirectory = subkey;
331 while (i < len && buffer[i] == '\\') i++;
332 pos = i;
333 while (i < len && buffer[i] != '\\') i++;
335 str.Buffer = buffer + pos;
336 str.Length = (i - pos) * sizeof(WCHAR);
337 attr->Attributes = attrs;
338 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
339 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
341 return status;
344 static const WCHAR classes_rootW[] =
345 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
346 '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
348 static HKEY classes_root_hkey;
350 /* create the special HKEY_CLASSES_ROOT key */
351 static HKEY create_classes_root_hkey(DWORD access)
353 HKEY hkey, ret = 0;
354 OBJECT_ATTRIBUTES attr;
355 UNICODE_STRING name;
357 attr.Length = sizeof(attr);
358 attr.RootDirectory = 0;
359 attr.ObjectName = &name;
360 attr.Attributes = 0;
361 attr.SecurityDescriptor = NULL;
362 attr.SecurityQualityOfService = NULL;
363 RtlInitUnicodeString( &name, classes_rootW );
364 if (create_key( &hkey, access, &attr )) return 0;
365 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
367 if (!(access & KEY_WOW64_64KEY))
369 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
370 ret = hkey;
371 else
372 NtClose( hkey ); /* somebody beat us to it */
374 else
375 ret = hkey;
376 return ret;
379 /* map the hkey from special root to normal key if necessary */
380 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
382 HKEY ret = hkey;
383 const BOOL is_win64 = sizeof(void*) > sizeof(int);
384 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
386 if (hkey == HKEY_CLASSES_ROOT &&
387 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
388 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
389 if (force_wow32 && ret && ret == classes_root_hkey)
391 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
392 access &= ~KEY_WOW64_32KEY;
393 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
394 return 0;
395 ret = hkey;
398 return ret;
401 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
403 OBJECT_ATTRIBUTES attr;
404 UNICODE_STRING nameW;
406 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
408 attr.Length = sizeof(attr);
409 attr.RootDirectory = hkey;
410 attr.ObjectName = &nameW;
411 attr.Attributes = 0;
412 attr.SecurityDescriptor = NULL;
413 attr.SecurityQualityOfService = NULL;
414 RtlInitUnicodeString( &nameW, name );
416 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
419 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
421 OBJECT_ATTRIBUTES attr;
422 UNICODE_STRING nameW;
424 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
426 attr.Length = sizeof(attr);
427 attr.RootDirectory = hkey;
428 attr.ObjectName = &nameW;
429 attr.Attributes = 0;
430 attr.SecurityDescriptor = NULL;
431 attr.SecurityQualityOfService = NULL;
432 RtlInitUnicodeString( &nameW, name );
434 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
437 /*****************************************************************************
438 * This section contains OpenDllList definitions
440 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
441 * other functions that do LoadLibrary _without_ giving back a HMODULE.
442 * Without this list these handles would never be freed.
444 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
445 * next unload-call but not before 600 sec.
448 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
449 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
451 typedef struct tagOpenDll
453 LONG refs;
454 LPWSTR library_name;
455 HANDLE library;
456 DllGetClassObjectFunc DllGetClassObject;
457 DllCanUnloadNowFunc DllCanUnloadNow;
458 struct list entry;
459 } OpenDll;
461 static struct list openDllList = LIST_INIT(openDllList);
463 static CRITICAL_SECTION csOpenDllList;
464 static CRITICAL_SECTION_DEBUG dll_cs_debug =
466 0, 0, &csOpenDllList,
467 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
468 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
470 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
472 struct apartment_loaded_dll
474 struct list entry;
475 OpenDll *dll;
476 DWORD unload_time;
477 BOOL multi_threaded;
480 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};
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 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
722 list_remove(&curClass->entry);
724 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
725 RPC_StopLocalServer(curClass->RpcRegistration);
727 IUnknown_Release(curClass->classObject);
728 HeapFree(GetProcessHeap(), 0, curClass);
731 static void COM_RevokeAllClasses(const struct apartment *apt)
733 RegisteredClass *curClass, *cursor;
735 EnterCriticalSection( &csRegisteredClassList );
737 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
739 if (curClass->apartment_id == apt->oxid)
740 COM_RevokeRegisteredClassObject(curClass);
743 LeaveCriticalSection( &csRegisteredClassList );
746 static void revoke_registered_psclsids(void)
748 struct registered_psclsid *psclsid, *psclsid2;
750 EnterCriticalSection( &cs_registered_psclsid_list );
752 LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, &registered_psclsid_list, struct registered_psclsid, entry)
754 list_remove(&psclsid->entry);
755 HeapFree(GetProcessHeap(), 0, psclsid);
758 LeaveCriticalSection( &cs_registered_psclsid_list );
761 /******************************************************************************
762 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
765 typedef struct ManualResetEvent {
766 ISynchronize ISynchronize_iface;
767 ISynchronizeHandle ISynchronizeHandle_iface;
768 LONG ref;
769 HANDLE event;
770 } MREImpl;
772 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
774 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
777 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
779 MREImpl *This = impl_from_ISynchronize(iface);
781 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
783 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
784 *ppv = &This->ISynchronize_iface;
785 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
786 *ppv = &This->ISynchronizeHandle_iface;
787 }else {
788 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
789 *ppv = NULL;
790 return E_NOINTERFACE;
793 IUnknown_AddRef((IUnknown*)*ppv);
794 return S_OK;
797 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
799 MREImpl *This = impl_from_ISynchronize(iface);
800 LONG ref = InterlockedIncrement(&This->ref);
801 TRACE("%p - ref %d\n", This, ref);
803 return ref;
806 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
808 MREImpl *This = impl_from_ISynchronize(iface);
809 LONG ref = InterlockedDecrement(&This->ref);
810 TRACE("%p - ref %d\n", This, ref);
812 if(!ref)
814 CloseHandle(This->event);
815 HeapFree(GetProcessHeap(), 0, This);
818 return ref;
821 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
823 MREImpl *This = impl_from_ISynchronize(iface);
824 UINT index;
825 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
826 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
829 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
831 MREImpl *This = impl_from_ISynchronize(iface);
832 TRACE("%p\n", This);
833 SetEvent(This->event);
834 return S_OK;
837 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
839 MREImpl *This = impl_from_ISynchronize(iface);
840 TRACE("%p\n", This);
841 ResetEvent(This->event);
842 return S_OK;
845 static ISynchronizeVtbl vt_ISynchronize = {
846 ISynchronize_fnQueryInterface,
847 ISynchronize_fnAddRef,
848 ISynchronize_fnRelease,
849 ISynchronize_fnWait,
850 ISynchronize_fnSignal,
851 ISynchronize_fnReset
854 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
856 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
859 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
861 MREImpl *This = impl_from_ISynchronizeHandle(iface);
862 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
865 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
867 MREImpl *This = impl_from_ISynchronizeHandle(iface);
868 return ISynchronize_AddRef(&This->ISynchronize_iface);
871 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
873 MREImpl *This = impl_from_ISynchronizeHandle(iface);
874 return ISynchronize_Release(&This->ISynchronize_iface);
877 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
879 MREImpl *This = impl_from_ISynchronizeHandle(iface);
881 *ph = This->event;
882 return S_OK;
885 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
886 SynchronizeHandle_QueryInterface,
887 SynchronizeHandle_AddRef,
888 SynchronizeHandle_Release,
889 SynchronizeHandle_GetHandle
892 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
894 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
895 HRESULT hr;
897 if(punkouter)
898 FIXME("Aggregation not implemented.\n");
900 This->ref = 1;
901 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
902 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
903 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
905 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
906 ISynchronize_Release(&This->ISynchronize_iface);
907 return hr;
910 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
912 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
915 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
917 LocalServer *This = impl_from_IServiceProvider(iface);
919 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
921 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
922 *ppv = &This->IServiceProvider_iface;
923 }else {
924 *ppv = NULL;
925 return E_NOINTERFACE;
928 IUnknown_AddRef((IUnknown*)*ppv);
929 return S_OK;
932 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
934 LocalServer *This = impl_from_IServiceProvider(iface);
935 LONG ref = InterlockedIncrement(&This->ref);
937 TRACE("(%p) ref=%d\n", This, ref);
939 return ref;
942 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
944 LocalServer *This = impl_from_IServiceProvider(iface);
945 LONG ref = InterlockedDecrement(&This->ref);
947 TRACE("(%p) ref=%d\n", This, ref);
949 if(!ref) {
950 assert(!This->apt);
951 HeapFree(GetProcessHeap(), 0, This);
954 return ref;
957 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
959 LocalServer *This = impl_from_IServiceProvider(iface);
960 APARTMENT *apt = COM_CurrentApt();
961 RegisteredClass *iter;
962 HRESULT hres = E_FAIL;
964 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
966 if(!This->apt)
967 return E_UNEXPECTED;
969 EnterCriticalSection(&csRegisteredClassList);
971 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
972 if(iter->apartment_id == apt->oxid
973 && (iter->runContext & CLSCTX_LOCAL_SERVER)
974 && IsEqualGUID(&iter->classIdentifier, guid)) {
975 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
976 break;
980 LeaveCriticalSection( &csRegisteredClassList );
982 return hres;
985 static const IServiceProviderVtbl LocalServerVtbl = {
986 LocalServer_QueryInterface,
987 LocalServer_AddRef,
988 LocalServer_Release,
989 LocalServer_QueryService
992 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
994 HRESULT hres = S_OK;
996 EnterCriticalSection(&apt->cs);
998 if(!apt->local_server) {
999 LocalServer *obj;
1001 obj = heap_alloc(sizeof(*obj));
1002 if(obj) {
1003 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
1004 obj->ref = 1;
1005 obj->apt = apt;
1007 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
1008 if(SUCCEEDED(hres)) {
1009 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
1010 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1011 if(FAILED(hres))
1012 IStream_Release(obj->marshal_stream);
1015 if(SUCCEEDED(hres))
1016 apt->local_server = obj;
1017 else
1018 heap_free(obj);
1019 }else {
1020 hres = E_OUTOFMEMORY;
1024 if(SUCCEEDED(hres))
1025 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1027 LeaveCriticalSection(&apt->cs);
1029 if(FAILED(hres))
1030 ERR("Failed: %08x\n", hres);
1031 return hres;
1034 /***********************************************************************
1035 * CoRevokeClassObject [OLE32.@]
1037 * Removes a class object from the class registry.
1039 * PARAMS
1040 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1042 * RETURNS
1043 * Success: S_OK.
1044 * Failure: HRESULT code.
1046 * NOTES
1047 * Must be called from the same apartment that called CoRegisterClassObject(),
1048 * otherwise it will fail with RPC_E_WRONG_THREAD.
1050 * SEE ALSO
1051 * CoRegisterClassObject
1053 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
1054 DWORD dwRegister)
1056 HRESULT hr = E_INVALIDARG;
1057 RegisteredClass *curClass;
1058 APARTMENT *apt;
1060 TRACE("(%08x)\n",dwRegister);
1062 apt = COM_CurrentApt();
1063 if (!apt)
1065 ERR("COM was not initialized\n");
1066 return CO_E_NOTINITIALIZED;
1069 EnterCriticalSection( &csRegisteredClassList );
1071 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1074 * Check if we have a match on the cookie.
1076 if (curClass->dwCookie == dwRegister)
1078 if (curClass->apartment_id == apt->oxid)
1080 COM_RevokeRegisteredClassObject(curClass);
1081 hr = S_OK;
1083 else
1085 ERR("called from wrong apartment, should be called from %s\n",
1086 wine_dbgstr_longlong(curClass->apartment_id));
1087 hr = RPC_E_WRONG_THREAD;
1089 break;
1093 LeaveCriticalSection( &csRegisteredClassList );
1095 return hr;
1098 /* frees unused libraries loaded by apartment_getclassobject by calling the
1099 * DLL's DllCanUnloadNow entry point */
1100 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1102 struct apartment_loaded_dll *entry, *next;
1103 EnterCriticalSection(&apt->cs);
1104 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1106 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1108 DWORD real_delay = delay;
1110 if (real_delay == INFINITE)
1112 /* DLLs that return multi-threaded objects aren't unloaded
1113 * straight away to cope for programs that have races between
1114 * last object destruction and threads in the DLLs that haven't
1115 * finished, despite DllCanUnloadNow returning S_OK */
1116 if (entry->multi_threaded)
1117 real_delay = 10 * 60 * 1000; /* 10 minutes */
1118 else
1119 real_delay = 0;
1122 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1124 list_remove(&entry->entry);
1125 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1126 HeapFree(GetProcessHeap(), 0, entry);
1128 else
1130 entry->unload_time = GetTickCount() + real_delay;
1131 if (!entry->unload_time) entry->unload_time = 1;
1134 else if (entry->unload_time)
1135 entry->unload_time = 0;
1137 LeaveCriticalSection(&apt->cs);
1140 DWORD apartment_release(struct apartment *apt)
1142 DWORD ret;
1144 EnterCriticalSection(&csApartment);
1146 ret = InterlockedDecrement(&apt->refs);
1147 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1148 /* destruction stuff that needs to happen under csApartment CS */
1149 if (ret == 0)
1151 if (apt == MTA) MTA = NULL;
1152 else if (apt == MainApartment) MainApartment = NULL;
1153 list_remove(&apt->entry);
1156 LeaveCriticalSection(&csApartment);
1158 if (ret == 0)
1160 struct list *cursor, *cursor2;
1162 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1164 if(apt->local_server) {
1165 LocalServer *local_server = apt->local_server;
1166 LARGE_INTEGER zero;
1168 memset(&zero, 0, sizeof(zero));
1169 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1170 CoReleaseMarshalData(local_server->marshal_stream);
1171 IStream_Release(local_server->marshal_stream);
1172 local_server->marshal_stream = NULL;
1174 apt->local_server = NULL;
1175 local_server->apt = NULL;
1176 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1179 /* Release the references to the registered class objects */
1180 COM_RevokeAllClasses(apt);
1182 /* no locking is needed for this apartment, because no other thread
1183 * can access it at this point */
1185 apartment_disconnectproxies(apt);
1187 if (apt->win) DestroyWindow(apt->win);
1188 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1190 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1192 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1193 /* release the implicit reference given by the fact that the
1194 * stub has external references (it must do since it is in the
1195 * stub manager list in the apartment and all non-apartment users
1196 * must have a ref on the apartment and so it cannot be destroyed).
1198 stub_manager_int_release(stubmgr);
1201 /* if this assert fires, then another thread took a reference to a
1202 * stub manager without taking a reference to the containing
1203 * apartment, which it must do. */
1204 assert(list_empty(&apt->stubmgrs));
1206 if (apt->filter) IMessageFilter_Release(apt->filter);
1208 /* free as many unused libraries as possible... */
1209 apartment_freeunusedlibraries(apt, 0);
1211 /* ... and free the memory for the apartment loaded dll entry and
1212 * release the dll list reference without freeing the library for the
1213 * rest */
1214 while ((cursor = list_head(&apt->loaded_dlls)))
1216 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1217 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1218 list_remove(cursor);
1219 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1222 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1223 DeleteCriticalSection(&apt->cs);
1225 HeapFree(GetProcessHeap(), 0, apt);
1228 return ret;
1231 /* The given OXID must be local to this process:
1233 * The ref parameter is here mostly to ensure people remember that
1234 * they get one, you should normally take a ref for thread safety.
1236 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1238 APARTMENT *result = NULL;
1239 struct list *cursor;
1241 EnterCriticalSection(&csApartment);
1242 LIST_FOR_EACH( cursor, &apts )
1244 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1245 if (apt->oxid == oxid)
1247 result = apt;
1248 if (ref) apartment_addref(result);
1249 break;
1252 LeaveCriticalSection(&csApartment);
1254 return result;
1257 /* gets the apartment which has a given creator thread ID. The caller must
1258 * release the reference from the apartment as soon as the apartment pointer
1259 * is no longer required. */
1260 APARTMENT *apartment_findfromtid(DWORD tid)
1262 APARTMENT *result = NULL;
1263 struct list *cursor;
1265 EnterCriticalSection(&csApartment);
1266 LIST_FOR_EACH( cursor, &apts )
1268 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1269 if (apt->tid == tid)
1271 result = apt;
1272 apartment_addref(result);
1273 break;
1276 LeaveCriticalSection(&csApartment);
1278 return result;
1281 /* gets the main apartment if it exists. The caller must
1282 * release the reference from the apartment as soon as the apartment pointer
1283 * is no longer required. */
1284 static APARTMENT *apartment_findmain(void)
1286 APARTMENT *result;
1288 EnterCriticalSection(&csApartment);
1290 result = MainApartment;
1291 if (result) apartment_addref(result);
1293 LeaveCriticalSection(&csApartment);
1295 return result;
1298 /* gets the multi-threaded apartment if it exists. The caller must
1299 * release the reference from the apartment as soon as the apartment pointer
1300 * is no longer required. */
1301 static APARTMENT *apartment_find_multi_threaded(void)
1303 APARTMENT *result = NULL;
1304 struct list *cursor;
1306 EnterCriticalSection(&csApartment);
1308 LIST_FOR_EACH( cursor, &apts )
1310 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1311 if (apt->multi_threaded)
1313 result = apt;
1314 apartment_addref(result);
1315 break;
1319 LeaveCriticalSection(&csApartment);
1320 return result;
1323 /* gets the specified class object by loading the appropriate DLL, if
1324 * necessary and calls the DllGetClassObject function for the DLL */
1325 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1326 BOOL apartment_threaded,
1327 REFCLSID rclsid, REFIID riid, void **ppv)
1329 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1330 HRESULT hr = S_OK;
1331 BOOL found = FALSE;
1332 struct apartment_loaded_dll *apartment_loaded_dll;
1334 if (!strcmpiW(dllpath, wszOle32))
1336 /* we don't need to control the lifetime of this dll, so use the local
1337 * implementation of DllGetClassObject directly */
1338 TRACE("calling ole32!DllGetClassObject\n");
1339 hr = DllGetClassObject(rclsid, riid, ppv);
1341 if (hr != S_OK)
1342 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1344 return hr;
1347 EnterCriticalSection(&apt->cs);
1349 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1350 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1352 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1353 found = TRUE;
1354 break;
1357 if (!found)
1359 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1360 if (!apartment_loaded_dll)
1361 hr = E_OUTOFMEMORY;
1362 if (SUCCEEDED(hr))
1364 apartment_loaded_dll->unload_time = 0;
1365 apartment_loaded_dll->multi_threaded = FALSE;
1366 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1367 if (FAILED(hr))
1368 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1370 if (SUCCEEDED(hr))
1372 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1373 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1377 LeaveCriticalSection(&apt->cs);
1379 if (SUCCEEDED(hr))
1381 /* one component being multi-threaded overrides any number of
1382 * apartment-threaded components */
1383 if (!apartment_threaded)
1384 apartment_loaded_dll->multi_threaded = TRUE;
1386 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1387 /* OK: get the ClassObject */
1388 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1390 if (hr != S_OK)
1391 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1394 return hr;
1397 /***********************************************************************
1398 * COM_RegReadPath [internal]
1400 * Reads a registry value and expands it when necessary
1402 static DWORD COM_RegReadPath(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1404 DWORD ret;
1406 if (regdata->hkey)
1408 DWORD keytype;
1409 WCHAR src[MAX_PATH];
1410 DWORD dwLength = dstlen * sizeof(WCHAR);
1412 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1413 if (keytype == REG_EXPAND_SZ) {
1414 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1415 } else {
1416 const WCHAR *quote_start;
1417 quote_start = strchrW(src, '\"');
1418 if (quote_start) {
1419 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1420 if (quote_end) {
1421 memmove(src, quote_start + 1,
1422 (quote_end - quote_start - 1) * sizeof(WCHAR));
1423 src[quote_end - quote_start - 1] = '\0';
1426 lstrcpynW(dst, src, dstlen);
1429 return ret;
1431 else
1433 ULONG_PTR cookie;
1434 WCHAR *nameW;
1436 *dst = 0;
1437 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1438 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1439 ret = SearchPathW(NULL, nameW, NULL, dstlen, dst, NULL);
1440 DeactivateActCtx(0, cookie);
1441 return !*dst;
1445 struct host_object_params
1447 struct class_reg_data regdata;
1448 CLSID clsid; /* clsid of object to marshal */
1449 IID iid; /* interface to marshal */
1450 HANDLE event; /* event signalling when ready for multi-threaded case */
1451 HRESULT hr; /* result for multi-threaded case */
1452 IStream *stream; /* stream that the object will be marshaled into */
1453 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1456 static HRESULT apartment_hostobject(struct apartment *apt,
1457 const struct host_object_params *params)
1459 IUnknown *object;
1460 HRESULT hr;
1461 static const LARGE_INTEGER llZero;
1462 WCHAR dllpath[MAX_PATH+1];
1464 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1466 if (COM_RegReadPath(&params->regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1468 /* failure: CLSID is not found in registry */
1469 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1470 return REGDB_E_CLASSNOTREG;
1473 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1474 &params->clsid, &params->iid, (void **)&object);
1475 if (FAILED(hr))
1476 return hr;
1478 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1479 if (FAILED(hr))
1480 IUnknown_Release(object);
1481 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1483 return hr;
1486 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1488 switch (msg)
1490 case DM_EXECUTERPC:
1491 RPC_ExecuteCall((struct dispatch_params *)lParam);
1492 return 0;
1493 case DM_HOSTOBJECT:
1494 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1495 default:
1496 return DefWindowProcW(hWnd, msg, wParam, lParam);
1500 struct host_thread_params
1502 COINIT threading_model;
1503 HANDLE ready_event;
1504 HWND apartment_hwnd;
1507 /* thread for hosting an object to allow an object to appear to be created in
1508 * an apartment with an incompatible threading model */
1509 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1511 struct host_thread_params *params = p;
1512 MSG msg;
1513 HRESULT hr;
1514 struct apartment *apt;
1516 TRACE("\n");
1518 hr = CoInitializeEx(NULL, params->threading_model);
1519 if (FAILED(hr)) return hr;
1521 apt = COM_CurrentApt();
1522 if (params->threading_model == COINIT_APARTMENTTHREADED)
1524 apartment_createwindowifneeded(apt);
1525 params->apartment_hwnd = apartment_getwindow(apt);
1527 else
1528 params->apartment_hwnd = NULL;
1530 /* force the message queue to be created before signaling parent thread */
1531 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1533 SetEvent(params->ready_event);
1534 params = NULL; /* can't touch params after here as it may be invalid */
1536 while (GetMessageW(&msg, NULL, 0, 0))
1538 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1540 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1541 obj_params->hr = apartment_hostobject(apt, obj_params);
1542 SetEvent(obj_params->event);
1544 else
1546 TranslateMessage(&msg);
1547 DispatchMessageW(&msg);
1551 TRACE("exiting\n");
1553 CoUninitialize();
1555 return S_OK;
1558 /* finds or creates a host apartment, creates the object inside it and returns
1559 * a proxy to it so that the object can be used in the apartment of the
1560 * caller of this function */
1561 static HRESULT apartment_hostobject_in_hostapt(
1562 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1563 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1565 struct host_object_params params;
1566 HWND apartment_hwnd = NULL;
1567 DWORD apartment_tid = 0;
1568 HRESULT hr;
1570 if (!multi_threaded && main_apartment)
1572 APARTMENT *host_apt = apartment_findmain();
1573 if (host_apt)
1575 apartment_hwnd = apartment_getwindow(host_apt);
1576 apartment_release(host_apt);
1580 if (!apartment_hwnd)
1582 EnterCriticalSection(&apt->cs);
1584 if (!apt->host_apt_tid)
1586 struct host_thread_params thread_params;
1587 HANDLE handles[2];
1588 DWORD wait_value;
1590 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1591 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1592 thread_params.apartment_hwnd = NULL;
1593 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1594 if (!handles[1])
1596 CloseHandle(handles[0]);
1597 LeaveCriticalSection(&apt->cs);
1598 return E_OUTOFMEMORY;
1600 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1601 CloseHandle(handles[0]);
1602 CloseHandle(handles[1]);
1603 if (wait_value == WAIT_OBJECT_0)
1604 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1605 else
1607 LeaveCriticalSection(&apt->cs);
1608 return E_OUTOFMEMORY;
1612 if (multi_threaded || !main_apartment)
1614 apartment_hwnd = apt->host_apt_hwnd;
1615 apartment_tid = apt->host_apt_tid;
1618 LeaveCriticalSection(&apt->cs);
1621 /* another thread may have become the main apartment in the time it took
1622 * us to create the thread for the host apartment */
1623 if (!apartment_hwnd && !multi_threaded && main_apartment)
1625 APARTMENT *host_apt = apartment_findmain();
1626 if (host_apt)
1628 apartment_hwnd = apartment_getwindow(host_apt);
1629 apartment_release(host_apt);
1633 params.regdata = *regdata;
1634 params.clsid = *rclsid;
1635 params.iid = *riid;
1636 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1637 if (FAILED(hr))
1638 return hr;
1639 params.apartment_threaded = !multi_threaded;
1640 if (multi_threaded)
1642 params.hr = S_OK;
1643 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1644 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1645 hr = E_OUTOFMEMORY;
1646 else
1648 WaitForSingleObject(params.event, INFINITE);
1649 hr = params.hr;
1651 CloseHandle(params.event);
1653 else
1655 if (!apartment_hwnd)
1657 ERR("host apartment didn't create window\n");
1658 hr = E_OUTOFMEMORY;
1660 else
1661 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1663 if (SUCCEEDED(hr))
1664 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1665 IStream_Release(params.stream);
1666 return hr;
1669 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1671 WNDCLASSW wclass;
1673 /* Dispatching to the correct thread in an apartment is done through
1674 * window messages rather than RPC transports. When an interface is
1675 * marshalled into another apartment in the same process, a window of the
1676 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1677 * application) is responsible for pumping the message loop in that thread.
1678 * The WM_USER messages which point to the RPCs are then dispatched to
1679 * apartment_wndproc by the user's code from the apartment in which the
1680 * interface was unmarshalled.
1682 memset(&wclass, 0, sizeof(wclass));
1683 wclass.lpfnWndProc = apartment_wndproc;
1684 wclass.hInstance = hProxyDll;
1685 wclass.lpszClassName = wszAptWinClass;
1686 RegisterClassW(&wclass);
1687 return TRUE;
1690 /* create a window for the apartment or return the current one if one has
1691 * already been created */
1692 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1694 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1696 if (apt->multi_threaded)
1697 return S_OK;
1699 if (!apt->win)
1701 HWND hwnd;
1703 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1705 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1706 HWND_MESSAGE, 0, hProxyDll, NULL);
1707 if (!hwnd)
1709 ERR("CreateWindow failed with error %d\n", GetLastError());
1710 return HRESULT_FROM_WIN32(GetLastError());
1712 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1713 /* someone beat us to it */
1714 DestroyWindow(hwnd);
1717 return S_OK;
1720 /* retrieves the window for the main- or apartment-threaded apartment */
1721 HWND apartment_getwindow(const struct apartment *apt)
1723 assert(!apt->multi_threaded);
1724 return apt->win;
1727 static void COM_TlsDestroy(void)
1729 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1730 if (info)
1732 if (info->apt) apartment_release(info->apt);
1733 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1734 if (info->state) IUnknown_Release(info->state);
1735 if (info->spy) IInitializeSpy_Release(info->spy);
1736 if (info->context_token) IObjContext_Release(info->context_token);
1737 HeapFree(GetProcessHeap(), 0, info);
1738 NtCurrentTeb()->ReservedForOle = NULL;
1742 /******************************************************************************
1743 * CoBuildVersion [OLE32.@]
1745 * Gets the build version of the DLL.
1747 * PARAMS
1749 * RETURNS
1750 * Current build version, hiword is majornumber, loword is minornumber
1752 DWORD WINAPI CoBuildVersion(void)
1754 TRACE("Returning version %d, build %d.\n", rmm, rup);
1755 return (rmm<<16)+rup;
1758 /******************************************************************************
1759 * CoRegisterInitializeSpy [OLE32.@]
1761 * Add a Spy that watches CoInitializeEx calls
1763 * PARAMS
1764 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1765 * cookie [II] cookie receiver
1767 * RETURNS
1768 * Success: S_OK if not already initialized, S_FALSE otherwise.
1769 * Failure: HRESULT code.
1771 * SEE ALSO
1772 * CoInitializeEx
1774 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1776 struct oletls *info = COM_CurrentInfo();
1777 HRESULT hr;
1779 TRACE("(%p, %p)\n", spy, cookie);
1781 if (!spy || !cookie || !info)
1783 if (!info)
1784 WARN("Could not allocate tls\n");
1785 return E_INVALIDARG;
1788 if (info->spy)
1790 FIXME("Already registered?\n");
1791 return E_UNEXPECTED;
1794 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1795 if (SUCCEEDED(hr))
1797 cookie->QuadPart = (DWORD_PTR)spy;
1798 return S_OK;
1800 return hr;
1803 /******************************************************************************
1804 * CoRevokeInitializeSpy [OLE32.@]
1806 * Remove a spy that previously watched CoInitializeEx calls
1808 * PARAMS
1809 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1811 * RETURNS
1812 * Success: S_OK if a spy is removed
1813 * Failure: E_INVALIDARG
1815 * SEE ALSO
1816 * CoInitializeEx
1818 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1820 struct oletls *info = COM_CurrentInfo();
1821 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1823 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1824 return E_INVALIDARG;
1826 IInitializeSpy_Release(info->spy);
1827 info->spy = NULL;
1828 return S_OK;
1831 HRESULT enter_apartment( struct oletls *info, DWORD model )
1833 HRESULT hr = S_OK;
1835 if (!info->apt)
1837 if (!apartment_get_or_create( model ))
1838 return E_OUTOFMEMORY;
1840 else if (!apartment_is_model( info->apt, model ))
1842 WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1843 info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1844 model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1845 return RPC_E_CHANGED_MODE;
1847 else
1848 hr = S_FALSE;
1850 info->inits++;
1852 return hr;
1855 void leave_apartment( struct oletls *info )
1857 if (!--info->inits)
1859 if (info->ole_inits)
1860 WARN( "Uninitializing apartment while Ole is still initialized\n" );
1861 apartment_release( info->apt );
1862 info->apt = NULL;
1866 /******************************************************************************
1867 * CoInitialize [OLE32.@]
1869 * Initializes the COM libraries by calling CoInitializeEx with
1870 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1872 * PARAMS
1873 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1875 * RETURNS
1876 * Success: S_OK if not already initialized, S_FALSE otherwise.
1877 * Failure: HRESULT code.
1879 * SEE ALSO
1880 * CoInitializeEx
1882 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1885 * Just delegate to the newer method.
1887 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1890 /******************************************************************************
1891 * CoInitializeEx [OLE32.@]
1893 * Initializes the COM libraries.
1895 * PARAMS
1896 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1897 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1899 * RETURNS
1900 * S_OK if successful,
1901 * S_FALSE if this function was called already.
1902 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1903 * threading model.
1905 * NOTES
1907 * The behavior used to set the IMalloc used for memory management is
1908 * obsolete.
1909 * The dwCoInit parameter must specify one of the following apartment
1910 * threading models:
1911 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1912 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1913 * The parameter may also specify zero or more of the following flags:
1914 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1915 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1917 * SEE ALSO
1918 * CoUninitialize
1920 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1922 struct oletls *info = COM_CurrentInfo();
1923 HRESULT hr;
1925 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1927 if (lpReserved!=NULL)
1929 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1933 * Check the lock count. If this is the first time going through the initialize
1934 * process, we have to initialize the libraries.
1936 * And crank-up that lock count.
1938 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1941 * Initialize the various COM libraries and data structures.
1943 TRACE("() - Initializing the COM libraries\n");
1945 /* we may need to defer this until after apartment initialisation */
1946 RunningObjectTableImpl_Initialize();
1949 if (info->spy)
1950 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1952 hr = enter_apartment( info, dwCoInit );
1954 if (info->spy)
1955 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1957 return hr;
1960 /***********************************************************************
1961 * CoUninitialize [OLE32.@]
1963 * This method will decrement the refcount on the current apartment, freeing
1964 * the resources associated with it if it is the last thread in the apartment.
1965 * If the last apartment is freed, the function will additionally release
1966 * any COM resources associated with the process.
1968 * PARAMS
1970 * RETURNS
1971 * Nothing.
1973 * SEE ALSO
1974 * CoInitializeEx
1976 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
1978 struct oletls * info = COM_CurrentInfo();
1979 LONG lCOMRefCnt;
1981 TRACE("()\n");
1983 /* will only happen on OOM */
1984 if (!info) return;
1986 if (info->spy)
1987 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1989 /* sanity check */
1990 if (!info->inits)
1992 ERR("Mismatched CoUninitialize\n");
1994 if (info->spy)
1995 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1996 return;
1999 leave_apartment( info );
2002 * Decrease the reference count.
2003 * If we are back to 0 locks on the COM library, make sure we free
2004 * all the associated data structures.
2006 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2007 if (lCOMRefCnt==1)
2009 TRACE("() - Releasing the COM libraries\n");
2011 revoke_registered_psclsids();
2012 RunningObjectTableImpl_UnInitialize();
2014 else if (lCOMRefCnt<1) {
2015 ERR( "CoUninitialize() - not CoInitialized.\n" );
2016 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2018 if (info->spy)
2019 IInitializeSpy_PostUninitialize(info->spy, info->inits);
2022 /******************************************************************************
2023 * CoDisconnectObject [OLE32.@]
2025 * Disconnects all connections to this object from remote processes. Dispatches
2026 * pending RPCs while blocking new RPCs from occurring, and then calls
2027 * IMarshal::DisconnectObject on the given object.
2029 * Typically called when the object server is forced to shut down, for instance by
2030 * the user.
2032 * PARAMS
2033 * lpUnk [I] The object whose stub should be disconnected.
2034 * reserved [I] Reserved. Should be set to 0.
2036 * RETURNS
2037 * Success: S_OK.
2038 * Failure: HRESULT code.
2040 * SEE ALSO
2041 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2043 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2045 struct stub_manager *manager;
2046 HRESULT hr;
2047 IMarshal *marshal;
2048 APARTMENT *apt;
2050 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2052 if (!lpUnk) return E_INVALIDARG;
2054 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2055 if (hr == S_OK)
2057 hr = IMarshal_DisconnectObject(marshal, reserved);
2058 IMarshal_Release(marshal);
2059 return hr;
2062 apt = COM_CurrentApt();
2063 if (!apt)
2064 return CO_E_NOTINITIALIZED;
2066 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2067 if (manager) {
2068 stub_manager_disconnect(manager);
2069 /* Release stub manager twice, to remove the apartment reference. */
2070 stub_manager_int_release(manager);
2071 stub_manager_int_release(manager);
2074 /* Note: native is pretty broken here because it just silently
2075 * fails, without returning an appropriate error code if the object was
2076 * not found, making apps think that the object was disconnected, when
2077 * it actually wasn't */
2079 return S_OK;
2082 /******************************************************************************
2083 * CoCreateGuid [OLE32.@]
2085 * Simply forwards to UuidCreate in RPCRT4.
2087 * PARAMS
2088 * pguid [O] Points to the GUID to initialize.
2090 * RETURNS
2091 * Success: S_OK.
2092 * Failure: HRESULT code.
2094 * SEE ALSO
2095 * UuidCreate
2097 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2099 DWORD status;
2101 if(!pguid) return E_INVALIDARG;
2103 status = UuidCreate(pguid);
2104 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2105 return HRESULT_FROM_WIN32( status );
2108 static inline BOOL is_valid_hex(WCHAR c)
2110 if (!(((c >= '0') && (c <= '9')) ||
2111 ((c >= 'a') && (c <= 'f')) ||
2112 ((c >= 'A') && (c <= 'F'))))
2113 return FALSE;
2114 return TRUE;
2117 static const BYTE guid_conv_table[256] =
2119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2122 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2123 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2124 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2125 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2128 /* conversion helper for CLSIDFromString/IIDFromString */
2129 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2131 int i;
2133 if (!s || s[0]!='{') {
2134 memset( id, 0, sizeof (CLSID) );
2135 if(!s) return TRUE;
2136 return FALSE;
2139 TRACE("%s -> %p\n", debugstr_w(s), id);
2141 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2143 id->Data1 = 0;
2144 for (i = 1; i < 9; i++) {
2145 if (!is_valid_hex(s[i])) return FALSE;
2146 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2148 if (s[9]!='-') return FALSE;
2150 id->Data2 = 0;
2151 for (i = 10; i < 14; i++) {
2152 if (!is_valid_hex(s[i])) return FALSE;
2153 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2155 if (s[14]!='-') return FALSE;
2157 id->Data3 = 0;
2158 for (i = 15; i < 19; i++) {
2159 if (!is_valid_hex(s[i])) return FALSE;
2160 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2162 if (s[19]!='-') return FALSE;
2164 for (i = 20; i < 37; i+=2) {
2165 if (i == 24) {
2166 if (s[i]!='-') return FALSE;
2167 i++;
2169 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2170 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2173 if (s[37] == '}' && s[38] == '\0')
2174 return TRUE;
2176 return FALSE;
2179 /*****************************************************************************/
2181 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2183 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2184 WCHAR buf2[CHARS_IN_GUID];
2185 LONG buf2len = sizeof(buf2);
2186 HKEY xhkey;
2187 WCHAR *buf;
2189 memset(clsid, 0, sizeof(*clsid));
2190 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2191 if (!buf) return E_OUTOFMEMORY;
2192 strcpyW( buf, progid );
2193 strcatW( buf, clsidW );
2194 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2196 HeapFree(GetProcessHeap(),0,buf);
2197 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2198 return CO_E_CLASSSTRING;
2200 HeapFree(GetProcessHeap(),0,buf);
2202 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2204 RegCloseKey(xhkey);
2205 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2206 return CO_E_CLASSSTRING;
2208 RegCloseKey(xhkey);
2209 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2212 /******************************************************************************
2213 * CLSIDFromString [OLE32.@]
2215 * Converts a unique identifier from its string representation into
2216 * the GUID struct.
2218 * PARAMS
2219 * idstr [I] The string representation of the GUID.
2220 * id [O] GUID converted from the string.
2222 * RETURNS
2223 * S_OK on success
2224 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2226 * SEE ALSO
2227 * StringFromCLSID
2229 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2231 HRESULT ret = CO_E_CLASSSTRING;
2232 CLSID tmp_id;
2234 if (!id)
2235 return E_INVALIDARG;
2237 if (guid_from_string(idstr, id))
2238 return S_OK;
2240 /* It appears a ProgID is also valid */
2241 ret = clsid_from_string_reg(idstr, &tmp_id);
2242 if(SUCCEEDED(ret))
2243 *id = tmp_id;
2245 return ret;
2248 /******************************************************************************
2249 * IIDFromString [OLE32.@]
2251 * Converts an interface identifier from its string representation to
2252 * the IID struct.
2254 * PARAMS
2255 * idstr [I] The string representation of the GUID.
2256 * id [O] IID converted from the string.
2258 * RETURNS
2259 * S_OK on success
2260 * CO_E_IIDSTRING if idstr is not a valid IID
2262 * SEE ALSO
2263 * StringFromIID
2265 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2267 TRACE("%s -> %p\n", debugstr_w(s), iid);
2269 if (!s)
2271 memset(iid, 0, sizeof(*iid));
2272 return S_OK;
2275 /* length mismatch is a special case */
2276 if (strlenW(s) + 1 != CHARS_IN_GUID)
2277 return E_INVALIDARG;
2279 if (s[0] != '{')
2280 return CO_E_IIDSTRING;
2282 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2285 /******************************************************************************
2286 * StringFromCLSID [OLE32.@]
2287 * StringFromIID [OLE32.@]
2289 * Converts a GUID into the respective string representation.
2290 * The target string is allocated using the OLE IMalloc.
2292 * PARAMS
2293 * id [I] the GUID to be converted.
2294 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2296 * RETURNS
2297 * S_OK
2298 * E_FAIL
2300 * SEE ALSO
2301 * StringFromGUID2, CLSIDFromString
2303 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2305 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2306 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2307 return S_OK;
2310 /******************************************************************************
2311 * StringFromGUID2 [OLE32.@]
2313 * Modified version of StringFromCLSID that allows you to specify max
2314 * buffer size.
2316 * PARAMS
2317 * id [I] GUID to convert to string.
2318 * str [O] Buffer where the result will be stored.
2319 * cmax [I] Size of the buffer in characters.
2321 * RETURNS
2322 * Success: The length of the resulting string in characters.
2323 * Failure: 0.
2325 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2327 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2328 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2329 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2330 '%','0','2','X','%','0','2','X','}',0 };
2331 if (!id || cmax < CHARS_IN_GUID) return 0;
2332 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2333 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2334 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2335 return CHARS_IN_GUID;
2338 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2339 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2341 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2342 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2343 LONG res;
2344 HKEY key;
2346 strcpyW(path, wszCLSIDSlash);
2347 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2348 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2349 if (res == ERROR_FILE_NOT_FOUND)
2350 return REGDB_E_CLASSNOTREG;
2351 else if (res != ERROR_SUCCESS)
2352 return REGDB_E_READREGDB;
2354 if (!keyname)
2356 *subkey = key;
2357 return S_OK;
2360 res = open_classes_key(key, keyname, access, subkey);
2361 RegCloseKey(key);
2362 if (res == ERROR_FILE_NOT_FOUND)
2363 return REGDB_E_KEYMISSING;
2364 else if (res != ERROR_SUCCESS)
2365 return REGDB_E_READREGDB;
2367 return S_OK;
2370 /* open HKCR\\AppId\\{string form of appid clsid} key */
2371 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2373 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2374 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2375 DWORD res;
2376 WCHAR buf[CHARS_IN_GUID];
2377 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2378 DWORD size;
2379 HKEY hkey;
2380 DWORD type;
2381 HRESULT hr;
2383 /* read the AppID value under the class's key */
2384 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2385 if (FAILED(hr))
2386 return hr;
2388 size = sizeof(buf);
2389 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2390 RegCloseKey(hkey);
2391 if (res == ERROR_FILE_NOT_FOUND)
2392 return REGDB_E_KEYMISSING;
2393 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2394 return REGDB_E_READREGDB;
2396 strcpyW(keyname, szAppIdKey);
2397 strcatW(keyname, buf);
2398 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2399 if (res == ERROR_FILE_NOT_FOUND)
2400 return REGDB_E_KEYMISSING;
2401 else if (res != ERROR_SUCCESS)
2402 return REGDB_E_READREGDB;
2404 return S_OK;
2407 /******************************************************************************
2408 * ProgIDFromCLSID [OLE32.@]
2410 * Converts a class id into the respective program ID.
2412 * PARAMS
2413 * clsid [I] Class ID, as found in registry.
2414 * ppszProgID [O] Associated ProgID.
2416 * RETURNS
2417 * S_OK
2418 * E_OUTOFMEMORY
2419 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2421 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2423 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2424 ACTCTX_SECTION_KEYED_DATA data;
2425 HKEY hkey;
2426 HRESULT ret;
2427 LONG progidlen = 0;
2429 if (!ppszProgID)
2430 return E_INVALIDARG;
2432 *ppszProgID = NULL;
2434 data.cbSize = sizeof(data);
2435 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2436 clsid, &data))
2438 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2439 if (comclass->progid_len)
2441 WCHAR *ptrW;
2443 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2444 if (!*ppszProgID) return E_OUTOFMEMORY;
2446 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2447 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2448 return S_OK;
2450 else
2451 return REGDB_E_CLASSNOTREG;
2454 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2455 if (FAILED(ret))
2456 return ret;
2458 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2459 ret = REGDB_E_CLASSNOTREG;
2461 if (ret == S_OK)
2463 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2464 if (*ppszProgID)
2466 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2467 ret = REGDB_E_CLASSNOTREG;
2468 CoTaskMemFree(*ppszProgID);
2469 *ppszProgID = NULL;
2472 else
2473 ret = E_OUTOFMEMORY;
2476 RegCloseKey(hkey);
2477 return ret;
2480 /******************************************************************************
2481 * CLSIDFromProgID [OLE32.@]
2483 * Converts a program id into the respective GUID.
2485 * PARAMS
2486 * progid [I] Unicode program ID, as found in registry.
2487 * clsid [O] Associated CLSID.
2489 * RETURNS
2490 * Success: S_OK
2491 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2493 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2495 ACTCTX_SECTION_KEYED_DATA data;
2497 if (!progid || !clsid)
2498 return E_INVALIDARG;
2500 data.cbSize = sizeof(data);
2501 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2502 progid, &data))
2504 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2505 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2506 *clsid = *alias;
2507 return S_OK;
2510 return clsid_from_string_reg(progid, clsid);
2513 /******************************************************************************
2514 * CLSIDFromProgIDEx [OLE32.@]
2516 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2518 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2520 return CLSIDFromProgID(progid, clsid);
2523 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2525 HKEY hkey;
2526 WCHAR value[CHARS_IN_GUID];
2527 DWORD len;
2529 access |= KEY_READ;
2531 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2532 return REGDB_E_IIDNOTREG;
2534 len = sizeof(value);
2535 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2536 return REGDB_E_IIDNOTREG;
2537 RegCloseKey(hkey);
2539 if (CLSIDFromString(value, pclsid) != NOERROR)
2540 return REGDB_E_IIDNOTREG;
2542 return S_OK;
2545 /*****************************************************************************
2546 * CoGetPSClsid [OLE32.@]
2548 * Retrieves the CLSID of the proxy/stub factory that implements
2549 * IPSFactoryBuffer for the specified interface.
2551 * PARAMS
2552 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2553 * pclsid [O] Where to store returned proxy/stub CLSID.
2555 * RETURNS
2556 * S_OK
2557 * E_OUTOFMEMORY
2558 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2560 * NOTES
2562 * The standard marshaller activates the object with the CLSID
2563 * returned and uses the CreateProxy and CreateStub methods on its
2564 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2565 * given object.
2567 * CoGetPSClsid determines this CLSID by searching the
2568 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2569 * in the registry and any interface id registered by
2570 * CoRegisterPSClsid within the current process.
2572 * BUGS
2574 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2575 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2576 * considered a bug in native unless an application depends on this (unlikely).
2578 * SEE ALSO
2579 * CoRegisterPSClsid.
2581 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2583 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2584 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2585 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2586 APARTMENT *apt = COM_CurrentApt();
2587 struct registered_psclsid *registered_psclsid;
2588 ACTCTX_SECTION_KEYED_DATA data;
2589 HRESULT hr;
2590 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2591 BOOL is_wow64;
2593 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2595 if (!apt)
2597 ERR("apartment not initialised\n");
2598 return CO_E_NOTINITIALIZED;
2601 if (!pclsid)
2602 return E_INVALIDARG;
2604 EnterCriticalSection(&cs_registered_psclsid_list);
2606 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2607 if (IsEqualIID(&registered_psclsid->iid, riid))
2609 *pclsid = registered_psclsid->clsid;
2610 LeaveCriticalSection(&cs_registered_psclsid_list);
2611 return S_OK;
2614 LeaveCriticalSection(&cs_registered_psclsid_list);
2616 data.cbSize = sizeof(data);
2617 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2618 riid, &data))
2620 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2621 *pclsid = ifaceps->iid;
2622 return S_OK;
2625 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2626 strcpyW(path, wszInterface);
2627 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2628 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2630 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2631 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2632 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2633 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2635 if (hr == S_OK)
2636 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2637 else
2638 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2640 return hr;
2643 /*****************************************************************************
2644 * CoRegisterPSClsid [OLE32.@]
2646 * Register a proxy/stub CLSID for the given interface in the current process
2647 * only.
2649 * PARAMS
2650 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2651 * rclsid [I] CLSID of the proxy/stub.
2653 * RETURNS
2654 * Success: S_OK
2655 * Failure: E_OUTOFMEMORY
2657 * NOTES
2659 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2660 * will be returned from other apartments in the same process.
2662 * This function does not add anything to the registry and the effects are
2663 * limited to the lifetime of the current process.
2665 * SEE ALSO
2666 * CoGetPSClsid.
2668 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2670 APARTMENT *apt = COM_CurrentApt();
2671 struct registered_psclsid *registered_psclsid;
2673 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2675 if (!apt)
2677 ERR("apartment not initialised\n");
2678 return CO_E_NOTINITIALIZED;
2681 EnterCriticalSection(&cs_registered_psclsid_list);
2683 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2684 if (IsEqualIID(&registered_psclsid->iid, riid))
2686 registered_psclsid->clsid = *rclsid;
2687 LeaveCriticalSection(&cs_registered_psclsid_list);
2688 return S_OK;
2691 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2692 if (!registered_psclsid)
2694 LeaveCriticalSection(&cs_registered_psclsid_list);
2695 return E_OUTOFMEMORY;
2698 registered_psclsid->iid = *riid;
2699 registered_psclsid->clsid = *rclsid;
2700 list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2702 LeaveCriticalSection(&cs_registered_psclsid_list);
2704 return S_OK;
2708 /***
2709 * COM_GetRegisteredClassObject
2711 * This internal method is used to scan the registered class list to
2712 * find a class object.
2714 * Params:
2715 * rclsid Class ID of the class to find.
2716 * dwClsContext Class context to match.
2717 * ppv [out] returns a pointer to the class object. Complying
2718 * to normal COM usage, this method will increase the
2719 * reference count on this object.
2721 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2722 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2724 HRESULT hr = S_FALSE;
2725 RegisteredClass *curClass;
2727 EnterCriticalSection( &csRegisteredClassList );
2729 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2732 * Check if we have a match on the class ID and context.
2734 if ((apt->oxid == curClass->apartment_id) &&
2735 (dwClsContext & curClass->runContext) &&
2736 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2739 * We have a match, return the pointer to the class object.
2741 *ppUnk = curClass->classObject;
2743 IUnknown_AddRef(curClass->classObject);
2745 hr = S_OK;
2746 break;
2750 LeaveCriticalSection( &csRegisteredClassList );
2752 return hr;
2755 /******************************************************************************
2756 * CoRegisterClassObject [OLE32.@]
2758 * Registers the class object for a given class ID. Servers housed in EXE
2759 * files use this method instead of exporting DllGetClassObject to allow
2760 * other code to connect to their objects.
2762 * PARAMS
2763 * rclsid [I] CLSID of the object to register.
2764 * pUnk [I] IUnknown of the object.
2765 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2766 * flags [I] REGCLS flags indicating how connections are made.
2767 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2769 * RETURNS
2770 * S_OK on success,
2771 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2772 * CO_E_OBJISREG if the object is already registered. We should not return this.
2774 * SEE ALSO
2775 * CoRevokeClassObject, CoGetClassObject
2777 * NOTES
2778 * In-process objects are only registered for the current apartment.
2779 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2780 * in other apartments.
2782 * BUGS
2783 * MSDN claims that multiple interface registrations are legal, but we
2784 * can't do that with our current implementation.
2786 HRESULT WINAPI CoRegisterClassObject(
2787 REFCLSID rclsid,
2788 LPUNKNOWN pUnk,
2789 DWORD dwClsContext,
2790 DWORD flags,
2791 LPDWORD lpdwRegister)
2793 static LONG next_cookie;
2794 RegisteredClass* newClass;
2795 LPUNKNOWN foundObject;
2796 HRESULT hr;
2797 APARTMENT *apt;
2799 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2800 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2802 if ( (lpdwRegister==0) || (pUnk==0) )
2803 return E_INVALIDARG;
2805 apt = COM_CurrentApt();
2806 if (!apt)
2808 ERR("COM was not initialized\n");
2809 return CO_E_NOTINITIALIZED;
2812 *lpdwRegister = 0;
2814 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2815 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2816 if (flags & REGCLS_MULTIPLEUSE)
2817 dwClsContext |= CLSCTX_INPROC_SERVER;
2820 * First, check if the class is already registered.
2821 * If it is, this should cause an error.
2823 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2824 if (hr == S_OK) {
2825 if (flags & REGCLS_MULTIPLEUSE) {
2826 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2827 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2828 IUnknown_Release(foundObject);
2829 return hr;
2831 IUnknown_Release(foundObject);
2832 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2833 return CO_E_OBJISREG;
2836 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2837 if ( newClass == NULL )
2838 return E_OUTOFMEMORY;
2840 newClass->classIdentifier = *rclsid;
2841 newClass->apartment_id = apt->oxid;
2842 newClass->runContext = dwClsContext;
2843 newClass->connectFlags = flags;
2844 newClass->RpcRegistration = NULL;
2846 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2847 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2850 * Since we're making a copy of the object pointer, we have to increase its
2851 * reference count.
2853 newClass->classObject = pUnk;
2854 IUnknown_AddRef(newClass->classObject);
2856 EnterCriticalSection( &csRegisteredClassList );
2857 list_add_tail(&RegisteredClassList, &newClass->entry);
2858 LeaveCriticalSection( &csRegisteredClassList );
2860 *lpdwRegister = newClass->dwCookie;
2862 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2863 IStream *marshal_stream;
2865 hr = get_local_server_stream(apt, &marshal_stream);
2866 if(FAILED(hr))
2867 return hr;
2869 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2870 marshal_stream,
2871 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2872 &newClass->RpcRegistration);
2873 IStream_Release(marshal_stream);
2875 return S_OK;
2878 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2880 if (data->hkey)
2882 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2883 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2884 static const WCHAR wszFree[] = {'F','r','e','e',0};
2885 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2886 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2887 DWORD dwLength = sizeof(threading_model);
2888 DWORD keytype;
2889 DWORD ret;
2891 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2892 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2893 threading_model[0] = '\0';
2895 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2896 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2897 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2899 /* there's not specific handling for this case */
2900 if (threading_model[0]) return ThreadingModel_Neutral;
2901 return ThreadingModel_No;
2903 else
2904 return data->u.actctx.data->model;
2907 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2908 REFCLSID rclsid, REFIID riid,
2909 BOOL hostifnecessary, void **ppv)
2911 WCHAR dllpath[MAX_PATH+1];
2912 BOOL apartment_threaded;
2914 if (hostifnecessary)
2916 enum comclass_threadingmodel model = get_threading_model(regdata);
2918 if (model == ThreadingModel_Apartment)
2920 apartment_threaded = TRUE;
2921 if (apt->multi_threaded)
2922 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2924 else if (model == ThreadingModel_Free)
2926 apartment_threaded = FALSE;
2927 if (!apt->multi_threaded)
2928 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2930 /* everything except "Apartment", "Free" and "Both" */
2931 else if (model != ThreadingModel_Both)
2933 apartment_threaded = TRUE;
2934 /* everything else is main-threaded */
2935 if (model != ThreadingModel_No)
2936 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2938 if (apt->multi_threaded || !apt->main)
2939 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2941 else
2942 apartment_threaded = FALSE;
2944 else
2945 apartment_threaded = !apt->multi_threaded;
2947 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2949 /* failure: CLSID is not found in registry */
2950 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2951 return REGDB_E_CLASSNOTREG;
2954 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2955 rclsid, riid, ppv);
2958 /***********************************************************************
2959 * CoGetClassObject [OLE32.@]
2961 * Creates an object of the specified class.
2963 * PARAMS
2964 * rclsid [I] Class ID to create an instance of.
2965 * dwClsContext [I] Flags to restrict the location of the created instance.
2966 * pServerInfo [I] Optional. Details for connecting to a remote server.
2967 * iid [I] The ID of the interface of the instance to return.
2968 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2970 * RETURNS
2971 * Success: S_OK
2972 * Failure: HRESULT code.
2974 * NOTES
2975 * The dwClsContext parameter can be one or more of the following:
2976 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2977 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2978 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2979 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2981 * SEE ALSO
2982 * CoCreateInstance()
2984 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2985 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2986 REFIID iid, LPVOID *ppv)
2988 struct class_reg_data clsreg;
2989 IUnknown *regClassObject;
2990 HRESULT hres = E_UNEXPECTED;
2991 APARTMENT *apt;
2992 BOOL release_apt = FALSE;
2994 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2996 if (!ppv)
2997 return E_INVALIDARG;
2999 *ppv = NULL;
3001 if (!(apt = COM_CurrentApt()))
3003 if (!(apt = apartment_find_multi_threaded()))
3005 ERR("apartment not initialised\n");
3006 return CO_E_NOTINITIALIZED;
3008 release_apt = TRUE;
3011 if (pServerInfo) {
3012 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3013 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
3016 if (CLSCTX_INPROC_SERVER & dwClsContext)
3018 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
3020 if (release_apt) apartment_release(apt);
3021 return FTMarshalCF_Create(iid, ppv);
3023 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3024 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3027 if (CLSCTX_INPROC & dwClsContext)
3029 ACTCTX_SECTION_KEYED_DATA data;
3031 data.cbSize = sizeof(data);
3032 /* search activation context first */
3033 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3034 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3035 rclsid, &data))
3037 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3039 clsreg.u.actctx.hactctx = data.hActCtx;
3040 clsreg.u.actctx.data = data.lpData;
3041 clsreg.u.actctx.section = data.lpSectionBase;
3042 clsreg.hkey = FALSE;
3044 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3045 ReleaseActCtx(data.hActCtx);
3046 if (release_apt) apartment_release(apt);
3047 return hres;
3052 * First, try and see if we can't match the class ID with one of the
3053 * registered classes.
3055 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3056 &regClassObject))
3058 /* Get the required interface from the retrieved pointer. */
3059 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3062 * Since QI got another reference on the pointer, we want to release the
3063 * one we already have. If QI was unsuccessful, this will release the object. This
3064 * is good since we are not returning it in the "out" parameter.
3066 IUnknown_Release(regClassObject);
3067 if (release_apt) apartment_release(apt);
3068 return hres;
3071 /* First try in-process server */
3072 if (CLSCTX_INPROC_SERVER & dwClsContext)
3074 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3075 HKEY hkey;
3077 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3078 if (FAILED(hres))
3080 if (hres == REGDB_E_CLASSNOTREG)
3081 ERR("class %s not registered\n", debugstr_guid(rclsid));
3082 else if (hres == REGDB_E_KEYMISSING)
3084 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3085 hres = REGDB_E_CLASSNOTREG;
3089 if (SUCCEEDED(hres))
3091 clsreg.u.hkey = hkey;
3092 clsreg.hkey = TRUE;
3094 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3095 RegCloseKey(hkey);
3098 /* return if we got a class, otherwise fall through to one of the
3099 * other types */
3100 if (SUCCEEDED(hres))
3102 if (release_apt) apartment_release(apt);
3103 return hres;
3107 /* Next try in-process handler */
3108 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3110 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3111 HKEY hkey;
3113 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3114 if (FAILED(hres))
3116 if (hres == REGDB_E_CLASSNOTREG)
3117 ERR("class %s not registered\n", debugstr_guid(rclsid));
3118 else if (hres == REGDB_E_KEYMISSING)
3120 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3121 hres = REGDB_E_CLASSNOTREG;
3125 if (SUCCEEDED(hres))
3127 clsreg.u.hkey = hkey;
3128 clsreg.hkey = TRUE;
3130 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3131 RegCloseKey(hkey);
3134 /* return if we got a class, otherwise fall through to one of the
3135 * other types */
3136 if (SUCCEEDED(hres))
3138 if (release_apt) apartment_release(apt);
3139 return hres;
3142 if (release_apt) apartment_release(apt);
3144 /* Next try out of process */
3145 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3147 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3148 if (SUCCEEDED(hres))
3149 return hres;
3152 /* Finally try remote: this requires networked DCOM (a lot of work) */
3153 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3155 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3156 hres = REGDB_E_CLASSNOTREG;
3159 if (FAILED(hres))
3160 ERR("no class object %s could be created for context 0x%x\n",
3161 debugstr_guid(rclsid), dwClsContext);
3162 return hres;
3165 /***********************************************************************
3166 * CoResumeClassObjects (OLE32.@)
3168 * Resumes all class objects registered with REGCLS_SUSPENDED.
3170 * RETURNS
3171 * Success: S_OK.
3172 * Failure: HRESULT code.
3174 HRESULT WINAPI CoResumeClassObjects(void)
3176 FIXME("stub\n");
3177 return S_OK;
3180 /***********************************************************************
3181 * CoCreateInstance [OLE32.@]
3183 * Creates an instance of the specified class.
3185 * PARAMS
3186 * rclsid [I] Class ID to create an instance of.
3187 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3188 * dwClsContext [I] Flags to restrict the location of the created instance.
3189 * iid [I] The ID of the interface of the instance to return.
3190 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3192 * RETURNS
3193 * Success: S_OK
3194 * Failure: HRESULT code.
3196 * NOTES
3197 * The dwClsContext parameter can be one or more of the following:
3198 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3199 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3200 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3201 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3203 * Aggregation is the concept of deferring the IUnknown of an object to another
3204 * object. This allows a separate object to behave as though it was part of
3205 * the object and to allow this the pUnkOuter parameter can be set. Note that
3206 * not all objects support having an outer of unknown.
3208 * SEE ALSO
3209 * CoGetClassObject()
3211 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3212 REFCLSID rclsid,
3213 LPUNKNOWN pUnkOuter,
3214 DWORD dwClsContext,
3215 REFIID iid,
3216 LPVOID *ppv)
3218 MULTI_QI multi_qi = { iid };
3219 HRESULT hres;
3221 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3222 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3224 if (ppv==0)
3225 return E_POINTER;
3227 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3228 *ppv = multi_qi.pItf;
3229 return hres;
3232 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3234 ULONG i;
3236 for (i = 0; i < count; i++)
3238 mqi[i].pItf = NULL;
3239 mqi[i].hr = hr;
3243 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3245 ULONG index = 0, fetched = 0;
3247 if (include_unk)
3249 mqi[0].hr = S_OK;
3250 mqi[0].pItf = unk;
3251 index = fetched = 1;
3254 for (; index < count; index++)
3256 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3257 if (mqi[index].hr == S_OK)
3258 fetched++;
3261 if (!include_unk)
3262 IUnknown_Release(unk);
3264 if (fetched == 0)
3265 return E_NOINTERFACE;
3267 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3270 /***********************************************************************
3271 * CoCreateInstanceEx [OLE32.@]
3273 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3274 REFCLSID rclsid,
3275 LPUNKNOWN pUnkOuter,
3276 DWORD dwClsContext,
3277 COSERVERINFO* pServerInfo,
3278 ULONG cmq,
3279 MULTI_QI* pResults)
3281 IUnknown *unk = NULL;
3282 IClassFactory *cf;
3283 APARTMENT *apt;
3284 CLSID clsid;
3285 HRESULT hres;
3287 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3289 if (!cmq || !pResults)
3290 return E_INVALIDARG;
3292 if (pServerInfo)
3293 FIXME("() non-NULL pServerInfo not supported!\n");
3295 init_multi_qi(cmq, pResults, E_NOINTERFACE);
3297 hres = CoGetTreatAsClass(rclsid, &clsid);
3298 if(FAILED(hres))
3299 clsid = *rclsid;
3301 if (!(apt = COM_CurrentApt()))
3303 if (!(apt = apartment_find_multi_threaded()))
3305 ERR("apartment not initialised\n");
3306 return CO_E_NOTINITIALIZED;
3308 apartment_release(apt);
3312 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3314 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3316 IGlobalInterfaceTable *git = get_std_git();
3317 TRACE("Retrieving GIT\n");
3318 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3321 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3322 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3323 if (FAILED(hres))
3324 return hres;
3325 return return_multi_qi(unk, cmq, pResults, TRUE);
3329 * Get a class factory to construct the object we want.
3331 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3332 if (FAILED(hres))
3333 return hres;
3336 * Create the object and don't forget to release the factory
3338 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3339 IClassFactory_Release(cf);
3340 if (FAILED(hres))
3342 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3343 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3344 else
3345 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3346 debugstr_guid(pResults[0].pIID),
3347 debugstr_guid(&clsid),hres);
3348 return hres;
3351 return return_multi_qi(unk, cmq, pResults, TRUE);
3354 /***********************************************************************
3355 * CoGetInstanceFromFile [OLE32.@]
3357 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3358 COSERVERINFO *server_info,
3359 CLSID *rclsid,
3360 IUnknown *outer,
3361 DWORD cls_context,
3362 DWORD grfmode,
3363 OLECHAR *filename,
3364 DWORD count,
3365 MULTI_QI *results
3368 IPersistFile *pf = NULL;
3369 IUnknown* unk = NULL;
3370 CLSID clsid;
3371 HRESULT hr;
3373 if (count == 0 || !results)
3374 return E_INVALIDARG;
3376 if (server_info)
3377 FIXME("() non-NULL server_info not supported\n");
3379 init_multi_qi(count, results, E_NOINTERFACE);
3381 /* optionally get CLSID from a file */
3382 if (!rclsid)
3384 hr = GetClassFile(filename, &clsid);
3385 if (FAILED(hr))
3387 ERR("failed to get CLSID from a file\n");
3388 return hr;
3391 rclsid = &clsid;
3394 hr = CoCreateInstance(rclsid,
3395 outer,
3396 cls_context,
3397 &IID_IUnknown,
3398 (void**)&unk);
3400 if (hr != S_OK)
3402 init_multi_qi(count, results, hr);
3403 return hr;
3406 /* init from file */
3407 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3408 if (FAILED(hr))
3410 init_multi_qi(count, results, hr);
3411 IUnknown_Release(unk);
3412 return hr;
3415 hr = IPersistFile_Load(pf, filename, grfmode);
3416 IPersistFile_Release(pf);
3417 if (SUCCEEDED(hr))
3418 return return_multi_qi(unk, count, results, FALSE);
3419 else
3421 init_multi_qi(count, results, hr);
3422 IUnknown_Release(unk);
3423 return hr;
3427 /***********************************************************************
3428 * CoGetInstanceFromIStorage [OLE32.@]
3430 HRESULT WINAPI CoGetInstanceFromIStorage(
3431 COSERVERINFO *server_info,
3432 CLSID *rclsid,
3433 IUnknown *outer,
3434 DWORD cls_context,
3435 IStorage *storage,
3436 DWORD count,
3437 MULTI_QI *results
3440 IPersistStorage *ps = NULL;
3441 IUnknown* unk = NULL;
3442 STATSTG stat;
3443 HRESULT hr;
3445 if (count == 0 || !results || !storage)
3446 return E_INVALIDARG;
3448 if (server_info)
3449 FIXME("() non-NULL server_info not supported\n");
3451 init_multi_qi(count, results, E_NOINTERFACE);
3453 /* optionally get CLSID from a file */
3454 if (!rclsid)
3456 memset(&stat.clsid, 0, sizeof(stat.clsid));
3457 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3458 if (FAILED(hr))
3460 ERR("failed to get CLSID from a file\n");
3461 return hr;
3464 rclsid = &stat.clsid;
3467 hr = CoCreateInstance(rclsid,
3468 outer,
3469 cls_context,
3470 &IID_IUnknown,
3471 (void**)&unk);
3473 if (hr != S_OK)
3474 return hr;
3476 /* init from IStorage */
3477 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3478 if (FAILED(hr))
3479 ERR("failed to get IPersistStorage\n");
3481 if (ps)
3483 IPersistStorage_Load(ps, storage);
3484 IPersistStorage_Release(ps);
3487 return return_multi_qi(unk, count, results, FALSE);
3490 /***********************************************************************
3491 * CoLoadLibrary (OLE32.@)
3493 * Loads a library.
3495 * PARAMS
3496 * lpszLibName [I] Path to library.
3497 * bAutoFree [I] Whether the library should automatically be freed.
3499 * RETURNS
3500 * Success: Handle to loaded library.
3501 * Failure: NULL.
3503 * SEE ALSO
3504 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3506 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3508 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3510 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3513 /***********************************************************************
3514 * CoFreeLibrary [OLE32.@]
3516 * Unloads a library from memory.
3518 * PARAMS
3519 * hLibrary [I] Handle to library to unload.
3521 * RETURNS
3522 * Nothing
3524 * SEE ALSO
3525 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3527 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3529 FreeLibrary(hLibrary);
3533 /***********************************************************************
3534 * CoFreeAllLibraries [OLE32.@]
3536 * Function for backwards compatibility only. Does nothing.
3538 * RETURNS
3539 * Nothing.
3541 * SEE ALSO
3542 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3544 void WINAPI CoFreeAllLibraries(void)
3546 /* NOP */
3549 /***********************************************************************
3550 * CoFreeUnusedLibrariesEx [OLE32.@]
3552 * Frees any previously unused libraries whose delay has expired and marks
3553 * currently unused libraries for unloading. Unused are identified as those that
3554 * return S_OK from their DllCanUnloadNow function.
3556 * PARAMS
3557 * dwUnloadDelay [I] Unload delay in milliseconds.
3558 * dwReserved [I] Reserved. Set to 0.
3560 * RETURNS
3561 * Nothing.
3563 * SEE ALSO
3564 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3566 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3568 struct apartment *apt = COM_CurrentApt();
3569 if (!apt)
3571 ERR("apartment not initialised\n");
3572 return;
3575 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3578 /***********************************************************************
3579 * CoFreeUnusedLibraries [OLE32.@]
3581 * Frees any unused libraries. Unused are identified as those that return
3582 * S_OK from their DllCanUnloadNow function.
3584 * RETURNS
3585 * Nothing.
3587 * SEE ALSO
3588 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3590 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3592 CoFreeUnusedLibrariesEx(INFINITE, 0);
3595 /***********************************************************************
3596 * CoFileTimeNow [OLE32.@]
3598 * Retrieves the current time in FILETIME format.
3600 * PARAMS
3601 * lpFileTime [O] The current time.
3603 * RETURNS
3604 * S_OK.
3606 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3608 GetSystemTimeAsFileTime( lpFileTime );
3609 return S_OK;
3612 /******************************************************************************
3613 * CoLockObjectExternal [OLE32.@]
3615 * Increments or decrements the external reference count of a stub object.
3617 * PARAMS
3618 * pUnk [I] Stub object.
3619 * fLock [I] If TRUE then increments the external ref-count,
3620 * otherwise decrements.
3621 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3622 * calling CoDisconnectObject.
3624 * RETURNS
3625 * Success: S_OK.
3626 * Failure: HRESULT code.
3628 * NOTES
3629 * If fLock is TRUE and an object is passed in that doesn't have a stub
3630 * manager then a new stub manager is created for the object.
3632 HRESULT WINAPI CoLockObjectExternal(
3633 LPUNKNOWN pUnk,
3634 BOOL fLock,
3635 BOOL fLastUnlockReleases)
3637 struct stub_manager *stubmgr;
3638 struct apartment *apt;
3640 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3641 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3643 apt = COM_CurrentApt();
3644 if (!apt) return CO_E_NOTINITIALIZED;
3646 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3647 if (!stubmgr)
3649 WARN("stub object not found %p\n", pUnk);
3650 /* Note: native is pretty broken here because it just silently
3651 * fails, without returning an appropriate error code, making apps
3652 * think that the object was disconnected, when it actually wasn't */
3653 return S_OK;
3656 if (fLock)
3657 stub_manager_ext_addref(stubmgr, 1, FALSE);
3658 else
3659 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3661 stub_manager_int_release(stubmgr);
3662 return S_OK;
3665 /***********************************************************************
3666 * CoInitializeWOW (OLE32.@)
3668 * WOW equivalent of CoInitialize?
3670 * PARAMS
3671 * x [I] Unknown.
3672 * y [I] Unknown.
3674 * RETURNS
3675 * Unknown.
3677 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3679 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3680 return 0;
3683 /***********************************************************************
3684 * CoGetState [OLE32.@]
3686 * Retrieves the thread state object previously stored by CoSetState().
3688 * PARAMS
3689 * ppv [I] Address where pointer to object will be stored.
3691 * RETURNS
3692 * Success: S_OK.
3693 * Failure: E_OUTOFMEMORY.
3695 * NOTES
3696 * Crashes on all invalid ppv addresses, including NULL.
3697 * If the function returns a non-NULL object then the caller must release its
3698 * reference on the object when the object is no longer required.
3700 * SEE ALSO
3701 * CoSetState().
3703 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3705 struct oletls *info = COM_CurrentInfo();
3706 if (!info) return E_OUTOFMEMORY;
3708 *ppv = NULL;
3710 if (info->state)
3712 IUnknown_AddRef(info->state);
3713 *ppv = info->state;
3714 TRACE("apt->state=%p\n", info->state);
3717 return S_OK;
3720 /***********************************************************************
3721 * CoSetState [OLE32.@]
3723 * Sets the thread state object.
3725 * PARAMS
3726 * pv [I] Pointer to state object to be stored.
3728 * NOTES
3729 * The system keeps a reference on the object while the object stored.
3731 * RETURNS
3732 * Success: S_OK.
3733 * Failure: E_OUTOFMEMORY.
3735 HRESULT WINAPI CoSetState(IUnknown * pv)
3737 struct oletls *info = COM_CurrentInfo();
3738 if (!info) return E_OUTOFMEMORY;
3740 if (pv) IUnknown_AddRef(pv);
3742 if (info->state)
3744 TRACE("-- release %p now\n", info->state);
3745 IUnknown_Release(info->state);
3748 info->state = pv;
3750 return S_OK;
3754 /******************************************************************************
3755 * CoTreatAsClass [OLE32.@]
3757 * Sets the TreatAs value of a class.
3759 * PARAMS
3760 * clsidOld [I] Class to set TreatAs value on.
3761 * clsidNew [I] The class the clsidOld should be treated as.
3763 * RETURNS
3764 * Success: S_OK.
3765 * Failure: HRESULT code.
3767 * SEE ALSO
3768 * CoGetTreatAsClass
3770 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3772 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3773 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3774 HKEY hkey = NULL;
3775 WCHAR szClsidNew[CHARS_IN_GUID];
3776 HRESULT res = S_OK;
3777 WCHAR auto_treat_as[CHARS_IN_GUID];
3778 LONG auto_treat_as_size = sizeof(auto_treat_as);
3779 CLSID id;
3781 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3782 if (FAILED(res))
3783 goto done;
3785 if (IsEqualGUID( clsidOld, clsidNew ))
3787 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3788 CLSIDFromString(auto_treat_as, &id) == S_OK)
3790 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3792 res = REGDB_E_WRITEREGDB;
3793 goto done;
3796 else
3798 if(RegDeleteKeyW(hkey, wszTreatAs))
3799 res = REGDB_E_WRITEREGDB;
3800 goto done;
3803 else
3805 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3806 RegDeleteKeyW(hkey, wszTreatAs);
3807 }else{
3808 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3809 WARN("StringFromGUID2 failed\n");
3810 res = E_FAIL;
3811 goto done;
3814 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3815 WARN("RegSetValue failed\n");
3816 res = REGDB_E_WRITEREGDB;
3817 goto done;
3822 done:
3823 if (hkey) RegCloseKey(hkey);
3824 return res;
3827 /******************************************************************************
3828 * CoGetTreatAsClass [OLE32.@]
3830 * Gets the TreatAs value of a class.
3832 * PARAMS
3833 * clsidOld [I] Class to get the TreatAs value of.
3834 * clsidNew [I] The class the clsidOld should be treated as.
3836 * RETURNS
3837 * Success: S_OK.
3838 * Failure: HRESULT code.
3840 * SEE ALSO
3841 * CoSetTreatAsClass
3843 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3845 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3846 HKEY hkey = NULL;
3847 WCHAR szClsidNew[CHARS_IN_GUID];
3848 HRESULT res = S_OK;
3849 LONG len = sizeof(szClsidNew);
3851 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3853 if (!clsidOld || !clsidNew)
3854 return E_INVALIDARG;
3856 *clsidNew = *clsidOld; /* copy over old value */
3858 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3859 if (FAILED(res))
3861 res = S_FALSE;
3862 goto done;
3864 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3866 res = S_FALSE;
3867 goto done;
3869 res = CLSIDFromString(szClsidNew,clsidNew);
3870 if (FAILED(res))
3871 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3872 done:
3873 if (hkey) RegCloseKey(hkey);
3874 return res;
3877 /******************************************************************************
3878 * CoGetCurrentProcess [OLE32.@]
3880 * Gets the current process ID.
3882 * RETURNS
3883 * The current process ID.
3885 * NOTES
3886 * Is DWORD really the correct return type for this function?
3888 DWORD WINAPI CoGetCurrentProcess(void)
3890 return GetCurrentProcessId();
3893 /***********************************************************************
3894 * CoGetCurrentLogicalThreadId [OLE32.@]
3896 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
3898 TRACE("(%p)\n", id);
3900 if (!id)
3901 return E_INVALIDARG;
3903 *id = COM_CurrentCausalityId();
3904 return S_OK;
3907 /******************************************************************************
3908 * CoRegisterMessageFilter [OLE32.@]
3910 * Registers a message filter.
3912 * PARAMS
3913 * lpMessageFilter [I] Pointer to interface.
3914 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3916 * RETURNS
3917 * Success: S_OK.
3918 * Failure: HRESULT code.
3920 * NOTES
3921 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3922 * lpMessageFilter removes the message filter.
3924 * If lplpMessageFilter is not NULL the previous message filter will be
3925 * returned in the memory pointer to this parameter and the caller is
3926 * responsible for releasing the object.
3928 * The current thread be in an apartment otherwise the function will crash.
3930 HRESULT WINAPI CoRegisterMessageFilter(
3931 LPMESSAGEFILTER lpMessageFilter,
3932 LPMESSAGEFILTER *lplpMessageFilter)
3934 struct apartment *apt;
3935 IMessageFilter *lpOldMessageFilter;
3937 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3939 apt = COM_CurrentApt();
3941 /* can't set a message filter in a multi-threaded apartment */
3942 if (!apt || apt->multi_threaded)
3944 WARN("can't set message filter in MTA or uninitialized apt\n");
3945 return CO_E_NOT_SUPPORTED;
3948 if (lpMessageFilter)
3949 IMessageFilter_AddRef(lpMessageFilter);
3951 EnterCriticalSection(&apt->cs);
3953 lpOldMessageFilter = apt->filter;
3954 apt->filter = lpMessageFilter;
3956 LeaveCriticalSection(&apt->cs);
3958 if (lplpMessageFilter)
3959 *lplpMessageFilter = lpOldMessageFilter;
3960 else if (lpOldMessageFilter)
3961 IMessageFilter_Release(lpOldMessageFilter);
3963 return S_OK;
3966 /***********************************************************************
3967 * CoIsOle1Class [OLE32.@]
3969 * Determines whether the specified class an OLE v1 class.
3971 * PARAMS
3972 * clsid [I] Class to test.
3974 * RETURNS
3975 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3977 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3979 FIXME("%s\n", debugstr_guid(clsid));
3980 return FALSE;
3983 /***********************************************************************
3984 * IsEqualGUID [OLE32.@]
3986 * Compares two Unique Identifiers.
3988 * PARAMS
3989 * rguid1 [I] The first GUID to compare.
3990 * rguid2 [I] The other GUID to compare.
3992 * RETURNS
3993 * TRUE if equal
3995 #undef IsEqualGUID
3996 BOOL WINAPI IsEqualGUID(
3997 REFGUID rguid1,
3998 REFGUID rguid2)
4000 return !memcmp(rguid1,rguid2,sizeof(GUID));
4003 /***********************************************************************
4004 * CoInitializeSecurity [OLE32.@]
4006 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
4007 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
4008 void* pReserved1, DWORD dwAuthnLevel,
4009 DWORD dwImpLevel, void* pReserved2,
4010 DWORD dwCapabilities, void* pReserved3)
4012 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
4013 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
4014 dwCapabilities, pReserved3);
4015 return S_OK;
4018 /***********************************************************************
4019 * CoSuspendClassObjects [OLE32.@]
4021 * Suspends all registered class objects to prevent further requests coming in
4022 * for those objects.
4024 * RETURNS
4025 * Success: S_OK.
4026 * Failure: HRESULT code.
4028 HRESULT WINAPI CoSuspendClassObjects(void)
4030 FIXME("\n");
4031 return S_OK;
4034 /***********************************************************************
4035 * CoAddRefServerProcess [OLE32.@]
4037 * Helper function for incrementing the reference count of a local-server
4038 * process.
4040 * RETURNS
4041 * New reference count.
4043 * SEE ALSO
4044 * CoReleaseServerProcess().
4046 ULONG WINAPI CoAddRefServerProcess(void)
4048 ULONG refs;
4050 TRACE("\n");
4052 EnterCriticalSection(&csRegisteredClassList);
4053 refs = ++s_COMServerProcessReferences;
4054 LeaveCriticalSection(&csRegisteredClassList);
4056 TRACE("refs before: %d\n", refs - 1);
4058 return refs;
4061 /***********************************************************************
4062 * CoReleaseServerProcess [OLE32.@]
4064 * Helper function for decrementing the reference count of a local-server
4065 * process.
4067 * RETURNS
4068 * New reference count.
4070 * NOTES
4071 * When reference count reaches 0, this function suspends all registered
4072 * classes so no new connections are accepted.
4074 * SEE ALSO
4075 * CoAddRefServerProcess(), CoSuspendClassObjects().
4077 ULONG WINAPI CoReleaseServerProcess(void)
4079 ULONG refs;
4081 TRACE("\n");
4083 EnterCriticalSection(&csRegisteredClassList);
4085 refs = --s_COMServerProcessReferences;
4086 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4088 LeaveCriticalSection(&csRegisteredClassList);
4090 TRACE("refs after: %d\n", refs);
4092 return refs;
4095 /***********************************************************************
4096 * CoIsHandlerConnected [OLE32.@]
4098 * Determines whether a proxy is connected to a remote stub.
4100 * PARAMS
4101 * pUnk [I] Pointer to object that may or may not be connected.
4103 * RETURNS
4104 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4105 * FALSE otherwise.
4107 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4109 FIXME("%p\n", pUnk);
4111 return TRUE;
4114 /***********************************************************************
4115 * CoAllowSetForegroundWindow [OLE32.@]
4118 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4120 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4121 return S_OK;
4124 /***********************************************************************
4125 * CoQueryProxyBlanket [OLE32.@]
4127 * Retrieves the security settings being used by a proxy.
4129 * PARAMS
4130 * pProxy [I] Pointer to the proxy object.
4131 * pAuthnSvc [O] The type of authentication service.
4132 * pAuthzSvc [O] The type of authorization service.
4133 * ppServerPrincName [O] Optional. The server prinicple name.
4134 * pAuthnLevel [O] The authentication level.
4135 * pImpLevel [O] The impersonation level.
4136 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4137 * pCapabilities [O] Flags affecting the security behaviour.
4139 * RETURNS
4140 * Success: S_OK.
4141 * Failure: HRESULT code.
4143 * SEE ALSO
4144 * CoCopyProxy, CoSetProxyBlanket.
4146 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4147 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4148 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4150 IClientSecurity *pCliSec;
4151 HRESULT hr;
4153 TRACE("%p\n", pProxy);
4155 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4156 if (SUCCEEDED(hr))
4158 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4159 pAuthzSvc, ppServerPrincName,
4160 pAuthnLevel, pImpLevel, ppAuthInfo,
4161 pCapabilities);
4162 IClientSecurity_Release(pCliSec);
4165 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4166 return hr;
4169 /***********************************************************************
4170 * CoSetProxyBlanket [OLE32.@]
4172 * Sets the security settings for a proxy.
4174 * PARAMS
4175 * pProxy [I] Pointer to the proxy object.
4176 * AuthnSvc [I] The type of authentication service.
4177 * AuthzSvc [I] The type of authorization service.
4178 * pServerPrincName [I] The server prinicple name.
4179 * AuthnLevel [I] The authentication level.
4180 * ImpLevel [I] The impersonation level.
4181 * pAuthInfo [I] Information specific to the authorization/authentication service.
4182 * Capabilities [I] Flags affecting the security behaviour.
4184 * RETURNS
4185 * Success: S_OK.
4186 * Failure: HRESULT code.
4188 * SEE ALSO
4189 * CoQueryProxyBlanket, CoCopyProxy.
4191 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4192 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4193 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4195 IClientSecurity *pCliSec;
4196 HRESULT hr;
4198 TRACE("%p\n", pProxy);
4200 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4201 if (SUCCEEDED(hr))
4203 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4204 AuthzSvc, pServerPrincName,
4205 AuthnLevel, ImpLevel, pAuthInfo,
4206 Capabilities);
4207 IClientSecurity_Release(pCliSec);
4210 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4211 return hr;
4214 /***********************************************************************
4215 * CoCopyProxy [OLE32.@]
4217 * Copies a proxy.
4219 * PARAMS
4220 * pProxy [I] Pointer to the proxy object.
4221 * ppCopy [O] Copy of the proxy.
4223 * RETURNS
4224 * Success: S_OK.
4225 * Failure: HRESULT code.
4227 * SEE ALSO
4228 * CoQueryProxyBlanket, CoSetProxyBlanket.
4230 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4232 IClientSecurity *pCliSec;
4233 HRESULT hr;
4235 TRACE("%p\n", pProxy);
4237 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4238 if (SUCCEEDED(hr))
4240 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4241 IClientSecurity_Release(pCliSec);
4244 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4245 return hr;
4249 /***********************************************************************
4250 * CoGetCallContext [OLE32.@]
4252 * Gets the context of the currently executing server call in the current
4253 * thread.
4255 * PARAMS
4256 * riid [I] Context interface to return.
4257 * ppv [O] Pointer to memory that will receive the context on return.
4259 * RETURNS
4260 * Success: S_OK.
4261 * Failure: HRESULT code.
4263 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4265 struct oletls *info = COM_CurrentInfo();
4267 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4269 if (!info)
4270 return E_OUTOFMEMORY;
4272 if (!info->call_state)
4273 return RPC_E_CALL_COMPLETE;
4275 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4278 /***********************************************************************
4279 * CoSwitchCallContext [OLE32.@]
4281 * Switches the context of the currently executing server call in the current
4282 * thread.
4284 * PARAMS
4285 * pObject [I] Pointer to new context object
4286 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4288 * RETURNS
4289 * Success: S_OK.
4290 * Failure: HRESULT code.
4292 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4294 struct oletls *info = COM_CurrentInfo();
4296 TRACE("(%p, %p)\n", pObject, ppOldObject);
4298 if (!info)
4299 return E_OUTOFMEMORY;
4301 *ppOldObject = info->call_state;
4302 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4304 return S_OK;
4307 /***********************************************************************
4308 * CoQueryClientBlanket [OLE32.@]
4310 * Retrieves the authentication information about the client of the currently
4311 * executing server call in the current thread.
4313 * PARAMS
4314 * pAuthnSvc [O] Optional. The type of authentication service.
4315 * pAuthzSvc [O] Optional. The type of authorization service.
4316 * pServerPrincName [O] Optional. The server prinicple name.
4317 * pAuthnLevel [O] Optional. The authentication level.
4318 * pImpLevel [O] Optional. The impersonation level.
4319 * pPrivs [O] Optional. Information about the privileges of the client.
4320 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4322 * RETURNS
4323 * Success: S_OK.
4324 * Failure: HRESULT code.
4326 * SEE ALSO
4327 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4329 HRESULT WINAPI CoQueryClientBlanket(
4330 DWORD *pAuthnSvc,
4331 DWORD *pAuthzSvc,
4332 OLECHAR **pServerPrincName,
4333 DWORD *pAuthnLevel,
4334 DWORD *pImpLevel,
4335 RPC_AUTHZ_HANDLE *pPrivs,
4336 DWORD *pCapabilities)
4338 IServerSecurity *pSrvSec;
4339 HRESULT hr;
4341 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4342 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4343 pPrivs, pCapabilities);
4345 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4346 if (SUCCEEDED(hr))
4348 hr = IServerSecurity_QueryBlanket(
4349 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4350 pImpLevel, pPrivs, pCapabilities);
4351 IServerSecurity_Release(pSrvSec);
4354 return hr;
4357 /***********************************************************************
4358 * CoImpersonateClient [OLE32.@]
4360 * Impersonates the client of the currently executing server call in the
4361 * current thread.
4363 * PARAMS
4364 * None.
4366 * RETURNS
4367 * Success: S_OK.
4368 * Failure: HRESULT code.
4370 * NOTES
4371 * If this function fails then the current thread will not be impersonating
4372 * the client and all actions will take place on behalf of the server.
4373 * Therefore, it is important to check the return value from this function.
4375 * SEE ALSO
4376 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4378 HRESULT WINAPI CoImpersonateClient(void)
4380 IServerSecurity *pSrvSec;
4381 HRESULT hr;
4383 TRACE("\n");
4385 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4386 if (SUCCEEDED(hr))
4388 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4389 IServerSecurity_Release(pSrvSec);
4392 return hr;
4395 /***********************************************************************
4396 * CoRevertToSelf [OLE32.@]
4398 * Ends the impersonation of the client of the currently executing server
4399 * call in the current thread.
4401 * PARAMS
4402 * None.
4404 * RETURNS
4405 * Success: S_OK.
4406 * Failure: HRESULT code.
4408 * SEE ALSO
4409 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4411 HRESULT WINAPI CoRevertToSelf(void)
4413 IServerSecurity *pSrvSec;
4414 HRESULT hr;
4416 TRACE("\n");
4418 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4419 if (SUCCEEDED(hr))
4421 hr = IServerSecurity_RevertToSelf(pSrvSec);
4422 IServerSecurity_Release(pSrvSec);
4425 return hr;
4428 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4430 /* first try to retrieve messages for incoming COM calls to the apartment window */
4431 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4432 /* next retrieve other messages necessary for the app to remain responsive */
4433 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4434 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4437 /***********************************************************************
4438 * CoWaitForMultipleHandles [OLE32.@]
4440 * Waits for one or more handles to become signaled.
4442 * PARAMS
4443 * dwFlags [I] Flags. See notes.
4444 * dwTimeout [I] Timeout in milliseconds.
4445 * cHandles [I] Number of handles pointed to by pHandles.
4446 * pHandles [I] Handles to wait for.
4447 * lpdwindex [O] Index of handle that was signaled.
4449 * RETURNS
4450 * Success: S_OK.
4451 * Failure: RPC_S_CALLPENDING on timeout.
4453 * NOTES
4455 * The dwFlags parameter can be zero or more of the following:
4456 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4457 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4459 * SEE ALSO
4460 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4462 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4463 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4465 HRESULT hr = S_OK;
4466 DWORD start_time = GetTickCount();
4467 APARTMENT *apt = COM_CurrentApt();
4468 BOOL message_loop = apt && !apt->multi_threaded;
4469 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4471 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4472 pHandles, lpdwindex);
4474 if (!lpdwindex)
4475 return E_INVALIDARG;
4477 *lpdwindex = 0;
4479 if (!pHandles)
4480 return E_INVALIDARG;
4482 if (!cHandles)
4483 return RPC_E_NO_SYNC;
4485 while (TRUE)
4487 DWORD now = GetTickCount();
4488 DWORD res;
4490 if (now - start_time > dwTimeout)
4492 hr = RPC_S_CALLPENDING;
4493 break;
4496 if (message_loop)
4498 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4499 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4501 TRACE("waiting for rpc completion or window message\n");
4503 res = WAIT_TIMEOUT;
4505 if (check_apc)
4507 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4508 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4509 check_apc = FALSE;
4512 if (res == WAIT_TIMEOUT)
4513 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4514 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4515 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4517 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4519 MSG msg;
4520 int count = 0;
4522 /* call message filter */
4524 if (COM_CurrentApt()->filter)
4526 PENDINGTYPE pendingtype =
4527 COM_CurrentInfo()->pending_call_count_server ?
4528 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4529 DWORD be_handled = IMessageFilter_MessagePending(
4530 COM_CurrentApt()->filter, 0 /* FIXME */,
4531 now - start_time, pendingtype);
4532 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4533 switch (be_handled)
4535 case PENDINGMSG_CANCELCALL:
4536 WARN("call canceled\n");
4537 hr = RPC_E_CALL_CANCELED;
4538 break;
4539 case PENDINGMSG_WAITNOPROCESS:
4540 case PENDINGMSG_WAITDEFPROCESS:
4541 default:
4542 /* FIXME: MSDN is very vague about the difference
4543 * between WAITNOPROCESS and WAITDEFPROCESS - there
4544 * appears to be none, so it is possibly a left-over
4545 * from the 16-bit world. */
4546 break;
4550 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4551 * so after processing 100 messages we go back to checking the wait handles */
4552 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4554 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4555 TranslateMessage(&msg);
4556 DispatchMessageW(&msg);
4557 if (msg.message == WM_QUIT)
4559 TRACE("resending WM_QUIT to outer message loop\n");
4560 PostQuitMessage(msg.wParam);
4561 /* no longer need to process messages */
4562 message_loop = FALSE;
4563 break;
4566 continue;
4569 else
4571 TRACE("waiting for rpc completion\n");
4573 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4574 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4575 (dwFlags & COWAIT_ALERTABLE) != 0);
4578 switch (res)
4580 case WAIT_TIMEOUT:
4581 hr = RPC_S_CALLPENDING;
4582 break;
4583 case WAIT_FAILED:
4584 hr = HRESULT_FROM_WIN32( GetLastError() );
4585 break;
4586 default:
4587 *lpdwindex = res;
4588 break;
4590 break;
4592 TRACE("-- 0x%08x\n", hr);
4593 return hr;
4597 /***********************************************************************
4598 * CoGetObject [OLE32.@]
4600 * Gets the object named by converting the name to a moniker and binding to it.
4602 * PARAMS
4603 * pszName [I] String representing the object.
4604 * pBindOptions [I] Parameters affecting the binding to the named object.
4605 * riid [I] Interface to bind to on the objecct.
4606 * ppv [O] On output, the interface riid of the object represented
4607 * by pszName.
4609 * RETURNS
4610 * Success: S_OK.
4611 * Failure: HRESULT code.
4613 * SEE ALSO
4614 * MkParseDisplayName.
4616 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4617 REFIID riid, void **ppv)
4619 IBindCtx *pbc;
4620 HRESULT hr;
4622 *ppv = NULL;
4624 hr = CreateBindCtx(0, &pbc);
4625 if (SUCCEEDED(hr))
4627 if (pBindOptions)
4628 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4630 if (SUCCEEDED(hr))
4632 ULONG chEaten;
4633 IMoniker *pmk;
4635 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4636 if (SUCCEEDED(hr))
4638 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4639 IMoniker_Release(pmk);
4643 IBindCtx_Release(pbc);
4645 return hr;
4648 /***********************************************************************
4649 * CoRegisterChannelHook [OLE32.@]
4651 * Registers a process-wide hook that is called during ORPC calls.
4653 * PARAMS
4654 * guidExtension [I] GUID of the channel hook to register.
4655 * pChannelHook [I] Channel hook object to register.
4657 * RETURNS
4658 * Success: S_OK.
4659 * Failure: HRESULT code.
4661 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4663 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4665 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4668 typedef struct Context
4670 IComThreadingInfo IComThreadingInfo_iface;
4671 IContextCallback IContextCallback_iface;
4672 IObjContext IObjContext_iface;
4673 LONG refs;
4674 } Context;
4676 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4678 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4681 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4683 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4686 static inline Context *impl_from_IObjContext( IObjContext *iface )
4688 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4691 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4693 *ppv = NULL;
4695 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4696 IsEqualIID(riid, &IID_IUnknown))
4698 *ppv = &iface->IComThreadingInfo_iface;
4700 else if (IsEqualIID(riid, &IID_IContextCallback))
4702 *ppv = &iface->IContextCallback_iface;
4704 else if (IsEqualIID(riid, &IID_IObjContext))
4706 *ppv = &iface->IObjContext_iface;
4709 if (*ppv)
4711 IUnknown_AddRef((IUnknown*)*ppv);
4712 return S_OK;
4715 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4716 return E_NOINTERFACE;
4719 static ULONG Context_AddRef(Context *This)
4721 return InterlockedIncrement(&This->refs);
4724 static ULONG Context_Release(Context *This)
4726 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4727 releasing context while refcount is at 0 destroys it. */
4728 if (!This->refs)
4730 HeapFree(GetProcessHeap(), 0, This);
4731 return 0;
4734 return InterlockedDecrement(&This->refs);
4737 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4739 Context *This = impl_from_IComThreadingInfo(iface);
4740 return Context_QueryInterface(This, riid, ppv);
4743 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4745 Context *This = impl_from_IComThreadingInfo(iface);
4746 return Context_AddRef(This);
4749 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4751 Context *This = impl_from_IComThreadingInfo(iface);
4752 return Context_Release(This);
4755 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4757 APTTYPEQUALIFIER qualifier;
4759 TRACE("(%p)\n", apttype);
4761 return CoGetApartmentType(apttype, &qualifier);
4764 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4766 APTTYPEQUALIFIER qualifier;
4767 APTTYPE apttype;
4768 HRESULT hr;
4770 hr = CoGetApartmentType(&apttype, &qualifier);
4771 if (FAILED(hr))
4772 return hr;
4774 TRACE("(%p)\n", thdtype);
4776 switch (apttype)
4778 case APTTYPE_STA:
4779 case APTTYPE_MAINSTA:
4780 *thdtype = THDTYPE_PROCESSMESSAGES;
4781 break;
4782 default:
4783 *thdtype = THDTYPE_BLOCKMESSAGES;
4784 break;
4786 return S_OK;
4789 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4791 TRACE("(%p)\n", logical_thread_id);
4792 return CoGetCurrentLogicalThreadId(logical_thread_id);
4795 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4797 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4798 return E_NOTIMPL;
4801 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4803 Context_CTI_QueryInterface,
4804 Context_CTI_AddRef,
4805 Context_CTI_Release,
4806 Context_CTI_GetCurrentApartmentType,
4807 Context_CTI_GetCurrentThreadType,
4808 Context_CTI_GetCurrentLogicalThreadId,
4809 Context_CTI_SetCurrentLogicalThreadId
4812 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4814 Context *This = impl_from_IContextCallback(iface);
4815 return Context_QueryInterface(This, riid, ppv);
4818 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4820 Context *This = impl_from_IContextCallback(iface);
4821 return Context_AddRef(This);
4824 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4826 Context *This = impl_from_IContextCallback(iface);
4827 return Context_Release(This);
4830 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4831 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4833 Context *This = impl_from_IContextCallback(iface);
4835 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4836 return E_NOTIMPL;
4839 static const IContextCallbackVtbl Context_Callback_Vtbl =
4841 Context_CC_QueryInterface,
4842 Context_CC_AddRef,
4843 Context_CC_Release,
4844 Context_CC_ContextCallback
4847 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4849 Context *This = impl_from_IObjContext(iface);
4850 return Context_QueryInterface(This, riid, ppv);
4853 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4855 Context *This = impl_from_IObjContext(iface);
4856 return Context_AddRef(This);
4859 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4861 Context *This = impl_from_IObjContext(iface);
4862 return Context_Release(This);
4865 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4867 Context *This = impl_from_IObjContext(iface);
4869 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4870 return E_NOTIMPL;
4873 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4875 Context *This = impl_from_IObjContext(iface);
4877 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4878 return E_NOTIMPL;
4881 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4883 Context *This = impl_from_IObjContext(iface);
4885 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4886 return E_NOTIMPL;
4889 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4891 Context *This = impl_from_IObjContext(iface);
4893 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4894 return E_NOTIMPL;
4897 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4899 Context *This = impl_from_IObjContext(iface);
4900 FIXME("(%p/%p)\n", This, iface);
4903 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4905 Context *This = impl_from_IObjContext(iface);
4906 FIXME("(%p/%p)\n", This, iface);
4909 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4911 Context *This = impl_from_IObjContext(iface);
4912 FIXME("(%p/%p)\n", This, iface);
4915 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4917 Context *This = impl_from_IObjContext(iface);
4918 FIXME("(%p/%p)\n", This, iface);
4921 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4923 Context *This = impl_from_IObjContext(iface);
4924 FIXME("(%p/%p)\n", This, iface);
4927 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4929 Context *This = impl_from_IObjContext(iface);
4930 FIXME("(%p/%p)\n", This, iface);
4933 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4935 Context *This = impl_from_IObjContext(iface);
4936 FIXME("(%p/%p)\n", This, iface);
4939 static const IObjContextVtbl Context_Object_Vtbl =
4941 Context_OC_QueryInterface,
4942 Context_OC_AddRef,
4943 Context_OC_Release,
4944 Context_OC_SetProperty,
4945 Context_OC_RemoveProperty,
4946 Context_OC_GetProperty,
4947 Context_OC_EnumContextProps,
4948 Context_OC_Reserved1,
4949 Context_OC_Reserved2,
4950 Context_OC_Reserved3,
4951 Context_OC_Reserved4,
4952 Context_OC_Reserved5,
4953 Context_OC_Reserved6,
4954 Context_OC_Reserved7
4957 /***********************************************************************
4958 * CoGetObjectContext [OLE32.@]
4960 * Retrieves an object associated with the current context (i.e. apartment).
4962 * PARAMS
4963 * riid [I] ID of the interface of the object to retrieve.
4964 * ppv [O] Address where object will be stored on return.
4966 * RETURNS
4967 * Success: S_OK.
4968 * Failure: HRESULT code.
4970 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4972 IObjContext *context;
4973 HRESULT hr;
4975 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4977 *ppv = NULL;
4978 hr = CoGetContextToken((ULONG_PTR*)&context);
4979 if (FAILED(hr))
4980 return hr;
4982 return IObjContext_QueryInterface(context, riid, ppv);
4985 /***********************************************************************
4986 * CoGetContextToken [OLE32.@]
4988 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4990 struct oletls *info = COM_CurrentInfo();
4992 TRACE("(%p)\n", token);
4994 if (!info)
4995 return E_OUTOFMEMORY;
4997 if (!info->apt)
4999 APARTMENT *apt;
5000 if (!(apt = apartment_find_multi_threaded()))
5002 ERR("apartment not initialised\n");
5003 return CO_E_NOTINITIALIZED;
5005 apartment_release(apt);
5008 if (!token)
5009 return E_POINTER;
5011 if (!info->context_token)
5013 Context *context;
5015 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
5016 if (!context)
5017 return E_OUTOFMEMORY;
5019 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
5020 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
5021 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
5022 /* Context token does not take a reference, it's always zero until the
5023 interface is explicitly requested with CoGetObjectContext(). */
5024 context->refs = 0;
5026 info->context_token = &context->IObjContext_iface;
5029 *token = (ULONG_PTR)info->context_token;
5030 TRACE("context_token=%p\n", info->context_token);
5032 return S_OK;
5035 /***********************************************************************
5036 * CoGetDefaultContext [OLE32.@]
5038 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5040 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5041 return E_NOINTERFACE;
5044 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5046 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5047 HKEY hkey;
5048 HRESULT hres;
5050 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5051 if (SUCCEEDED(hres))
5053 struct class_reg_data regdata;
5054 WCHAR dllpath[MAX_PATH+1];
5056 regdata.u.hkey = hkey;
5057 regdata.hkey = TRUE;
5059 if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
5061 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5062 if (!strcmpiW(dllpath, wszOle32))
5064 RegCloseKey(hkey);
5065 return HandlerCF_Create(rclsid, riid, ppv);
5068 else
5069 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5070 RegCloseKey(hkey);
5073 return CLASS_E_CLASSNOTAVAILABLE;
5076 /***********************************************************************
5077 * CoGetApartmentType [OLE32.@]
5079 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5081 struct oletls *info = COM_CurrentInfo();
5083 FIXME("(%p, %p): semi-stub\n", type, qualifier);
5085 if (!type || !qualifier)
5086 return E_INVALIDARG;
5088 if (!info)
5089 return E_OUTOFMEMORY;
5091 if (!info->apt)
5092 *type = APTTYPE_CURRENT;
5093 else if (info->apt->multi_threaded)
5094 *type = APTTYPE_MTA;
5095 else if (info->apt->main)
5096 *type = APTTYPE_MAINSTA;
5097 else
5098 *type = APTTYPE_STA;
5100 *qualifier = APTTYPEQUALIFIER_NONE;
5102 return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5105 /***********************************************************************
5106 * CoRegisterSurrogate [OLE32.@]
5108 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5110 FIXME("(%p): stub\n", surrogate);
5112 return E_NOTIMPL;
5115 /***********************************************************************
5116 * CoRegisterSurrogateEx [OLE32.@]
5118 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5120 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5122 return E_NOTIMPL;
5125 typedef struct {
5126 IGlobalOptions IGlobalOptions_iface;
5127 LONG ref;
5128 } GlobalOptions;
5130 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5132 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5135 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5137 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5139 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5141 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5143 *ppv = iface;
5145 else
5147 *ppv = NULL;
5148 return E_NOINTERFACE;
5151 IUnknown_AddRef((IUnknown*)*ppv);
5152 return S_OK;
5155 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5157 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5158 LONG ref = InterlockedIncrement(&This->ref);
5160 TRACE("(%p) ref=%d\n", This, ref);
5162 return ref;
5165 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5167 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5168 LONG ref = InterlockedDecrement(&This->ref);
5170 TRACE("(%p) ref=%d\n", This, ref);
5172 if (!ref)
5173 heap_free(This);
5175 return ref;
5178 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5180 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5181 FIXME("(%p)->(%u %lx)\n", This, property, value);
5182 return S_OK;
5185 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5187 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5188 FIXME("(%p)->(%u %p)\n", This, property, value);
5189 return E_NOTIMPL;
5192 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5193 GlobalOptions_QueryInterface,
5194 GlobalOptions_AddRef,
5195 GlobalOptions_Release,
5196 GlobalOptions_Set,
5197 GlobalOptions_Query
5200 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5202 GlobalOptions *global_options;
5203 HRESULT hres;
5205 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5207 if (outer)
5208 return E_INVALIDARG;
5210 global_options = heap_alloc(sizeof(*global_options));
5211 if (!global_options)
5212 return E_OUTOFMEMORY;
5213 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5214 global_options->ref = 1;
5216 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5217 IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5218 return hres;
5221 /***********************************************************************
5222 * DllMain (OLE32.@)
5224 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5226 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5228 switch(fdwReason) {
5229 case DLL_PROCESS_ATTACH:
5230 hProxyDll = hinstDLL;
5231 break;
5233 case DLL_PROCESS_DETACH:
5234 if (reserved) break;
5235 release_std_git();
5236 UnregisterClassW( wszAptWinClass, hProxyDll );
5237 RPC_UnregisterAllChannelHooks();
5238 COMPOBJ_DllList_Free();
5239 DeleteCriticalSection(&csRegisteredClassList);
5240 DeleteCriticalSection(&csApartment);
5241 break;
5243 case DLL_THREAD_DETACH:
5244 COM_TlsDestroy();
5245 break;
5247 return TRUE;
5250 /***********************************************************************
5251 * DllRegisterServer (OLE32.@)
5253 HRESULT WINAPI DllRegisterServer(void)
5255 return OLE32_DllRegisterServer();
5258 /***********************************************************************
5259 * DllUnregisterServer (OLE32.@)
5261 HRESULT WINAPI DllUnregisterServer(void)
5263 return OLE32_DllUnregisterServer();