mshtml: Store event target as EventTarget in HTMLEventObj.
[wine.git] / dlls / ole32 / compobj.c
blob6fb07bf2baf28db76fc7385b3eb7578d6fd604aa
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 void apartment_joinmta(void)
1729 apartment_addref(MTA);
1730 COM_CurrentInfo()->apt = MTA;
1733 static void COM_TlsDestroy(void)
1735 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1736 if (info)
1738 if (info->apt) apartment_release(info->apt);
1739 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1740 if (info->state) IUnknown_Release(info->state);
1741 if (info->spy) IInitializeSpy_Release(info->spy);
1742 if (info->context_token) IObjContext_Release(info->context_token);
1743 HeapFree(GetProcessHeap(), 0, info);
1744 NtCurrentTeb()->ReservedForOle = NULL;
1748 /******************************************************************************
1749 * CoBuildVersion [OLE32.@]
1751 * Gets the build version of the DLL.
1753 * PARAMS
1755 * RETURNS
1756 * Current build version, hiword is majornumber, loword is minornumber
1758 DWORD WINAPI CoBuildVersion(void)
1760 TRACE("Returning version %d, build %d.\n", rmm, rup);
1761 return (rmm<<16)+rup;
1764 /******************************************************************************
1765 * CoRegisterInitializeSpy [OLE32.@]
1767 * Add a Spy that watches CoInitializeEx calls
1769 * PARAMS
1770 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1771 * cookie [II] cookie receiver
1773 * RETURNS
1774 * Success: S_OK if not already initialized, S_FALSE otherwise.
1775 * Failure: HRESULT code.
1777 * SEE ALSO
1778 * CoInitializeEx
1780 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1782 struct oletls *info = COM_CurrentInfo();
1783 HRESULT hr;
1785 TRACE("(%p, %p)\n", spy, cookie);
1787 if (!spy || !cookie || !info)
1789 if (!info)
1790 WARN("Could not allocate tls\n");
1791 return E_INVALIDARG;
1794 if (info->spy)
1796 FIXME("Already registered?\n");
1797 return E_UNEXPECTED;
1800 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1801 if (SUCCEEDED(hr))
1803 cookie->QuadPart = (DWORD_PTR)spy;
1804 return S_OK;
1806 return hr;
1809 /******************************************************************************
1810 * CoRevokeInitializeSpy [OLE32.@]
1812 * Remove a spy that previously watched CoInitializeEx calls
1814 * PARAMS
1815 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1817 * RETURNS
1818 * Success: S_OK if a spy is removed
1819 * Failure: E_INVALIDARG
1821 * SEE ALSO
1822 * CoInitializeEx
1824 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1826 struct oletls *info = COM_CurrentInfo();
1827 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1829 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1830 return E_INVALIDARG;
1832 IInitializeSpy_Release(info->spy);
1833 info->spy = NULL;
1834 return S_OK;
1838 /******************************************************************************
1839 * CoInitialize [OLE32.@]
1841 * Initializes the COM libraries by calling CoInitializeEx with
1842 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1844 * PARAMS
1845 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1847 * RETURNS
1848 * Success: S_OK if not already initialized, S_FALSE otherwise.
1849 * Failure: HRESULT code.
1851 * SEE ALSO
1852 * CoInitializeEx
1854 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1857 * Just delegate to the newer method.
1859 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1862 /******************************************************************************
1863 * CoInitializeEx [OLE32.@]
1865 * Initializes the COM libraries.
1867 * PARAMS
1868 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1869 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1871 * RETURNS
1872 * S_OK if successful,
1873 * S_FALSE if this function was called already.
1874 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1875 * threading model.
1877 * NOTES
1879 * The behavior used to set the IMalloc used for memory management is
1880 * obsolete.
1881 * The dwCoInit parameter must specify one of the following apartment
1882 * threading models:
1883 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1884 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1885 * The parameter may also specify zero or more of the following flags:
1886 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1887 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1889 * SEE ALSO
1890 * CoUninitialize
1892 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1894 struct oletls *info = COM_CurrentInfo();
1895 HRESULT hr = S_OK;
1896 APARTMENT *apt;
1898 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1900 if (lpReserved!=NULL)
1902 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1906 * Check the lock count. If this is the first time going through the initialize
1907 * process, we have to initialize the libraries.
1909 * And crank-up that lock count.
1911 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1914 * Initialize the various COM libraries and data structures.
1916 TRACE("() - Initializing the COM libraries\n");
1918 /* we may need to defer this until after apartment initialisation */
1919 RunningObjectTableImpl_Initialize();
1922 if (info->spy)
1923 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1925 if (!(apt = info->apt))
1927 apt = apartment_get_or_create(dwCoInit);
1928 if (!apt) return E_OUTOFMEMORY;
1930 else if (!apartment_is_model(apt, dwCoInit))
1932 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1933 code then we are probably using the wrong threading model to implement that API. */
1934 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1935 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1936 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1937 return RPC_E_CHANGED_MODE;
1939 else
1940 hr = S_FALSE;
1942 info->inits++;
1944 if (info->spy)
1945 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1947 return hr;
1950 /***********************************************************************
1951 * CoUninitialize [OLE32.@]
1953 * This method will decrement the refcount on the current apartment, freeing
1954 * the resources associated with it if it is the last thread in the apartment.
1955 * If the last apartment is freed, the function will additionally release
1956 * any COM resources associated with the process.
1958 * PARAMS
1960 * RETURNS
1961 * Nothing.
1963 * SEE ALSO
1964 * CoInitializeEx
1966 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
1968 struct oletls * info = COM_CurrentInfo();
1969 LONG lCOMRefCnt;
1971 TRACE("()\n");
1973 /* will only happen on OOM */
1974 if (!info) return;
1976 if (info->spy)
1977 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1979 /* sanity check */
1980 if (!info->inits)
1982 ERR("Mismatched CoUninitialize\n");
1984 if (info->spy)
1985 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1986 return;
1989 if (!--info->inits)
1991 if (info->ole_inits)
1992 WARN("uninitializing apartment while Ole is still initialized\n");
1993 apartment_release(info->apt);
1994 info->apt = NULL;
1998 * Decrease the reference count.
1999 * If we are back to 0 locks on the COM library, make sure we free
2000 * all the associated data structures.
2002 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
2003 if (lCOMRefCnt==1)
2005 TRACE("() - Releasing the COM libraries\n");
2007 revoke_registered_psclsids();
2008 RunningObjectTableImpl_UnInitialize();
2010 else if (lCOMRefCnt<1) {
2011 ERR( "CoUninitialize() - not CoInitialized.\n" );
2012 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
2014 if (info->spy)
2015 IInitializeSpy_PostUninitialize(info->spy, info->inits);
2018 /******************************************************************************
2019 * CoDisconnectObject [OLE32.@]
2021 * Disconnects all connections to this object from remote processes. Dispatches
2022 * pending RPCs while blocking new RPCs from occurring, and then calls
2023 * IMarshal::DisconnectObject on the given object.
2025 * Typically called when the object server is forced to shut down, for instance by
2026 * the user.
2028 * PARAMS
2029 * lpUnk [I] The object whose stub should be disconnected.
2030 * reserved [I] Reserved. Should be set to 0.
2032 * RETURNS
2033 * Success: S_OK.
2034 * Failure: HRESULT code.
2036 * SEE ALSO
2037 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2039 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2041 struct stub_manager *manager;
2042 HRESULT hr;
2043 IMarshal *marshal;
2044 APARTMENT *apt;
2046 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2048 if (!lpUnk) return E_INVALIDARG;
2050 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2051 if (hr == S_OK)
2053 hr = IMarshal_DisconnectObject(marshal, reserved);
2054 IMarshal_Release(marshal);
2055 return hr;
2058 apt = COM_CurrentApt();
2059 if (!apt)
2060 return CO_E_NOTINITIALIZED;
2062 manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2063 if (manager) {
2064 stub_manager_disconnect(manager);
2065 /* Release stub manager twice, to remove the apartment reference. */
2066 stub_manager_int_release(manager);
2067 stub_manager_int_release(manager);
2070 /* Note: native is pretty broken here because it just silently
2071 * fails, without returning an appropriate error code if the object was
2072 * not found, making apps think that the object was disconnected, when
2073 * it actually wasn't */
2075 return S_OK;
2078 /******************************************************************************
2079 * CoCreateGuid [OLE32.@]
2081 * Simply forwards to UuidCreate in RPCRT4.
2083 * PARAMS
2084 * pguid [O] Points to the GUID to initialize.
2086 * RETURNS
2087 * Success: S_OK.
2088 * Failure: HRESULT code.
2090 * SEE ALSO
2091 * UuidCreate
2093 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2095 DWORD status;
2097 if(!pguid) return E_INVALIDARG;
2099 status = UuidCreate(pguid);
2100 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2101 return HRESULT_FROM_WIN32( status );
2104 static inline BOOL is_valid_hex(WCHAR c)
2106 if (!(((c >= '0') && (c <= '9')) ||
2107 ((c >= 'a') && (c <= 'f')) ||
2108 ((c >= 'A') && (c <= 'F'))))
2109 return FALSE;
2110 return TRUE;
2113 static const BYTE guid_conv_table[256] =
2115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2118 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2119 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2121 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2124 /* conversion helper for CLSIDFromString/IIDFromString */
2125 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2127 int i;
2129 if (!s || s[0]!='{') {
2130 memset( id, 0, sizeof (CLSID) );
2131 if(!s) return TRUE;
2132 return FALSE;
2135 TRACE("%s -> %p\n", debugstr_w(s), id);
2137 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2139 id->Data1 = 0;
2140 for (i = 1; i < 9; i++) {
2141 if (!is_valid_hex(s[i])) return FALSE;
2142 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2144 if (s[9]!='-') return FALSE;
2146 id->Data2 = 0;
2147 for (i = 10; i < 14; i++) {
2148 if (!is_valid_hex(s[i])) return FALSE;
2149 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2151 if (s[14]!='-') return FALSE;
2153 id->Data3 = 0;
2154 for (i = 15; i < 19; i++) {
2155 if (!is_valid_hex(s[i])) return FALSE;
2156 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2158 if (s[19]!='-') return FALSE;
2160 for (i = 20; i < 37; i+=2) {
2161 if (i == 24) {
2162 if (s[i]!='-') return FALSE;
2163 i++;
2165 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2166 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2169 if (s[37] == '}' && s[38] == '\0')
2170 return TRUE;
2172 return FALSE;
2175 /*****************************************************************************/
2177 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2179 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2180 WCHAR buf2[CHARS_IN_GUID];
2181 LONG buf2len = sizeof(buf2);
2182 HKEY xhkey;
2183 WCHAR *buf;
2185 memset(clsid, 0, sizeof(*clsid));
2186 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2187 if (!buf) return E_OUTOFMEMORY;
2188 strcpyW( buf, progid );
2189 strcatW( buf, clsidW );
2190 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2192 HeapFree(GetProcessHeap(),0,buf);
2193 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2194 return CO_E_CLASSSTRING;
2196 HeapFree(GetProcessHeap(),0,buf);
2198 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2200 RegCloseKey(xhkey);
2201 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2202 return CO_E_CLASSSTRING;
2204 RegCloseKey(xhkey);
2205 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2208 /******************************************************************************
2209 * CLSIDFromString [OLE32.@]
2211 * Converts a unique identifier from its string representation into
2212 * the GUID struct.
2214 * PARAMS
2215 * idstr [I] The string representation of the GUID.
2216 * id [O] GUID converted from the string.
2218 * RETURNS
2219 * S_OK on success
2220 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2222 * SEE ALSO
2223 * StringFromCLSID
2225 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2227 HRESULT ret = CO_E_CLASSSTRING;
2228 CLSID tmp_id;
2230 if (!id)
2231 return E_INVALIDARG;
2233 if (guid_from_string(idstr, id))
2234 return S_OK;
2236 /* It appears a ProgID is also valid */
2237 ret = clsid_from_string_reg(idstr, &tmp_id);
2238 if(SUCCEEDED(ret))
2239 *id = tmp_id;
2241 return ret;
2244 /******************************************************************************
2245 * IIDFromString [OLE32.@]
2247 * Converts an interface identifier from its string representation to
2248 * the IID struct.
2250 * PARAMS
2251 * idstr [I] The string representation of the GUID.
2252 * id [O] IID converted from the string.
2254 * RETURNS
2255 * S_OK on success
2256 * CO_E_IIDSTRING if idstr is not a valid IID
2258 * SEE ALSO
2259 * StringFromIID
2261 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2263 TRACE("%s -> %p\n", debugstr_w(s), iid);
2265 if (!s)
2267 memset(iid, 0, sizeof(*iid));
2268 return S_OK;
2271 /* length mismatch is a special case */
2272 if (strlenW(s) + 1 != CHARS_IN_GUID)
2273 return E_INVALIDARG;
2275 if (s[0] != '{')
2276 return CO_E_IIDSTRING;
2278 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2281 /******************************************************************************
2282 * StringFromCLSID [OLE32.@]
2283 * StringFromIID [OLE32.@]
2285 * Converts a GUID into the respective string representation.
2286 * The target string is allocated using the OLE IMalloc.
2288 * PARAMS
2289 * id [I] the GUID to be converted.
2290 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2292 * RETURNS
2293 * S_OK
2294 * E_FAIL
2296 * SEE ALSO
2297 * StringFromGUID2, CLSIDFromString
2299 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2301 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2302 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2303 return S_OK;
2306 /******************************************************************************
2307 * StringFromGUID2 [OLE32.@]
2309 * Modified version of StringFromCLSID that allows you to specify max
2310 * buffer size.
2312 * PARAMS
2313 * id [I] GUID to convert to string.
2314 * str [O] Buffer where the result will be stored.
2315 * cmax [I] Size of the buffer in characters.
2317 * RETURNS
2318 * Success: The length of the resulting string in characters.
2319 * Failure: 0.
2321 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2323 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2324 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2325 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2326 '%','0','2','X','%','0','2','X','}',0 };
2327 if (!id || cmax < CHARS_IN_GUID) return 0;
2328 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2329 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2330 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2331 return CHARS_IN_GUID;
2334 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2335 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2337 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2338 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2339 LONG res;
2340 HKEY key;
2342 strcpyW(path, wszCLSIDSlash);
2343 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2344 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2345 if (res == ERROR_FILE_NOT_FOUND)
2346 return REGDB_E_CLASSNOTREG;
2347 else if (res != ERROR_SUCCESS)
2348 return REGDB_E_READREGDB;
2350 if (!keyname)
2352 *subkey = key;
2353 return S_OK;
2356 res = open_classes_key(key, keyname, access, subkey);
2357 RegCloseKey(key);
2358 if (res == ERROR_FILE_NOT_FOUND)
2359 return REGDB_E_KEYMISSING;
2360 else if (res != ERROR_SUCCESS)
2361 return REGDB_E_READREGDB;
2363 return S_OK;
2366 /* open HKCR\\AppId\\{string form of appid clsid} key */
2367 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2369 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2370 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2371 DWORD res;
2372 WCHAR buf[CHARS_IN_GUID];
2373 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2374 DWORD size;
2375 HKEY hkey;
2376 DWORD type;
2377 HRESULT hr;
2379 /* read the AppID value under the class's key */
2380 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2381 if (FAILED(hr))
2382 return hr;
2384 size = sizeof(buf);
2385 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2386 RegCloseKey(hkey);
2387 if (res == ERROR_FILE_NOT_FOUND)
2388 return REGDB_E_KEYMISSING;
2389 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2390 return REGDB_E_READREGDB;
2392 strcpyW(keyname, szAppIdKey);
2393 strcatW(keyname, buf);
2394 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2395 if (res == ERROR_FILE_NOT_FOUND)
2396 return REGDB_E_KEYMISSING;
2397 else if (res != ERROR_SUCCESS)
2398 return REGDB_E_READREGDB;
2400 return S_OK;
2403 /******************************************************************************
2404 * ProgIDFromCLSID [OLE32.@]
2406 * Converts a class id into the respective program ID.
2408 * PARAMS
2409 * clsid [I] Class ID, as found in registry.
2410 * ppszProgID [O] Associated ProgID.
2412 * RETURNS
2413 * S_OK
2414 * E_OUTOFMEMORY
2415 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2417 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2419 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2420 ACTCTX_SECTION_KEYED_DATA data;
2421 HKEY hkey;
2422 HRESULT ret;
2423 LONG progidlen = 0;
2425 if (!ppszProgID)
2426 return E_INVALIDARG;
2428 *ppszProgID = NULL;
2430 data.cbSize = sizeof(data);
2431 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2432 clsid, &data))
2434 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2435 if (comclass->progid_len)
2437 WCHAR *ptrW;
2439 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2440 if (!*ppszProgID) return E_OUTOFMEMORY;
2442 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2443 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2444 return S_OK;
2446 else
2447 return REGDB_E_CLASSNOTREG;
2450 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2451 if (FAILED(ret))
2452 return ret;
2454 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2455 ret = REGDB_E_CLASSNOTREG;
2457 if (ret == S_OK)
2459 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2460 if (*ppszProgID)
2462 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2463 ret = REGDB_E_CLASSNOTREG;
2464 CoTaskMemFree(*ppszProgID);
2465 *ppszProgID = NULL;
2468 else
2469 ret = E_OUTOFMEMORY;
2472 RegCloseKey(hkey);
2473 return ret;
2476 /******************************************************************************
2477 * CLSIDFromProgID [OLE32.@]
2479 * Converts a program id into the respective GUID.
2481 * PARAMS
2482 * progid [I] Unicode program ID, as found in registry.
2483 * clsid [O] Associated CLSID.
2485 * RETURNS
2486 * Success: S_OK
2487 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2489 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2491 ACTCTX_SECTION_KEYED_DATA data;
2493 if (!progid || !clsid)
2494 return E_INVALIDARG;
2496 data.cbSize = sizeof(data);
2497 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2498 progid, &data))
2500 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2501 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2502 *clsid = *alias;
2503 return S_OK;
2506 return clsid_from_string_reg(progid, clsid);
2509 /******************************************************************************
2510 * CLSIDFromProgIDEx [OLE32.@]
2512 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2514 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2516 return CLSIDFromProgID(progid, clsid);
2519 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2521 HKEY hkey;
2522 WCHAR value[CHARS_IN_GUID];
2523 DWORD len;
2525 access |= KEY_READ;
2527 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2528 return REGDB_E_IIDNOTREG;
2530 len = sizeof(value);
2531 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2532 return REGDB_E_IIDNOTREG;
2533 RegCloseKey(hkey);
2535 if (CLSIDFromString(value, pclsid) != NOERROR)
2536 return REGDB_E_IIDNOTREG;
2538 return S_OK;
2541 /*****************************************************************************
2542 * CoGetPSClsid [OLE32.@]
2544 * Retrieves the CLSID of the proxy/stub factory that implements
2545 * IPSFactoryBuffer for the specified interface.
2547 * PARAMS
2548 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2549 * pclsid [O] Where to store returned proxy/stub CLSID.
2551 * RETURNS
2552 * S_OK
2553 * E_OUTOFMEMORY
2554 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2556 * NOTES
2558 * The standard marshaller activates the object with the CLSID
2559 * returned and uses the CreateProxy and CreateStub methods on its
2560 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2561 * given object.
2563 * CoGetPSClsid determines this CLSID by searching the
2564 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2565 * in the registry and any interface id registered by
2566 * CoRegisterPSClsid within the current process.
2568 * BUGS
2570 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2571 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2572 * considered a bug in native unless an application depends on this (unlikely).
2574 * SEE ALSO
2575 * CoRegisterPSClsid.
2577 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2579 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2580 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2581 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2582 APARTMENT *apt = COM_CurrentApt();
2583 struct registered_psclsid *registered_psclsid;
2584 ACTCTX_SECTION_KEYED_DATA data;
2585 HRESULT hr;
2586 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2587 BOOL is_wow64;
2589 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2591 if (!apt)
2593 ERR("apartment not initialised\n");
2594 return CO_E_NOTINITIALIZED;
2597 if (!pclsid)
2598 return E_INVALIDARG;
2600 EnterCriticalSection(&cs_registered_psclsid_list);
2602 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2603 if (IsEqualIID(&registered_psclsid->iid, riid))
2605 *pclsid = registered_psclsid->clsid;
2606 LeaveCriticalSection(&cs_registered_psclsid_list);
2607 return S_OK;
2610 LeaveCriticalSection(&cs_registered_psclsid_list);
2612 data.cbSize = sizeof(data);
2613 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2614 riid, &data))
2616 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2617 *pclsid = ifaceps->iid;
2618 return S_OK;
2621 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2622 strcpyW(path, wszInterface);
2623 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2624 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2626 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2627 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2628 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2629 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2631 if (hr == S_OK)
2632 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2633 else
2634 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2636 return hr;
2639 /*****************************************************************************
2640 * CoRegisterPSClsid [OLE32.@]
2642 * Register a proxy/stub CLSID for the given interface in the current process
2643 * only.
2645 * PARAMS
2646 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2647 * rclsid [I] CLSID of the proxy/stub.
2649 * RETURNS
2650 * Success: S_OK
2651 * Failure: E_OUTOFMEMORY
2653 * NOTES
2655 * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2656 * will be returned from other apartments in the same process.
2658 * This function does not add anything to the registry and the effects are
2659 * limited to the lifetime of the current process.
2661 * SEE ALSO
2662 * CoGetPSClsid.
2664 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2666 APARTMENT *apt = COM_CurrentApt();
2667 struct registered_psclsid *registered_psclsid;
2669 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2671 if (!apt)
2673 ERR("apartment not initialised\n");
2674 return CO_E_NOTINITIALIZED;
2677 EnterCriticalSection(&cs_registered_psclsid_list);
2679 LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2680 if (IsEqualIID(&registered_psclsid->iid, riid))
2682 registered_psclsid->clsid = *rclsid;
2683 LeaveCriticalSection(&cs_registered_psclsid_list);
2684 return S_OK;
2687 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2688 if (!registered_psclsid)
2690 LeaveCriticalSection(&cs_registered_psclsid_list);
2691 return E_OUTOFMEMORY;
2694 registered_psclsid->iid = *riid;
2695 registered_psclsid->clsid = *rclsid;
2696 list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2698 LeaveCriticalSection(&cs_registered_psclsid_list);
2700 return S_OK;
2704 /***
2705 * COM_GetRegisteredClassObject
2707 * This internal method is used to scan the registered class list to
2708 * find a class object.
2710 * Params:
2711 * rclsid Class ID of the class to find.
2712 * dwClsContext Class context to match.
2713 * ppv [out] returns a pointer to the class object. Complying
2714 * to normal COM usage, this method will increase the
2715 * reference count on this object.
2717 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2718 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2720 HRESULT hr = S_FALSE;
2721 RegisteredClass *curClass;
2723 EnterCriticalSection( &csRegisteredClassList );
2725 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2728 * Check if we have a match on the class ID and context.
2730 if ((apt->oxid == curClass->apartment_id) &&
2731 (dwClsContext & curClass->runContext) &&
2732 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2735 * We have a match, return the pointer to the class object.
2737 *ppUnk = curClass->classObject;
2739 IUnknown_AddRef(curClass->classObject);
2741 hr = S_OK;
2742 break;
2746 LeaveCriticalSection( &csRegisteredClassList );
2748 return hr;
2751 /******************************************************************************
2752 * CoRegisterClassObject [OLE32.@]
2754 * Registers the class object for a given class ID. Servers housed in EXE
2755 * files use this method instead of exporting DllGetClassObject to allow
2756 * other code to connect to their objects.
2758 * PARAMS
2759 * rclsid [I] CLSID of the object to register.
2760 * pUnk [I] IUnknown of the object.
2761 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2762 * flags [I] REGCLS flags indicating how connections are made.
2763 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2765 * RETURNS
2766 * S_OK on success,
2767 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2768 * CO_E_OBJISREG if the object is already registered. We should not return this.
2770 * SEE ALSO
2771 * CoRevokeClassObject, CoGetClassObject
2773 * NOTES
2774 * In-process objects are only registered for the current apartment.
2775 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2776 * in other apartments.
2778 * BUGS
2779 * MSDN claims that multiple interface registrations are legal, but we
2780 * can't do that with our current implementation.
2782 HRESULT WINAPI CoRegisterClassObject(
2783 REFCLSID rclsid,
2784 LPUNKNOWN pUnk,
2785 DWORD dwClsContext,
2786 DWORD flags,
2787 LPDWORD lpdwRegister)
2789 static LONG next_cookie;
2790 RegisteredClass* newClass;
2791 LPUNKNOWN foundObject;
2792 HRESULT hr;
2793 APARTMENT *apt;
2795 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2796 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2798 if ( (lpdwRegister==0) || (pUnk==0) )
2799 return E_INVALIDARG;
2801 apt = COM_CurrentApt();
2802 if (!apt)
2804 ERR("COM was not initialized\n");
2805 return CO_E_NOTINITIALIZED;
2808 *lpdwRegister = 0;
2810 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2811 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2812 if (flags & REGCLS_MULTIPLEUSE)
2813 dwClsContext |= CLSCTX_INPROC_SERVER;
2816 * First, check if the class is already registered.
2817 * If it is, this should cause an error.
2819 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2820 if (hr == S_OK) {
2821 if (flags & REGCLS_MULTIPLEUSE) {
2822 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2823 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2824 IUnknown_Release(foundObject);
2825 return hr;
2827 IUnknown_Release(foundObject);
2828 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2829 return CO_E_OBJISREG;
2832 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2833 if ( newClass == NULL )
2834 return E_OUTOFMEMORY;
2836 newClass->classIdentifier = *rclsid;
2837 newClass->apartment_id = apt->oxid;
2838 newClass->runContext = dwClsContext;
2839 newClass->connectFlags = flags;
2840 newClass->RpcRegistration = NULL;
2842 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2843 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2846 * Since we're making a copy of the object pointer, we have to increase its
2847 * reference count.
2849 newClass->classObject = pUnk;
2850 IUnknown_AddRef(newClass->classObject);
2852 EnterCriticalSection( &csRegisteredClassList );
2853 list_add_tail(&RegisteredClassList, &newClass->entry);
2854 LeaveCriticalSection( &csRegisteredClassList );
2856 *lpdwRegister = newClass->dwCookie;
2858 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2859 IStream *marshal_stream;
2861 hr = get_local_server_stream(apt, &marshal_stream);
2862 if(FAILED(hr))
2863 return hr;
2865 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2866 marshal_stream,
2867 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2868 &newClass->RpcRegistration);
2869 IStream_Release(marshal_stream);
2871 return S_OK;
2874 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2876 if (data->hkey)
2878 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2879 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2880 static const WCHAR wszFree[] = {'F','r','e','e',0};
2881 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2882 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2883 DWORD dwLength = sizeof(threading_model);
2884 DWORD keytype;
2885 DWORD ret;
2887 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2888 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2889 threading_model[0] = '\0';
2891 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2892 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2893 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2895 /* there's not specific handling for this case */
2896 if (threading_model[0]) return ThreadingModel_Neutral;
2897 return ThreadingModel_No;
2899 else
2900 return data->u.actctx.data->model;
2903 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2904 REFCLSID rclsid, REFIID riid,
2905 BOOL hostifnecessary, void **ppv)
2907 WCHAR dllpath[MAX_PATH+1];
2908 BOOL apartment_threaded;
2910 if (hostifnecessary)
2912 enum comclass_threadingmodel model = get_threading_model(regdata);
2914 if (model == ThreadingModel_Apartment)
2916 apartment_threaded = TRUE;
2917 if (apt->multi_threaded)
2918 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2920 else if (model == ThreadingModel_Free)
2922 apartment_threaded = FALSE;
2923 if (!apt->multi_threaded)
2924 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2926 /* everything except "Apartment", "Free" and "Both" */
2927 else if (model != ThreadingModel_Both)
2929 apartment_threaded = TRUE;
2930 /* everything else is main-threaded */
2931 if (model != ThreadingModel_No)
2932 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2934 if (apt->multi_threaded || !apt->main)
2935 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2937 else
2938 apartment_threaded = FALSE;
2940 else
2941 apartment_threaded = !apt->multi_threaded;
2943 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2945 /* failure: CLSID is not found in registry */
2946 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2947 return REGDB_E_CLASSNOTREG;
2950 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2951 rclsid, riid, ppv);
2954 /***********************************************************************
2955 * CoGetClassObject [OLE32.@]
2957 * Creates an object of the specified class.
2959 * PARAMS
2960 * rclsid [I] Class ID to create an instance of.
2961 * dwClsContext [I] Flags to restrict the location of the created instance.
2962 * pServerInfo [I] Optional. Details for connecting to a remote server.
2963 * iid [I] The ID of the interface of the instance to return.
2964 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2966 * RETURNS
2967 * Success: S_OK
2968 * Failure: HRESULT code.
2970 * NOTES
2971 * The dwClsContext parameter can be one or more of the following:
2972 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2973 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2974 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2975 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2977 * SEE ALSO
2978 * CoCreateInstance()
2980 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2981 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2982 REFIID iid, LPVOID *ppv)
2984 struct class_reg_data clsreg;
2985 IUnknown *regClassObject;
2986 HRESULT hres = E_UNEXPECTED;
2987 APARTMENT *apt;
2988 BOOL release_apt = FALSE;
2990 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2992 if (!ppv)
2993 return E_INVALIDARG;
2995 *ppv = NULL;
2997 if (!(apt = COM_CurrentApt()))
2999 if (!(apt = apartment_find_multi_threaded()))
3001 ERR("apartment not initialised\n");
3002 return CO_E_NOTINITIALIZED;
3004 release_apt = TRUE;
3007 if (pServerInfo) {
3008 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
3009 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
3012 if (CLSCTX_INPROC_SERVER & dwClsContext)
3014 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
3016 if (release_apt) apartment_release(apt);
3017 return FTMarshalCF_Create(iid, ppv);
3019 if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3020 return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3023 if (CLSCTX_INPROC & dwClsContext)
3025 ACTCTX_SECTION_KEYED_DATA data;
3027 data.cbSize = sizeof(data);
3028 /* search activation context first */
3029 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3030 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3031 rclsid, &data))
3033 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3035 clsreg.u.actctx.hactctx = data.hActCtx;
3036 clsreg.u.actctx.data = data.lpData;
3037 clsreg.u.actctx.section = data.lpSectionBase;
3038 clsreg.hkey = FALSE;
3040 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3041 ReleaseActCtx(data.hActCtx);
3042 if (release_apt) apartment_release(apt);
3043 return hres;
3048 * First, try and see if we can't match the class ID with one of the
3049 * registered classes.
3051 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3052 &regClassObject))
3054 /* Get the required interface from the retrieved pointer. */
3055 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3058 * Since QI got another reference on the pointer, we want to release the
3059 * one we already have. If QI was unsuccessful, this will release the object. This
3060 * is good since we are not returning it in the "out" parameter.
3062 IUnknown_Release(regClassObject);
3063 if (release_apt) apartment_release(apt);
3064 return hres;
3067 /* First try in-process server */
3068 if (CLSCTX_INPROC_SERVER & dwClsContext)
3070 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3071 HKEY hkey;
3073 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3074 if (FAILED(hres))
3076 if (hres == REGDB_E_CLASSNOTREG)
3077 ERR("class %s not registered\n", debugstr_guid(rclsid));
3078 else if (hres == REGDB_E_KEYMISSING)
3080 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3081 hres = REGDB_E_CLASSNOTREG;
3085 if (SUCCEEDED(hres))
3087 clsreg.u.hkey = hkey;
3088 clsreg.hkey = TRUE;
3090 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3091 RegCloseKey(hkey);
3094 /* return if we got a class, otherwise fall through to one of the
3095 * other types */
3096 if (SUCCEEDED(hres))
3098 if (release_apt) apartment_release(apt);
3099 return hres;
3103 /* Next try in-process handler */
3104 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3106 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3107 HKEY hkey;
3109 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3110 if (FAILED(hres))
3112 if (hres == REGDB_E_CLASSNOTREG)
3113 ERR("class %s not registered\n", debugstr_guid(rclsid));
3114 else if (hres == REGDB_E_KEYMISSING)
3116 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3117 hres = REGDB_E_CLASSNOTREG;
3121 if (SUCCEEDED(hres))
3123 clsreg.u.hkey = hkey;
3124 clsreg.hkey = TRUE;
3126 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3127 RegCloseKey(hkey);
3130 /* return if we got a class, otherwise fall through to one of the
3131 * other types */
3132 if (SUCCEEDED(hres))
3134 if (release_apt) apartment_release(apt);
3135 return hres;
3138 if (release_apt) apartment_release(apt);
3140 /* Next try out of process */
3141 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3143 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3144 if (SUCCEEDED(hres))
3145 return hres;
3148 /* Finally try remote: this requires networked DCOM (a lot of work) */
3149 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3151 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3152 hres = REGDB_E_CLASSNOTREG;
3155 if (FAILED(hres))
3156 ERR("no class object %s could be created for context 0x%x\n",
3157 debugstr_guid(rclsid), dwClsContext);
3158 return hres;
3161 /***********************************************************************
3162 * CoResumeClassObjects (OLE32.@)
3164 * Resumes all class objects registered with REGCLS_SUSPENDED.
3166 * RETURNS
3167 * Success: S_OK.
3168 * Failure: HRESULT code.
3170 HRESULT WINAPI CoResumeClassObjects(void)
3172 FIXME("stub\n");
3173 return S_OK;
3176 /***********************************************************************
3177 * CoCreateInstance [OLE32.@]
3179 * Creates an instance of the specified class.
3181 * PARAMS
3182 * rclsid [I] Class ID to create an instance of.
3183 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3184 * dwClsContext [I] Flags to restrict the location of the created instance.
3185 * iid [I] The ID of the interface of the instance to return.
3186 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3188 * RETURNS
3189 * Success: S_OK
3190 * Failure: HRESULT code.
3192 * NOTES
3193 * The dwClsContext parameter can be one or more of the following:
3194 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3195 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3196 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3197 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3199 * Aggregation is the concept of deferring the IUnknown of an object to another
3200 * object. This allows a separate object to behave as though it was part of
3201 * the object and to allow this the pUnkOuter parameter can be set. Note that
3202 * not all objects support having an outer of unknown.
3204 * SEE ALSO
3205 * CoGetClassObject()
3207 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3208 REFCLSID rclsid,
3209 LPUNKNOWN pUnkOuter,
3210 DWORD dwClsContext,
3211 REFIID iid,
3212 LPVOID *ppv)
3214 MULTI_QI multi_qi = { iid };
3215 HRESULT hres;
3217 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3218 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3220 if (ppv==0)
3221 return E_POINTER;
3223 hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3224 *ppv = multi_qi.pItf;
3225 return hres;
3228 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3230 ULONG i;
3232 for (i = 0; i < count; i++)
3234 mqi[i].pItf = NULL;
3235 mqi[i].hr = hr;
3239 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3241 ULONG index = 0, fetched = 0;
3243 if (include_unk)
3245 mqi[0].hr = S_OK;
3246 mqi[0].pItf = unk;
3247 index = fetched = 1;
3250 for (; index < count; index++)
3252 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3253 if (mqi[index].hr == S_OK)
3254 fetched++;
3257 if (!include_unk)
3258 IUnknown_Release(unk);
3260 if (fetched == 0)
3261 return E_NOINTERFACE;
3263 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3266 /***********************************************************************
3267 * CoCreateInstanceEx [OLE32.@]
3269 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3270 REFCLSID rclsid,
3271 LPUNKNOWN pUnkOuter,
3272 DWORD dwClsContext,
3273 COSERVERINFO* pServerInfo,
3274 ULONG cmq,
3275 MULTI_QI* pResults)
3277 IUnknown *unk = NULL;
3278 IClassFactory *cf;
3279 APARTMENT *apt;
3280 CLSID clsid;
3281 HRESULT hres;
3283 TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3285 if (!cmq || !pResults)
3286 return E_INVALIDARG;
3288 if (pServerInfo)
3289 FIXME("() non-NULL pServerInfo not supported!\n");
3291 init_multi_qi(cmq, pResults, E_NOINTERFACE);
3293 hres = CoGetTreatAsClass(rclsid, &clsid);
3294 if(FAILED(hres))
3295 clsid = *rclsid;
3297 if (!(apt = COM_CurrentApt()))
3299 if (!(apt = apartment_find_multi_threaded()))
3301 ERR("apartment not initialised\n");
3302 return CO_E_NOTINITIALIZED;
3304 apartment_release(apt);
3308 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3310 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3312 IGlobalInterfaceTable *git = get_std_git();
3313 TRACE("Retrieving GIT\n");
3314 return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3317 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3318 hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3319 if (FAILED(hres))
3320 return hres;
3321 return return_multi_qi(unk, cmq, pResults, TRUE);
3325 * Get a class factory to construct the object we want.
3327 hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3328 if (FAILED(hres))
3329 return hres;
3332 * Create the object and don't forget to release the factory
3334 hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3335 IClassFactory_Release(cf);
3336 if (FAILED(hres))
3338 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3339 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3340 else
3341 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3342 debugstr_guid(pResults[0].pIID),
3343 debugstr_guid(&clsid),hres);
3344 return hres;
3347 return return_multi_qi(unk, cmq, pResults, TRUE);
3350 /***********************************************************************
3351 * CoGetInstanceFromFile [OLE32.@]
3353 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3354 COSERVERINFO *server_info,
3355 CLSID *rclsid,
3356 IUnknown *outer,
3357 DWORD cls_context,
3358 DWORD grfmode,
3359 OLECHAR *filename,
3360 DWORD count,
3361 MULTI_QI *results
3364 IPersistFile *pf = NULL;
3365 IUnknown* unk = NULL;
3366 CLSID clsid;
3367 HRESULT hr;
3369 if (count == 0 || !results)
3370 return E_INVALIDARG;
3372 if (server_info)
3373 FIXME("() non-NULL server_info not supported\n");
3375 init_multi_qi(count, results, E_NOINTERFACE);
3377 /* optionally get CLSID from a file */
3378 if (!rclsid)
3380 hr = GetClassFile(filename, &clsid);
3381 if (FAILED(hr))
3383 ERR("failed to get CLSID from a file\n");
3384 return hr;
3387 rclsid = &clsid;
3390 hr = CoCreateInstance(rclsid,
3391 outer,
3392 cls_context,
3393 &IID_IUnknown,
3394 (void**)&unk);
3396 if (hr != S_OK)
3398 init_multi_qi(count, results, hr);
3399 return hr;
3402 /* init from file */
3403 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3404 if (FAILED(hr))
3406 init_multi_qi(count, results, hr);
3407 IUnknown_Release(unk);
3408 return hr;
3411 hr = IPersistFile_Load(pf, filename, grfmode);
3412 IPersistFile_Release(pf);
3413 if (SUCCEEDED(hr))
3414 return return_multi_qi(unk, count, results, FALSE);
3415 else
3417 init_multi_qi(count, results, hr);
3418 IUnknown_Release(unk);
3419 return hr;
3423 /***********************************************************************
3424 * CoGetInstanceFromIStorage [OLE32.@]
3426 HRESULT WINAPI CoGetInstanceFromIStorage(
3427 COSERVERINFO *server_info,
3428 CLSID *rclsid,
3429 IUnknown *outer,
3430 DWORD cls_context,
3431 IStorage *storage,
3432 DWORD count,
3433 MULTI_QI *results
3436 IPersistStorage *ps = NULL;
3437 IUnknown* unk = NULL;
3438 STATSTG stat;
3439 HRESULT hr;
3441 if (count == 0 || !results || !storage)
3442 return E_INVALIDARG;
3444 if (server_info)
3445 FIXME("() non-NULL server_info not supported\n");
3447 init_multi_qi(count, results, E_NOINTERFACE);
3449 /* optionally get CLSID from a file */
3450 if (!rclsid)
3452 memset(&stat.clsid, 0, sizeof(stat.clsid));
3453 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3454 if (FAILED(hr))
3456 ERR("failed to get CLSID from a file\n");
3457 return hr;
3460 rclsid = &stat.clsid;
3463 hr = CoCreateInstance(rclsid,
3464 outer,
3465 cls_context,
3466 &IID_IUnknown,
3467 (void**)&unk);
3469 if (hr != S_OK)
3470 return hr;
3472 /* init from IStorage */
3473 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3474 if (FAILED(hr))
3475 ERR("failed to get IPersistStorage\n");
3477 if (ps)
3479 IPersistStorage_Load(ps, storage);
3480 IPersistStorage_Release(ps);
3483 return return_multi_qi(unk, count, results, FALSE);
3486 /***********************************************************************
3487 * CoLoadLibrary (OLE32.@)
3489 * Loads a library.
3491 * PARAMS
3492 * lpszLibName [I] Path to library.
3493 * bAutoFree [I] Whether the library should automatically be freed.
3495 * RETURNS
3496 * Success: Handle to loaded library.
3497 * Failure: NULL.
3499 * SEE ALSO
3500 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3502 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3504 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3506 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3509 /***********************************************************************
3510 * CoFreeLibrary [OLE32.@]
3512 * Unloads a library from memory.
3514 * PARAMS
3515 * hLibrary [I] Handle to library to unload.
3517 * RETURNS
3518 * Nothing
3520 * SEE ALSO
3521 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3523 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3525 FreeLibrary(hLibrary);
3529 /***********************************************************************
3530 * CoFreeAllLibraries [OLE32.@]
3532 * Function for backwards compatibility only. Does nothing.
3534 * RETURNS
3535 * Nothing.
3537 * SEE ALSO
3538 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3540 void WINAPI CoFreeAllLibraries(void)
3542 /* NOP */
3545 /***********************************************************************
3546 * CoFreeUnusedLibrariesEx [OLE32.@]
3548 * Frees any previously unused libraries whose delay has expired and marks
3549 * currently unused libraries for unloading. Unused are identified as those that
3550 * return S_OK from their DllCanUnloadNow function.
3552 * PARAMS
3553 * dwUnloadDelay [I] Unload delay in milliseconds.
3554 * dwReserved [I] Reserved. Set to 0.
3556 * RETURNS
3557 * Nothing.
3559 * SEE ALSO
3560 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3562 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3564 struct apartment *apt = COM_CurrentApt();
3565 if (!apt)
3567 ERR("apartment not initialised\n");
3568 return;
3571 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3574 /***********************************************************************
3575 * CoFreeUnusedLibraries [OLE32.@]
3577 * Frees any unused libraries. Unused are identified as those that return
3578 * S_OK from their DllCanUnloadNow function.
3580 * RETURNS
3581 * Nothing.
3583 * SEE ALSO
3584 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3586 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3588 CoFreeUnusedLibrariesEx(INFINITE, 0);
3591 /***********************************************************************
3592 * CoFileTimeNow [OLE32.@]
3594 * Retrieves the current time in FILETIME format.
3596 * PARAMS
3597 * lpFileTime [O] The current time.
3599 * RETURNS
3600 * S_OK.
3602 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3604 GetSystemTimeAsFileTime( lpFileTime );
3605 return S_OK;
3608 /******************************************************************************
3609 * CoLockObjectExternal [OLE32.@]
3611 * Increments or decrements the external reference count of a stub object.
3613 * PARAMS
3614 * pUnk [I] Stub object.
3615 * fLock [I] If TRUE then increments the external ref-count,
3616 * otherwise decrements.
3617 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3618 * calling CoDisconnectObject.
3620 * RETURNS
3621 * Success: S_OK.
3622 * Failure: HRESULT code.
3624 * NOTES
3625 * If fLock is TRUE and an object is passed in that doesn't have a stub
3626 * manager then a new stub manager is created for the object.
3628 HRESULT WINAPI CoLockObjectExternal(
3629 LPUNKNOWN pUnk,
3630 BOOL fLock,
3631 BOOL fLastUnlockReleases)
3633 struct stub_manager *stubmgr;
3634 struct apartment *apt;
3636 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3637 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3639 apt = COM_CurrentApt();
3640 if (!apt) return CO_E_NOTINITIALIZED;
3642 stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3643 if (!stubmgr)
3645 WARN("stub object not found %p\n", pUnk);
3646 /* Note: native is pretty broken here because it just silently
3647 * fails, without returning an appropriate error code, making apps
3648 * think that the object was disconnected, when it actually wasn't */
3649 return S_OK;
3652 if (fLock)
3653 stub_manager_ext_addref(stubmgr, 1, FALSE);
3654 else
3655 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3657 stub_manager_int_release(stubmgr);
3658 return S_OK;
3661 /***********************************************************************
3662 * CoInitializeWOW (OLE32.@)
3664 * WOW equivalent of CoInitialize?
3666 * PARAMS
3667 * x [I] Unknown.
3668 * y [I] Unknown.
3670 * RETURNS
3671 * Unknown.
3673 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3675 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3676 return 0;
3679 /***********************************************************************
3680 * CoGetState [OLE32.@]
3682 * Retrieves the thread state object previously stored by CoSetState().
3684 * PARAMS
3685 * ppv [I] Address where pointer to object will be stored.
3687 * RETURNS
3688 * Success: S_OK.
3689 * Failure: E_OUTOFMEMORY.
3691 * NOTES
3692 * Crashes on all invalid ppv addresses, including NULL.
3693 * If the function returns a non-NULL object then the caller must release its
3694 * reference on the object when the object is no longer required.
3696 * SEE ALSO
3697 * CoSetState().
3699 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3701 struct oletls *info = COM_CurrentInfo();
3702 if (!info) return E_OUTOFMEMORY;
3704 *ppv = NULL;
3706 if (info->state)
3708 IUnknown_AddRef(info->state);
3709 *ppv = info->state;
3710 TRACE("apt->state=%p\n", info->state);
3713 return S_OK;
3716 /***********************************************************************
3717 * CoSetState [OLE32.@]
3719 * Sets the thread state object.
3721 * PARAMS
3722 * pv [I] Pointer to state object to be stored.
3724 * NOTES
3725 * The system keeps a reference on the object while the object stored.
3727 * RETURNS
3728 * Success: S_OK.
3729 * Failure: E_OUTOFMEMORY.
3731 HRESULT WINAPI CoSetState(IUnknown * pv)
3733 struct oletls *info = COM_CurrentInfo();
3734 if (!info) return E_OUTOFMEMORY;
3736 if (pv) IUnknown_AddRef(pv);
3738 if (info->state)
3740 TRACE("-- release %p now\n", info->state);
3741 IUnknown_Release(info->state);
3744 info->state = pv;
3746 return S_OK;
3750 /******************************************************************************
3751 * CoTreatAsClass [OLE32.@]
3753 * Sets the TreatAs value of a class.
3755 * PARAMS
3756 * clsidOld [I] Class to set TreatAs value on.
3757 * clsidNew [I] The class the clsidOld should be treated as.
3759 * RETURNS
3760 * Success: S_OK.
3761 * Failure: HRESULT code.
3763 * SEE ALSO
3764 * CoGetTreatAsClass
3766 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3768 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3769 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3770 HKEY hkey = NULL;
3771 WCHAR szClsidNew[CHARS_IN_GUID];
3772 HRESULT res = S_OK;
3773 WCHAR auto_treat_as[CHARS_IN_GUID];
3774 LONG auto_treat_as_size = sizeof(auto_treat_as);
3775 CLSID id;
3777 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3778 if (FAILED(res))
3779 goto done;
3781 if (IsEqualGUID( clsidOld, clsidNew ))
3783 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3784 CLSIDFromString(auto_treat_as, &id) == S_OK)
3786 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3788 res = REGDB_E_WRITEREGDB;
3789 goto done;
3792 else
3794 if(RegDeleteKeyW(hkey, wszTreatAs))
3795 res = REGDB_E_WRITEREGDB;
3796 goto done;
3799 else
3801 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3802 RegDeleteKeyW(hkey, wszTreatAs);
3803 }else{
3804 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3805 WARN("StringFromGUID2 failed\n");
3806 res = E_FAIL;
3807 goto done;
3810 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3811 WARN("RegSetValue failed\n");
3812 res = REGDB_E_WRITEREGDB;
3813 goto done;
3818 done:
3819 if (hkey) RegCloseKey(hkey);
3820 return res;
3823 /******************************************************************************
3824 * CoGetTreatAsClass [OLE32.@]
3826 * Gets the TreatAs value of a class.
3828 * PARAMS
3829 * clsidOld [I] Class to get the TreatAs value of.
3830 * clsidNew [I] The class the clsidOld should be treated as.
3832 * RETURNS
3833 * Success: S_OK.
3834 * Failure: HRESULT code.
3836 * SEE ALSO
3837 * CoSetTreatAsClass
3839 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3841 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3842 HKEY hkey = NULL;
3843 WCHAR szClsidNew[CHARS_IN_GUID];
3844 HRESULT res = S_OK;
3845 LONG len = sizeof(szClsidNew);
3847 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3849 if (!clsidOld || !clsidNew)
3850 return E_INVALIDARG;
3852 *clsidNew = *clsidOld; /* copy over old value */
3854 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3855 if (FAILED(res))
3857 res = S_FALSE;
3858 goto done;
3860 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3862 res = S_FALSE;
3863 goto done;
3865 res = CLSIDFromString(szClsidNew,clsidNew);
3866 if (FAILED(res))
3867 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3868 done:
3869 if (hkey) RegCloseKey(hkey);
3870 return res;
3873 /******************************************************************************
3874 * CoGetCurrentProcess [OLE32.@]
3876 * Gets the current process ID.
3878 * RETURNS
3879 * The current process ID.
3881 * NOTES
3882 * Is DWORD really the correct return type for this function?
3884 DWORD WINAPI CoGetCurrentProcess(void)
3886 return GetCurrentProcessId();
3889 /***********************************************************************
3890 * CoGetCurrentLogicalThreadId [OLE32.@]
3892 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
3894 TRACE("(%p)\n", id);
3896 if (!id)
3897 return E_INVALIDARG;
3899 *id = COM_CurrentCausalityId();
3900 return S_OK;
3903 /******************************************************************************
3904 * CoRegisterMessageFilter [OLE32.@]
3906 * Registers a message filter.
3908 * PARAMS
3909 * lpMessageFilter [I] Pointer to interface.
3910 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3912 * RETURNS
3913 * Success: S_OK.
3914 * Failure: HRESULT code.
3916 * NOTES
3917 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3918 * lpMessageFilter removes the message filter.
3920 * If lplpMessageFilter is not NULL the previous message filter will be
3921 * returned in the memory pointer to this parameter and the caller is
3922 * responsible for releasing the object.
3924 * The current thread be in an apartment otherwise the function will crash.
3926 HRESULT WINAPI CoRegisterMessageFilter(
3927 LPMESSAGEFILTER lpMessageFilter,
3928 LPMESSAGEFILTER *lplpMessageFilter)
3930 struct apartment *apt;
3931 IMessageFilter *lpOldMessageFilter;
3933 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3935 apt = COM_CurrentApt();
3937 /* can't set a message filter in a multi-threaded apartment */
3938 if (!apt || apt->multi_threaded)
3940 WARN("can't set message filter in MTA or uninitialized apt\n");
3941 return CO_E_NOT_SUPPORTED;
3944 if (lpMessageFilter)
3945 IMessageFilter_AddRef(lpMessageFilter);
3947 EnterCriticalSection(&apt->cs);
3949 lpOldMessageFilter = apt->filter;
3950 apt->filter = lpMessageFilter;
3952 LeaveCriticalSection(&apt->cs);
3954 if (lplpMessageFilter)
3955 *lplpMessageFilter = lpOldMessageFilter;
3956 else if (lpOldMessageFilter)
3957 IMessageFilter_Release(lpOldMessageFilter);
3959 return S_OK;
3962 /***********************************************************************
3963 * CoIsOle1Class [OLE32.@]
3965 * Determines whether the specified class an OLE v1 class.
3967 * PARAMS
3968 * clsid [I] Class to test.
3970 * RETURNS
3971 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3973 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3975 FIXME("%s\n", debugstr_guid(clsid));
3976 return FALSE;
3979 /***********************************************************************
3980 * IsEqualGUID [OLE32.@]
3982 * Compares two Unique Identifiers.
3984 * PARAMS
3985 * rguid1 [I] The first GUID to compare.
3986 * rguid2 [I] The other GUID to compare.
3988 * RETURNS
3989 * TRUE if equal
3991 #undef IsEqualGUID
3992 BOOL WINAPI IsEqualGUID(
3993 REFGUID rguid1,
3994 REFGUID rguid2)
3996 return !memcmp(rguid1,rguid2,sizeof(GUID));
3999 /***********************************************************************
4000 * CoInitializeSecurity [OLE32.@]
4002 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
4003 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
4004 void* pReserved1, DWORD dwAuthnLevel,
4005 DWORD dwImpLevel, void* pReserved2,
4006 DWORD dwCapabilities, void* pReserved3)
4008 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
4009 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
4010 dwCapabilities, pReserved3);
4011 return S_OK;
4014 /***********************************************************************
4015 * CoSuspendClassObjects [OLE32.@]
4017 * Suspends all registered class objects to prevent further requests coming in
4018 * for those objects.
4020 * RETURNS
4021 * Success: S_OK.
4022 * Failure: HRESULT code.
4024 HRESULT WINAPI CoSuspendClassObjects(void)
4026 FIXME("\n");
4027 return S_OK;
4030 /***********************************************************************
4031 * CoAddRefServerProcess [OLE32.@]
4033 * Helper function for incrementing the reference count of a local-server
4034 * process.
4036 * RETURNS
4037 * New reference count.
4039 * SEE ALSO
4040 * CoReleaseServerProcess().
4042 ULONG WINAPI CoAddRefServerProcess(void)
4044 ULONG refs;
4046 TRACE("\n");
4048 EnterCriticalSection(&csRegisteredClassList);
4049 refs = ++s_COMServerProcessReferences;
4050 LeaveCriticalSection(&csRegisteredClassList);
4052 TRACE("refs before: %d\n", refs - 1);
4054 return refs;
4057 /***********************************************************************
4058 * CoReleaseServerProcess [OLE32.@]
4060 * Helper function for decrementing the reference count of a local-server
4061 * process.
4063 * RETURNS
4064 * New reference count.
4066 * NOTES
4067 * When reference count reaches 0, this function suspends all registered
4068 * classes so no new connections are accepted.
4070 * SEE ALSO
4071 * CoAddRefServerProcess(), CoSuspendClassObjects().
4073 ULONG WINAPI CoReleaseServerProcess(void)
4075 ULONG refs;
4077 TRACE("\n");
4079 EnterCriticalSection(&csRegisteredClassList);
4081 refs = --s_COMServerProcessReferences;
4082 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4084 LeaveCriticalSection(&csRegisteredClassList);
4086 TRACE("refs after: %d\n", refs);
4088 return refs;
4091 /***********************************************************************
4092 * CoIsHandlerConnected [OLE32.@]
4094 * Determines whether a proxy is connected to a remote stub.
4096 * PARAMS
4097 * pUnk [I] Pointer to object that may or may not be connected.
4099 * RETURNS
4100 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4101 * FALSE otherwise.
4103 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4105 FIXME("%p\n", pUnk);
4107 return TRUE;
4110 /***********************************************************************
4111 * CoAllowSetForegroundWindow [OLE32.@]
4114 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4116 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4117 return S_OK;
4120 /***********************************************************************
4121 * CoQueryProxyBlanket [OLE32.@]
4123 * Retrieves the security settings being used by a proxy.
4125 * PARAMS
4126 * pProxy [I] Pointer to the proxy object.
4127 * pAuthnSvc [O] The type of authentication service.
4128 * pAuthzSvc [O] The type of authorization service.
4129 * ppServerPrincName [O] Optional. The server prinicple name.
4130 * pAuthnLevel [O] The authentication level.
4131 * pImpLevel [O] The impersonation level.
4132 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4133 * pCapabilities [O] Flags affecting the security behaviour.
4135 * RETURNS
4136 * Success: S_OK.
4137 * Failure: HRESULT code.
4139 * SEE ALSO
4140 * CoCopyProxy, CoSetProxyBlanket.
4142 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4143 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4144 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4146 IClientSecurity *pCliSec;
4147 HRESULT hr;
4149 TRACE("%p\n", pProxy);
4151 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4152 if (SUCCEEDED(hr))
4154 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4155 pAuthzSvc, ppServerPrincName,
4156 pAuthnLevel, pImpLevel, ppAuthInfo,
4157 pCapabilities);
4158 IClientSecurity_Release(pCliSec);
4161 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4162 return hr;
4165 /***********************************************************************
4166 * CoSetProxyBlanket [OLE32.@]
4168 * Sets the security settings for a proxy.
4170 * PARAMS
4171 * pProxy [I] Pointer to the proxy object.
4172 * AuthnSvc [I] The type of authentication service.
4173 * AuthzSvc [I] The type of authorization service.
4174 * pServerPrincName [I] The server prinicple name.
4175 * AuthnLevel [I] The authentication level.
4176 * ImpLevel [I] The impersonation level.
4177 * pAuthInfo [I] Information specific to the authorization/authentication service.
4178 * Capabilities [I] Flags affecting the security behaviour.
4180 * RETURNS
4181 * Success: S_OK.
4182 * Failure: HRESULT code.
4184 * SEE ALSO
4185 * CoQueryProxyBlanket, CoCopyProxy.
4187 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4188 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4189 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4191 IClientSecurity *pCliSec;
4192 HRESULT hr;
4194 TRACE("%p\n", pProxy);
4196 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4197 if (SUCCEEDED(hr))
4199 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4200 AuthzSvc, pServerPrincName,
4201 AuthnLevel, ImpLevel, pAuthInfo,
4202 Capabilities);
4203 IClientSecurity_Release(pCliSec);
4206 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4207 return hr;
4210 /***********************************************************************
4211 * CoCopyProxy [OLE32.@]
4213 * Copies a proxy.
4215 * PARAMS
4216 * pProxy [I] Pointer to the proxy object.
4217 * ppCopy [O] Copy of the proxy.
4219 * RETURNS
4220 * Success: S_OK.
4221 * Failure: HRESULT code.
4223 * SEE ALSO
4224 * CoQueryProxyBlanket, CoSetProxyBlanket.
4226 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4228 IClientSecurity *pCliSec;
4229 HRESULT hr;
4231 TRACE("%p\n", pProxy);
4233 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4234 if (SUCCEEDED(hr))
4236 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4237 IClientSecurity_Release(pCliSec);
4240 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4241 return hr;
4245 /***********************************************************************
4246 * CoGetCallContext [OLE32.@]
4248 * Gets the context of the currently executing server call in the current
4249 * thread.
4251 * PARAMS
4252 * riid [I] Context interface to return.
4253 * ppv [O] Pointer to memory that will receive the context on return.
4255 * RETURNS
4256 * Success: S_OK.
4257 * Failure: HRESULT code.
4259 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4261 struct oletls *info = COM_CurrentInfo();
4263 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4265 if (!info)
4266 return E_OUTOFMEMORY;
4268 if (!info->call_state)
4269 return RPC_E_CALL_COMPLETE;
4271 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4274 /***********************************************************************
4275 * CoSwitchCallContext [OLE32.@]
4277 * Switches the context of the currently executing server call in the current
4278 * thread.
4280 * PARAMS
4281 * pObject [I] Pointer to new context object
4282 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4284 * RETURNS
4285 * Success: S_OK.
4286 * Failure: HRESULT code.
4288 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4290 struct oletls *info = COM_CurrentInfo();
4292 TRACE("(%p, %p)\n", pObject, ppOldObject);
4294 if (!info)
4295 return E_OUTOFMEMORY;
4297 *ppOldObject = info->call_state;
4298 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4300 return S_OK;
4303 /***********************************************************************
4304 * CoQueryClientBlanket [OLE32.@]
4306 * Retrieves the authentication information about the client of the currently
4307 * executing server call in the current thread.
4309 * PARAMS
4310 * pAuthnSvc [O] Optional. The type of authentication service.
4311 * pAuthzSvc [O] Optional. The type of authorization service.
4312 * pServerPrincName [O] Optional. The server prinicple name.
4313 * pAuthnLevel [O] Optional. The authentication level.
4314 * pImpLevel [O] Optional. The impersonation level.
4315 * pPrivs [O] Optional. Information about the privileges of the client.
4316 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4318 * RETURNS
4319 * Success: S_OK.
4320 * Failure: HRESULT code.
4322 * SEE ALSO
4323 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4325 HRESULT WINAPI CoQueryClientBlanket(
4326 DWORD *pAuthnSvc,
4327 DWORD *pAuthzSvc,
4328 OLECHAR **pServerPrincName,
4329 DWORD *pAuthnLevel,
4330 DWORD *pImpLevel,
4331 RPC_AUTHZ_HANDLE *pPrivs,
4332 DWORD *pCapabilities)
4334 IServerSecurity *pSrvSec;
4335 HRESULT hr;
4337 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4338 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4339 pPrivs, pCapabilities);
4341 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4342 if (SUCCEEDED(hr))
4344 hr = IServerSecurity_QueryBlanket(
4345 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4346 pImpLevel, pPrivs, pCapabilities);
4347 IServerSecurity_Release(pSrvSec);
4350 return hr;
4353 /***********************************************************************
4354 * CoImpersonateClient [OLE32.@]
4356 * Impersonates the client of the currently executing server call in the
4357 * current thread.
4359 * PARAMS
4360 * None.
4362 * RETURNS
4363 * Success: S_OK.
4364 * Failure: HRESULT code.
4366 * NOTES
4367 * If this function fails then the current thread will not be impersonating
4368 * the client and all actions will take place on behalf of the server.
4369 * Therefore, it is important to check the return value from this function.
4371 * SEE ALSO
4372 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4374 HRESULT WINAPI CoImpersonateClient(void)
4376 IServerSecurity *pSrvSec;
4377 HRESULT hr;
4379 TRACE("\n");
4381 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4382 if (SUCCEEDED(hr))
4384 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4385 IServerSecurity_Release(pSrvSec);
4388 return hr;
4391 /***********************************************************************
4392 * CoRevertToSelf [OLE32.@]
4394 * Ends the impersonation of the client of the currently executing server
4395 * call in the current thread.
4397 * PARAMS
4398 * None.
4400 * RETURNS
4401 * Success: S_OK.
4402 * Failure: HRESULT code.
4404 * SEE ALSO
4405 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4407 HRESULT WINAPI CoRevertToSelf(void)
4409 IServerSecurity *pSrvSec;
4410 HRESULT hr;
4412 TRACE("\n");
4414 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4415 if (SUCCEEDED(hr))
4417 hr = IServerSecurity_RevertToSelf(pSrvSec);
4418 IServerSecurity_Release(pSrvSec);
4421 return hr;
4424 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4426 /* first try to retrieve messages for incoming COM calls to the apartment window */
4427 return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4428 /* next retrieve other messages necessary for the app to remain responsive */
4429 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4430 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4433 /***********************************************************************
4434 * CoWaitForMultipleHandles [OLE32.@]
4436 * Waits for one or more handles to become signaled.
4438 * PARAMS
4439 * dwFlags [I] Flags. See notes.
4440 * dwTimeout [I] Timeout in milliseconds.
4441 * cHandles [I] Number of handles pointed to by pHandles.
4442 * pHandles [I] Handles to wait for.
4443 * lpdwindex [O] Index of handle that was signaled.
4445 * RETURNS
4446 * Success: S_OK.
4447 * Failure: RPC_S_CALLPENDING on timeout.
4449 * NOTES
4451 * The dwFlags parameter can be zero or more of the following:
4452 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4453 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4455 * SEE ALSO
4456 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4458 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4459 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4461 HRESULT hr = S_OK;
4462 DWORD start_time = GetTickCount();
4463 APARTMENT *apt = COM_CurrentApt();
4464 BOOL message_loop = apt && !apt->multi_threaded;
4465 BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4467 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4468 pHandles, lpdwindex);
4470 if (!lpdwindex)
4471 return E_INVALIDARG;
4473 *lpdwindex = 0;
4475 if (!pHandles)
4476 return E_INVALIDARG;
4478 if (!cHandles)
4479 return RPC_E_NO_SYNC;
4481 while (TRUE)
4483 DWORD now = GetTickCount();
4484 DWORD res;
4486 if (now - start_time > dwTimeout)
4488 hr = RPC_S_CALLPENDING;
4489 break;
4492 if (message_loop)
4494 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4495 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4497 TRACE("waiting for rpc completion or window message\n");
4499 res = WAIT_TIMEOUT;
4501 if (check_apc)
4503 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4504 (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4505 check_apc = FALSE;
4508 if (res == WAIT_TIMEOUT)
4509 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4510 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4511 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4513 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4515 MSG msg;
4516 int count = 0;
4518 /* call message filter */
4520 if (COM_CurrentApt()->filter)
4522 PENDINGTYPE pendingtype =
4523 COM_CurrentInfo()->pending_call_count_server ?
4524 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4525 DWORD be_handled = IMessageFilter_MessagePending(
4526 COM_CurrentApt()->filter, 0 /* FIXME */,
4527 now - start_time, pendingtype);
4528 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4529 switch (be_handled)
4531 case PENDINGMSG_CANCELCALL:
4532 WARN("call canceled\n");
4533 hr = RPC_E_CALL_CANCELED;
4534 break;
4535 case PENDINGMSG_WAITNOPROCESS:
4536 case PENDINGMSG_WAITDEFPROCESS:
4537 default:
4538 /* FIXME: MSDN is very vague about the difference
4539 * between WAITNOPROCESS and WAITDEFPROCESS - there
4540 * appears to be none, so it is possibly a left-over
4541 * from the 16-bit world. */
4542 break;
4546 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4547 * so after processing 100 messages we go back to checking the wait handles */
4548 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4550 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4551 TranslateMessage(&msg);
4552 DispatchMessageW(&msg);
4553 if (msg.message == WM_QUIT)
4555 TRACE("resending WM_QUIT to outer message loop\n");
4556 PostQuitMessage(msg.wParam);
4557 /* no longer need to process messages */
4558 message_loop = FALSE;
4559 break;
4562 continue;
4565 else
4567 TRACE("waiting for rpc completion\n");
4569 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4570 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4571 (dwFlags & COWAIT_ALERTABLE) != 0);
4574 switch (res)
4576 case WAIT_TIMEOUT:
4577 hr = RPC_S_CALLPENDING;
4578 break;
4579 case WAIT_FAILED:
4580 hr = HRESULT_FROM_WIN32( GetLastError() );
4581 break;
4582 default:
4583 *lpdwindex = res;
4584 break;
4586 break;
4588 TRACE("-- 0x%08x\n", hr);
4589 return hr;
4593 /***********************************************************************
4594 * CoGetObject [OLE32.@]
4596 * Gets the object named by converting the name to a moniker and binding to it.
4598 * PARAMS
4599 * pszName [I] String representing the object.
4600 * pBindOptions [I] Parameters affecting the binding to the named object.
4601 * riid [I] Interface to bind to on the objecct.
4602 * ppv [O] On output, the interface riid of the object represented
4603 * by pszName.
4605 * RETURNS
4606 * Success: S_OK.
4607 * Failure: HRESULT code.
4609 * SEE ALSO
4610 * MkParseDisplayName.
4612 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4613 REFIID riid, void **ppv)
4615 IBindCtx *pbc;
4616 HRESULT hr;
4618 *ppv = NULL;
4620 hr = CreateBindCtx(0, &pbc);
4621 if (SUCCEEDED(hr))
4623 if (pBindOptions)
4624 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4626 if (SUCCEEDED(hr))
4628 ULONG chEaten;
4629 IMoniker *pmk;
4631 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4632 if (SUCCEEDED(hr))
4634 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4635 IMoniker_Release(pmk);
4639 IBindCtx_Release(pbc);
4641 return hr;
4644 /***********************************************************************
4645 * CoRegisterChannelHook [OLE32.@]
4647 * Registers a process-wide hook that is called during ORPC calls.
4649 * PARAMS
4650 * guidExtension [I] GUID of the channel hook to register.
4651 * pChannelHook [I] Channel hook object to register.
4653 * RETURNS
4654 * Success: S_OK.
4655 * Failure: HRESULT code.
4657 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4659 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4661 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4664 typedef struct Context
4666 IComThreadingInfo IComThreadingInfo_iface;
4667 IContextCallback IContextCallback_iface;
4668 IObjContext IObjContext_iface;
4669 LONG refs;
4670 } Context;
4672 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4674 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4677 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4679 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4682 static inline Context *impl_from_IObjContext( IObjContext *iface )
4684 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4687 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4689 *ppv = NULL;
4691 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4692 IsEqualIID(riid, &IID_IUnknown))
4694 *ppv = &iface->IComThreadingInfo_iface;
4696 else if (IsEqualIID(riid, &IID_IContextCallback))
4698 *ppv = &iface->IContextCallback_iface;
4700 else if (IsEqualIID(riid, &IID_IObjContext))
4702 *ppv = &iface->IObjContext_iface;
4705 if (*ppv)
4707 IUnknown_AddRef((IUnknown*)*ppv);
4708 return S_OK;
4711 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4712 return E_NOINTERFACE;
4715 static ULONG Context_AddRef(Context *This)
4717 return InterlockedIncrement(&This->refs);
4720 static ULONG Context_Release(Context *This)
4722 /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4723 releasing context while refcount is at 0 destroys it. */
4724 if (!This->refs)
4726 HeapFree(GetProcessHeap(), 0, This);
4727 return 0;
4730 return InterlockedDecrement(&This->refs);
4733 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4735 Context *This = impl_from_IComThreadingInfo(iface);
4736 return Context_QueryInterface(This, riid, ppv);
4739 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4741 Context *This = impl_from_IComThreadingInfo(iface);
4742 return Context_AddRef(This);
4745 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4747 Context *This = impl_from_IComThreadingInfo(iface);
4748 return Context_Release(This);
4751 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4753 APTTYPEQUALIFIER qualifier;
4755 TRACE("(%p)\n", apttype);
4757 return CoGetApartmentType(apttype, &qualifier);
4760 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4762 APTTYPEQUALIFIER qualifier;
4763 APTTYPE apttype;
4764 HRESULT hr;
4766 hr = CoGetApartmentType(&apttype, &qualifier);
4767 if (FAILED(hr))
4768 return hr;
4770 TRACE("(%p)\n", thdtype);
4772 switch (apttype)
4774 case APTTYPE_STA:
4775 case APTTYPE_MAINSTA:
4776 *thdtype = THDTYPE_PROCESSMESSAGES;
4777 break;
4778 default:
4779 *thdtype = THDTYPE_BLOCKMESSAGES;
4780 break;
4782 return S_OK;
4785 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4787 TRACE("(%p)\n", logical_thread_id);
4788 return CoGetCurrentLogicalThreadId(logical_thread_id);
4791 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4793 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4794 return E_NOTIMPL;
4797 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4799 Context_CTI_QueryInterface,
4800 Context_CTI_AddRef,
4801 Context_CTI_Release,
4802 Context_CTI_GetCurrentApartmentType,
4803 Context_CTI_GetCurrentThreadType,
4804 Context_CTI_GetCurrentLogicalThreadId,
4805 Context_CTI_SetCurrentLogicalThreadId
4808 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4810 Context *This = impl_from_IContextCallback(iface);
4811 return Context_QueryInterface(This, riid, ppv);
4814 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4816 Context *This = impl_from_IContextCallback(iface);
4817 return Context_AddRef(This);
4820 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4822 Context *This = impl_from_IContextCallback(iface);
4823 return Context_Release(This);
4826 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4827 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4829 Context *This = impl_from_IContextCallback(iface);
4831 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4832 return E_NOTIMPL;
4835 static const IContextCallbackVtbl Context_Callback_Vtbl =
4837 Context_CC_QueryInterface,
4838 Context_CC_AddRef,
4839 Context_CC_Release,
4840 Context_CC_ContextCallback
4843 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4845 Context *This = impl_from_IObjContext(iface);
4846 return Context_QueryInterface(This, riid, ppv);
4849 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4851 Context *This = impl_from_IObjContext(iface);
4852 return Context_AddRef(This);
4855 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4857 Context *This = impl_from_IObjContext(iface);
4858 return Context_Release(This);
4861 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4863 Context *This = impl_from_IObjContext(iface);
4865 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4866 return E_NOTIMPL;
4869 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4871 Context *This = impl_from_IObjContext(iface);
4873 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4874 return E_NOTIMPL;
4877 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4879 Context *This = impl_from_IObjContext(iface);
4881 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4882 return E_NOTIMPL;
4885 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4887 Context *This = impl_from_IObjContext(iface);
4889 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4890 return E_NOTIMPL;
4893 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4895 Context *This = impl_from_IObjContext(iface);
4896 FIXME("(%p/%p)\n", This, iface);
4899 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4901 Context *This = impl_from_IObjContext(iface);
4902 FIXME("(%p/%p)\n", This, iface);
4905 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4907 Context *This = impl_from_IObjContext(iface);
4908 FIXME("(%p/%p)\n", This, iface);
4911 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4913 Context *This = impl_from_IObjContext(iface);
4914 FIXME("(%p/%p)\n", This, iface);
4917 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4919 Context *This = impl_from_IObjContext(iface);
4920 FIXME("(%p/%p)\n", This, iface);
4923 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4925 Context *This = impl_from_IObjContext(iface);
4926 FIXME("(%p/%p)\n", This, iface);
4929 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4931 Context *This = impl_from_IObjContext(iface);
4932 FIXME("(%p/%p)\n", This, iface);
4935 static const IObjContextVtbl Context_Object_Vtbl =
4937 Context_OC_QueryInterface,
4938 Context_OC_AddRef,
4939 Context_OC_Release,
4940 Context_OC_SetProperty,
4941 Context_OC_RemoveProperty,
4942 Context_OC_GetProperty,
4943 Context_OC_EnumContextProps,
4944 Context_OC_Reserved1,
4945 Context_OC_Reserved2,
4946 Context_OC_Reserved3,
4947 Context_OC_Reserved4,
4948 Context_OC_Reserved5,
4949 Context_OC_Reserved6,
4950 Context_OC_Reserved7
4953 /***********************************************************************
4954 * CoGetObjectContext [OLE32.@]
4956 * Retrieves an object associated with the current context (i.e. apartment).
4958 * PARAMS
4959 * riid [I] ID of the interface of the object to retrieve.
4960 * ppv [O] Address where object will be stored on return.
4962 * RETURNS
4963 * Success: S_OK.
4964 * Failure: HRESULT code.
4966 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4968 IObjContext *context;
4969 HRESULT hr;
4971 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4973 *ppv = NULL;
4974 hr = CoGetContextToken((ULONG_PTR*)&context);
4975 if (FAILED(hr))
4976 return hr;
4978 return IObjContext_QueryInterface(context, riid, ppv);
4981 /***********************************************************************
4982 * CoGetContextToken [OLE32.@]
4984 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4986 struct oletls *info = COM_CurrentInfo();
4988 TRACE("(%p)\n", token);
4990 if (!info)
4991 return E_OUTOFMEMORY;
4993 if (!info->apt)
4995 APARTMENT *apt;
4996 if (!(apt = apartment_find_multi_threaded()))
4998 ERR("apartment not initialised\n");
4999 return CO_E_NOTINITIALIZED;
5001 apartment_release(apt);
5004 if (!token)
5005 return E_POINTER;
5007 if (!info->context_token)
5009 Context *context;
5011 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
5012 if (!context)
5013 return E_OUTOFMEMORY;
5015 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
5016 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
5017 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
5018 /* Context token does not take a reference, it's always zero until the
5019 interface is explicitly requested with CoGetObjectContext(). */
5020 context->refs = 0;
5022 info->context_token = &context->IObjContext_iface;
5025 *token = (ULONG_PTR)info->context_token;
5026 TRACE("context_token=%p\n", info->context_token);
5028 return S_OK;
5031 /***********************************************************************
5032 * CoGetDefaultContext [OLE32.@]
5034 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5036 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5037 return E_NOINTERFACE;
5040 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5042 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5043 HKEY hkey;
5044 HRESULT hres;
5046 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5047 if (SUCCEEDED(hres))
5049 struct class_reg_data regdata;
5050 WCHAR dllpath[MAX_PATH+1];
5052 regdata.u.hkey = hkey;
5053 regdata.hkey = TRUE;
5055 if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
5057 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5058 if (!strcmpiW(dllpath, wszOle32))
5060 RegCloseKey(hkey);
5061 return HandlerCF_Create(rclsid, riid, ppv);
5064 else
5065 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5066 RegCloseKey(hkey);
5069 return CLASS_E_CLASSNOTAVAILABLE;
5072 /***********************************************************************
5073 * CoGetApartmentType [OLE32.@]
5075 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5077 struct oletls *info = COM_CurrentInfo();
5079 FIXME("(%p, %p): semi-stub\n", type, qualifier);
5081 if (!type || !qualifier)
5082 return E_INVALIDARG;
5084 if (!info)
5085 return E_OUTOFMEMORY;
5087 if (!info->apt)
5088 *type = APTTYPE_CURRENT;
5089 else if (info->apt->multi_threaded)
5090 *type = APTTYPE_MTA;
5091 else if (info->apt->main)
5092 *type = APTTYPE_MAINSTA;
5093 else
5094 *type = APTTYPE_STA;
5096 *qualifier = APTTYPEQUALIFIER_NONE;
5098 return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5101 /***********************************************************************
5102 * CoRegisterSurrogate [OLE32.@]
5104 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5106 FIXME("(%p): stub\n", surrogate);
5108 return E_NOTIMPL;
5111 /***********************************************************************
5112 * CoRegisterSurrogateEx [OLE32.@]
5114 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5116 FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5118 return E_NOTIMPL;
5121 typedef struct {
5122 IGlobalOptions IGlobalOptions_iface;
5123 LONG ref;
5124 } GlobalOptions;
5126 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5128 return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5131 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5133 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5135 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5137 if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5139 *ppv = iface;
5141 else
5143 *ppv = NULL;
5144 return E_NOINTERFACE;
5147 IUnknown_AddRef((IUnknown*)*ppv);
5148 return S_OK;
5151 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5153 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5154 LONG ref = InterlockedIncrement(&This->ref);
5156 TRACE("(%p) ref=%d\n", This, ref);
5158 return ref;
5161 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5163 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5164 LONG ref = InterlockedDecrement(&This->ref);
5166 TRACE("(%p) ref=%d\n", This, ref);
5168 if (!ref)
5169 heap_free(This);
5171 return ref;
5174 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5176 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5177 FIXME("(%p)->(%u %lx)\n", This, property, value);
5178 return S_OK;
5181 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5183 GlobalOptions *This = impl_from_IGlobalOptions(iface);
5184 FIXME("(%p)->(%u %p)\n", This, property, value);
5185 return E_NOTIMPL;
5188 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5189 GlobalOptions_QueryInterface,
5190 GlobalOptions_AddRef,
5191 GlobalOptions_Release,
5192 GlobalOptions_Set,
5193 GlobalOptions_Query
5196 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5198 GlobalOptions *global_options;
5199 HRESULT hres;
5201 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5203 if (outer)
5204 return E_INVALIDARG;
5206 global_options = heap_alloc(sizeof(*global_options));
5207 if (!global_options)
5208 return E_OUTOFMEMORY;
5209 global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5210 global_options->ref = 1;
5212 hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5213 IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5214 return hres;
5217 /***********************************************************************
5218 * DllMain (OLE32.@)
5220 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5222 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5224 switch(fdwReason) {
5225 case DLL_PROCESS_ATTACH:
5226 hProxyDll = hinstDLL;
5227 break;
5229 case DLL_PROCESS_DETACH:
5230 if (reserved) break;
5231 release_std_git();
5232 UnregisterClassW( wszAptWinClass, hProxyDll );
5233 RPC_UnregisterAllChannelHooks();
5234 COMPOBJ_DllList_Free();
5235 DeleteCriticalSection(&csRegisteredClassList);
5236 DeleteCriticalSection(&csApartment);
5237 break;
5239 case DLL_THREAD_DETACH:
5240 COM_TlsDestroy();
5241 break;
5243 return TRUE;
5246 /***********************************************************************
5247 * DllRegisterServer (OLE32.@)
5249 HRESULT WINAPI DllRegisterServer(void)
5251 return OLE32_DllRegisterServer();
5254 /***********************************************************************
5255 * DllUnregisterServer (OLE32.@)
5257 HRESULT WINAPI DllUnregisterServer(void)
5259 return OLE32_DllUnregisterServer();