dwrite: Implement CreateFontFaceFromHdc().
[wine.git] / dlls / ole32 / compobj.c
blob1fab04fd0eb4499ae66b24a710b4eec3d585cb71
1 /*
2 * COMPOBJ library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 Justin Bradford
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Sylvain St-Germain
8 * Copyright 2002 Marcus Meissner
9 * Copyright 2004 Mike Hearn
10 * Copyright 2005-2006 Robert Shearman (for CodeWeavers)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note
27 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28 * Therefore do not test against COINIT_MULTITHREADED
30 * TODO list: (items bunched together depend on each other)
32 * - Implement the service control manager (in rpcss) to keep track
33 * of registered class objects: ISCM::ServerRegisterClsid et al
34 * - Implement the OXID resolver so we don't need magic endpoint names for
35 * clients and servers to meet up
39 #include "config.h"
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
50 #include "ntstatus.h"
51 #define WIN32_NO_STATUS
52 #include "windef.h"
53 #include "winbase.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "winuser.h"
57 #define USE_COM_CONTEXT_DEF
58 #include "objbase.h"
59 #include "ole2.h"
60 #include "ole2ver.h"
61 #include "ctxtcall.h"
62 #include "dde.h"
63 #include "servprov.h"
65 #include "initguid.h"
66 #include "compobj_private.h"
67 #include "moniker.h"
69 #include "wine/unicode.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(ole);
74 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
76 /****************************************************************************
77 * This section defines variables internal to the COM module.
80 static APARTMENT *MTA; /* protected by csApartment */
81 static APARTMENT *MainApartment; /* the first STA apartment */
82 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
84 static CRITICAL_SECTION csApartment;
85 static CRITICAL_SECTION_DEBUG critsect_debug =
87 0, 0, &csApartment,
88 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
89 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
91 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
93 enum comclass_threadingmodel
95 ThreadingModel_Apartment = 1,
96 ThreadingModel_Free = 2,
97 ThreadingModel_No = 3,
98 ThreadingModel_Both = 4,
99 ThreadingModel_Neutral = 5
102 enum comclass_miscfields
104 MiscStatus = 1,
105 MiscStatusIcon = 2,
106 MiscStatusContent = 4,
107 MiscStatusThumbnail = 8,
108 MiscStatusDocPrint = 16
111 struct comclassredirect_data
113 ULONG size;
114 BYTE res;
115 BYTE miscmask;
116 BYTE res1[2];
117 DWORD model;
118 GUID clsid;
119 GUID alias;
120 GUID clsid2;
121 GUID tlbid;
122 ULONG name_len;
123 ULONG name_offset;
124 ULONG progid_len;
125 ULONG progid_offset;
126 ULONG clrdata_len;
127 ULONG clrdata_offset;
128 DWORD miscstatus;
129 DWORD miscstatuscontent;
130 DWORD miscstatusthumbnail;
131 DWORD miscstatusicon;
132 DWORD miscstatusdocprint;
135 struct ifacepsredirect_data
137 ULONG size;
138 DWORD mask;
139 GUID iid;
140 ULONG nummethods;
141 GUID tlbid;
142 GUID base;
143 ULONG name_len;
144 ULONG name_offset;
147 struct progidredirect_data
149 ULONG size;
150 DWORD reserved;
151 ULONG clsid_offset;
154 struct class_reg_data
156 union
158 struct
160 struct comclassredirect_data *data;
161 void *section;
162 HANDLE hactctx;
163 } actctx;
164 HKEY hkey;
165 } u;
166 BOOL hkey;
169 struct registered_psclsid
171 struct list entry;
172 IID iid;
173 CLSID clsid;
177 * This is a marshallable object exposing registered local servers.
178 * IServiceProvider is used only because it happens meet requirements
179 * and already has proxy/stub code. If more functionality is needed,
180 * a custom interface may be used instead.
182 struct LocalServer
184 IServiceProvider IServiceProvider_iface;
185 LONG ref;
186 APARTMENT *apt;
187 IStream *marshal_stream;
191 * This lock count counts the number of times CoInitialize is called. It is
192 * decreased every time CoUninitialize is called. When it hits 0, the COM
193 * libraries are freed
195 static LONG s_COMLockCount = 0;
196 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
197 static LONG s_COMServerProcessReferences = 0;
200 * This linked list contains the list of registered class objects. These
201 * are mostly used to register the factories for out-of-proc servers of OLE
202 * objects.
204 * TODO: Make this data structure aware of inter-process communication. This
205 * means that parts of this will be exported to rpcss.
207 typedef struct tagRegisteredClass
209 struct list entry;
210 CLSID classIdentifier;
211 OXID apartment_id;
212 LPUNKNOWN classObject;
213 DWORD runContext;
214 DWORD connectFlags;
215 DWORD dwCookie;
216 void *RpcRegistration;
217 } RegisteredClass;
219 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
221 static CRITICAL_SECTION csRegisteredClassList;
222 static CRITICAL_SECTION_DEBUG class_cs_debug =
224 0, 0, &csRegisteredClassList,
225 { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
226 0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
228 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
230 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
232 switch (aspect)
234 case DVASPECT_CONTENT:
235 return MiscStatusContent;
236 case DVASPECT_THUMBNAIL:
237 return MiscStatusThumbnail;
238 case DVASPECT_ICON:
239 return MiscStatusIcon;
240 case DVASPECT_DOCPRINT:
241 return MiscStatusDocPrint;
242 default:
243 return MiscStatus;
247 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
249 ACTCTX_SECTION_KEYED_DATA data;
251 data.cbSize = sizeof(data);
252 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
253 clsid, &data))
255 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
256 enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
258 if (!(comclass->miscmask & misc))
260 if (!(comclass->miscmask & MiscStatus))
262 *status = 0;
263 return TRUE;
265 misc = MiscStatus;
268 switch (misc)
270 case MiscStatus:
271 *status = comclass->miscstatus;
272 break;
273 case MiscStatusIcon:
274 *status = comclass->miscstatusicon;
275 break;
276 case MiscStatusContent:
277 *status = comclass->miscstatuscontent;
278 break;
279 case MiscStatusThumbnail:
280 *status = comclass->miscstatusthumbnail;
281 break;
282 case MiscStatusDocPrint:
283 *status = comclass->miscstatusdocprint;
284 break;
285 default:
289 return TRUE;
291 else
292 return FALSE;
295 /* wrapper for NtCreateKey that creates the key recursively if necessary */
296 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
298 NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
300 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
302 HANDLE subkey, root = attr->RootDirectory;
303 WCHAR *buffer = attr->ObjectName->Buffer;
304 DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
305 UNICODE_STRING str;
307 while (i < len && buffer[i] != '\\') i++;
308 if (i == len) return status;
310 attrs = attr->Attributes;
311 attr->ObjectName = &str;
313 while (i < len)
315 str.Buffer = buffer + pos;
316 str.Length = (i - pos) * sizeof(WCHAR);
317 status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
318 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
319 if (status) return status;
320 attr->RootDirectory = subkey;
321 while (i < len && buffer[i] == '\\') i++;
322 pos = i;
323 while (i < len && buffer[i] != '\\') i++;
325 str.Buffer = buffer + pos;
326 str.Length = (i - pos) * sizeof(WCHAR);
327 attr->Attributes = attrs;
328 status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
329 if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
331 return status;
334 static const WCHAR classes_rootW[] =
335 {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
337 static HKEY classes_root_hkey;
339 /* create the special HKEY_CLASSES_ROOT key */
340 static HKEY create_classes_root_hkey(DWORD access)
342 HKEY hkey, ret = 0;
343 OBJECT_ATTRIBUTES attr;
344 UNICODE_STRING name;
346 attr.Length = sizeof(attr);
347 attr.RootDirectory = 0;
348 attr.ObjectName = &name;
349 attr.Attributes = 0;
350 attr.SecurityDescriptor = NULL;
351 attr.SecurityQualityOfService = NULL;
352 RtlInitUnicodeString( &name, classes_rootW );
353 if (create_key( &hkey, access, &attr )) return 0;
354 TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
356 if (!(access & KEY_WOW64_64KEY))
358 if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
359 ret = hkey;
360 else
361 NtClose( hkey ); /* somebody beat us to it */
363 else
364 ret = hkey;
365 return ret;
368 /* map the hkey from special root to normal key if necessary */
369 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
371 HKEY ret = hkey;
372 const BOOL is_win64 = sizeof(void*) > sizeof(int);
373 const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
375 if (hkey == HKEY_CLASSES_ROOT &&
376 ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
377 ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
378 if (force_wow32 && ret && ret == classes_root_hkey)
380 static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
381 access &= ~KEY_WOW64_32KEY;
382 if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
383 return 0;
384 ret = hkey;
387 return ret;
390 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
392 OBJECT_ATTRIBUTES attr;
393 UNICODE_STRING nameW;
395 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
397 attr.Length = sizeof(attr);
398 attr.RootDirectory = hkey;
399 attr.ObjectName = &nameW;
400 attr.Attributes = 0;
401 attr.SecurityDescriptor = NULL;
402 attr.SecurityQualityOfService = NULL;
403 RtlInitUnicodeString( &nameW, name );
405 return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
408 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
410 OBJECT_ATTRIBUTES attr;
411 UNICODE_STRING nameW;
413 if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
415 attr.Length = sizeof(attr);
416 attr.RootDirectory = hkey;
417 attr.ObjectName = &nameW;
418 attr.Attributes = 0;
419 attr.SecurityDescriptor = NULL;
420 attr.SecurityQualityOfService = NULL;
421 RtlInitUnicodeString( &nameW, name );
423 return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
426 /*****************************************************************************
427 * This section contains OpenDllList definitions
429 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
430 * other functions that do LoadLibrary _without_ giving back a HMODULE.
431 * Without this list these handles would never be freed.
433 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
434 * next unload-call but not before 600 sec.
437 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
438 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
440 typedef struct tagOpenDll
442 LONG refs;
443 LPWSTR library_name;
444 HANDLE library;
445 DllGetClassObjectFunc DllGetClassObject;
446 DllCanUnloadNowFunc DllCanUnloadNow;
447 struct list entry;
448 } OpenDll;
450 static struct list openDllList = LIST_INIT(openDllList);
452 static CRITICAL_SECTION csOpenDllList;
453 static CRITICAL_SECTION_DEBUG dll_cs_debug =
455 0, 0, &csOpenDllList,
456 { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
457 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
459 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
461 struct apartment_loaded_dll
463 struct list entry;
464 OpenDll *dll;
465 DWORD unload_time;
466 BOOL multi_threaded;
469 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',' ',
470 '0','x','#','#','#','#','#','#','#','#',' ',0};
472 /*****************************************************************************
473 * This section contains OpenDllList implementation
476 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
478 OpenDll *ptr;
479 OpenDll *ret = NULL;
480 EnterCriticalSection(&csOpenDllList);
481 LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
483 if (!strcmpiW(library_name, ptr->library_name) &&
484 (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
486 ret = ptr;
487 break;
490 LeaveCriticalSection(&csOpenDllList);
491 return ret;
494 /* caller must ensure that library_name is not already in the open dll list */
495 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
497 OpenDll *entry;
498 int len;
499 HRESULT hr = S_OK;
500 HANDLE hLibrary;
501 DllCanUnloadNowFunc DllCanUnloadNow;
502 DllGetClassObjectFunc DllGetClassObject;
504 TRACE("%s\n", debugstr_w(library_name));
506 *ret = COMPOBJ_DllList_Get(library_name);
507 if (*ret) return S_OK;
509 /* do this outside the csOpenDllList to avoid creating a lock dependency on
510 * the loader lock */
511 hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
512 if (!hLibrary)
514 ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
515 /* failure: DLL could not be loaded */
516 return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
519 DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
520 /* Note: failing to find DllCanUnloadNow is not a failure */
521 DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
522 if (!DllGetClassObject)
524 /* failure: the dll did not export DllGetClassObject */
525 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
526 FreeLibrary(hLibrary);
527 return CO_E_DLLNOTFOUND;
530 EnterCriticalSection( &csOpenDllList );
532 *ret = COMPOBJ_DllList_Get(library_name);
533 if (*ret)
535 /* another caller to this function already added the dll while we
536 * weren't in the critical section */
537 FreeLibrary(hLibrary);
539 else
541 len = strlenW(library_name);
542 entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
543 if (entry)
544 entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
545 if (entry && entry->library_name)
547 memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
548 entry->library = hLibrary;
549 entry->refs = 1;
550 entry->DllCanUnloadNow = DllCanUnloadNow;
551 entry->DllGetClassObject = DllGetClassObject;
552 list_add_tail(&openDllList, &entry->entry);
553 *ret = entry;
555 else
557 HeapFree(GetProcessHeap(), 0, entry);
558 hr = E_OUTOFMEMORY;
559 FreeLibrary(hLibrary);
563 LeaveCriticalSection( &csOpenDllList );
565 return hr;
568 /* pass FALSE for free_entry to release a reference without destroying the
569 * entry if it reaches zero or TRUE otherwise */
570 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
572 if (!InterlockedDecrement(&entry->refs) && free_entry)
574 EnterCriticalSection(&csOpenDllList);
575 list_remove(&entry->entry);
576 LeaveCriticalSection(&csOpenDllList);
578 TRACE("freeing %p\n", entry->library);
579 FreeLibrary(entry->library);
581 HeapFree(GetProcessHeap(), 0, entry->library_name);
582 HeapFree(GetProcessHeap(), 0, entry);
586 /* frees memory associated with active dll list */
587 static void COMPOBJ_DllList_Free(void)
589 OpenDll *entry, *cursor2;
590 EnterCriticalSection(&csOpenDllList);
591 LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
593 list_remove(&entry->entry);
595 HeapFree(GetProcessHeap(), 0, entry->library_name);
596 HeapFree(GetProcessHeap(), 0, entry);
598 LeaveCriticalSection(&csOpenDllList);
599 DeleteCriticalSection(&csOpenDllList);
602 /******************************************************************************
603 * Manage apartments.
606 static DWORD apartment_addref(struct apartment *apt)
608 DWORD refs = InterlockedIncrement(&apt->refs);
609 TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
610 return refs;
613 /* allocates memory and fills in the necessary fields for a new apartment
614 * object. must be called inside apartment cs */
615 static APARTMENT *apartment_construct(DWORD model)
617 APARTMENT *apt;
619 TRACE("creating new apartment, model=%d\n", model);
621 apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
622 apt->tid = GetCurrentThreadId();
624 list_init(&apt->proxies);
625 list_init(&apt->stubmgrs);
626 list_init(&apt->psclsids);
627 list_init(&apt->loaded_dlls);
628 apt->ipidc = 0;
629 apt->refs = 1;
630 apt->remunk_exported = FALSE;
631 apt->oidc = 1;
632 InitializeCriticalSection(&apt->cs);
633 DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
635 apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
637 if (apt->multi_threaded)
639 /* FIXME: should be randomly generated by in an RPC call to rpcss */
640 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
642 else
644 /* FIXME: should be randomly generated by in an RPC call to rpcss */
645 apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
648 TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
650 list_add_head(&apts, &apt->entry);
652 return apt;
655 /* gets and existing apartment if one exists or otherwise creates an apartment
656 * structure which stores OLE apartment-local information and stores a pointer
657 * to it in the thread-local storage */
658 static APARTMENT *apartment_get_or_create(DWORD model)
660 APARTMENT *apt = COM_CurrentApt();
662 if (!apt)
664 if (model & COINIT_APARTMENTTHREADED)
666 EnterCriticalSection(&csApartment);
668 apt = apartment_construct(model);
669 if (!MainApartment)
671 MainApartment = apt;
672 apt->main = TRUE;
673 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
676 LeaveCriticalSection(&csApartment);
678 if (apt->main)
679 apartment_createwindowifneeded(apt);
681 else
683 EnterCriticalSection(&csApartment);
685 /* The multi-threaded apartment (MTA) contains zero or more threads interacting
686 * with free threaded (ie thread safe) COM objects. There is only ever one MTA
687 * in a process */
688 if (MTA)
690 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
691 apartment_addref(MTA);
693 else
694 MTA = apartment_construct(model);
696 apt = MTA;
698 LeaveCriticalSection(&csApartment);
700 COM_CurrentInfo()->apt = apt;
703 return apt;
706 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
708 return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
711 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
713 list_remove(&curClass->entry);
715 if (curClass->runContext & CLSCTX_LOCAL_SERVER)
716 RPC_StopLocalServer(curClass->RpcRegistration);
718 IUnknown_Release(curClass->classObject);
719 HeapFree(GetProcessHeap(), 0, curClass);
722 static void COM_RevokeAllClasses(const struct apartment *apt)
724 RegisteredClass *curClass, *cursor;
726 EnterCriticalSection( &csRegisteredClassList );
728 LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
730 if (curClass->apartment_id == apt->oxid)
731 COM_RevokeRegisteredClassObject(curClass);
734 LeaveCriticalSection( &csRegisteredClassList );
737 /******************************************************************************
738 * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
741 typedef struct ManualResetEvent {
742 ISynchronize ISynchronize_iface;
743 ISynchronizeHandle ISynchronizeHandle_iface;
744 LONG ref;
745 HANDLE event;
746 } MREImpl;
748 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
750 return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
753 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
755 MREImpl *This = impl_from_ISynchronize(iface);
757 TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
759 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
760 *ppv = &This->ISynchronize_iface;
761 }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
762 *ppv = &This->ISynchronizeHandle_iface;
763 }else {
764 ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
765 *ppv = NULL;
766 return E_NOINTERFACE;
769 IUnknown_AddRef((IUnknown*)*ppv);
770 return S_OK;
773 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
775 MREImpl *This = impl_from_ISynchronize(iface);
776 LONG ref = InterlockedIncrement(&This->ref);
777 TRACE("%p - ref %d\n", This, ref);
779 return ref;
782 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
784 MREImpl *This = impl_from_ISynchronize(iface);
785 LONG ref = InterlockedDecrement(&This->ref);
786 TRACE("%p - ref %d\n", This, ref);
788 if(!ref)
790 CloseHandle(This->event);
791 HeapFree(GetProcessHeap(), 0, This);
794 return ref;
797 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
799 MREImpl *This = impl_from_ISynchronize(iface);
800 UINT index;
801 TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
802 return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
805 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
807 MREImpl *This = impl_from_ISynchronize(iface);
808 TRACE("%p\n", This);
809 SetEvent(This->event);
810 return S_OK;
813 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
815 MREImpl *This = impl_from_ISynchronize(iface);
816 TRACE("%p\n", This);
817 ResetEvent(This->event);
818 return S_OK;
821 static ISynchronizeVtbl vt_ISynchronize = {
822 ISynchronize_fnQueryInterface,
823 ISynchronize_fnAddRef,
824 ISynchronize_fnRelease,
825 ISynchronize_fnWait,
826 ISynchronize_fnSignal,
827 ISynchronize_fnReset
830 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
832 return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
835 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
837 MREImpl *This = impl_from_ISynchronizeHandle(iface);
838 return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
841 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
843 MREImpl *This = impl_from_ISynchronizeHandle(iface);
844 return ISynchronize_AddRef(&This->ISynchronize_iface);
847 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
849 MREImpl *This = impl_from_ISynchronizeHandle(iface);
850 return ISynchronize_Release(&This->ISynchronize_iface);
853 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
855 MREImpl *This = impl_from_ISynchronizeHandle(iface);
857 *ph = This->event;
858 return S_OK;
861 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
862 SynchronizeHandle_QueryInterface,
863 SynchronizeHandle_AddRef,
864 SynchronizeHandle_Release,
865 SynchronizeHandle_GetHandle
868 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
870 MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
871 HRESULT hr;
873 if(punkouter)
874 FIXME("Aggregation not implemented.\n");
876 This->ref = 1;
877 This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
878 This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
879 This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
881 hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
882 ISynchronize_Release(&This->ISynchronize_iface);
883 return hr;
886 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
888 return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
891 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
893 LocalServer *This = impl_from_IServiceProvider(iface);
895 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
897 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
898 *ppv = &This->IServiceProvider_iface;
899 }else {
900 *ppv = NULL;
901 return E_NOINTERFACE;
904 IUnknown_AddRef((IUnknown*)*ppv);
905 return S_OK;
908 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
910 LocalServer *This = impl_from_IServiceProvider(iface);
911 LONG ref = InterlockedIncrement(&This->ref);
913 TRACE("(%p) ref=%d\n", This, ref);
915 return ref;
918 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
920 LocalServer *This = impl_from_IServiceProvider(iface);
921 LONG ref = InterlockedDecrement(&This->ref);
923 TRACE("(%p) ref=%d\n", This, ref);
925 if(!ref) {
926 assert(!This->apt);
927 HeapFree(GetProcessHeap(), 0, This);
930 return ref;
933 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
935 LocalServer *This = impl_from_IServiceProvider(iface);
936 APARTMENT *apt = COM_CurrentApt();
937 RegisteredClass *iter;
938 HRESULT hres = E_FAIL;
940 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
942 if(!This->apt)
943 return E_UNEXPECTED;
945 EnterCriticalSection(&csRegisteredClassList);
947 LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
948 if(iter->apartment_id == apt->oxid
949 && (iter->runContext & CLSCTX_LOCAL_SERVER)
950 && IsEqualGUID(&iter->classIdentifier, guid)) {
951 hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
952 break;
956 LeaveCriticalSection( &csRegisteredClassList );
958 return hres;
961 static const IServiceProviderVtbl LocalServerVtbl = {
962 LocalServer_QueryInterface,
963 LocalServer_AddRef,
964 LocalServer_Release,
965 LocalServer_QueryService
968 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
970 HRESULT hres = S_OK;
972 EnterCriticalSection(&apt->cs);
974 if(!apt->local_server) {
975 LocalServer *obj;
977 obj = heap_alloc(sizeof(*obj));
978 if(obj) {
979 obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
980 obj->ref = 1;
981 obj->apt = apt;
983 hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
984 if(SUCCEEDED(hres)) {
985 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
986 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
987 if(FAILED(hres))
988 IStream_Release(obj->marshal_stream);
991 if(SUCCEEDED(hres))
992 apt->local_server = obj;
993 else
994 heap_free(obj);
995 }else {
996 hres = E_OUTOFMEMORY;
1000 if(SUCCEEDED(hres))
1001 hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1003 LeaveCriticalSection(&apt->cs);
1005 if(FAILED(hres))
1006 ERR("Failed: %08x\n", hres);
1007 return hres;
1010 /***********************************************************************
1011 * CoRevokeClassObject [OLE32.@]
1013 * Removes a class object from the class registry.
1015 * PARAMS
1016 * dwRegister [I] Cookie returned from CoRegisterClassObject().
1018 * RETURNS
1019 * Success: S_OK.
1020 * Failure: HRESULT code.
1022 * NOTES
1023 * Must be called from the same apartment that called CoRegisterClassObject(),
1024 * otherwise it will fail with RPC_E_WRONG_THREAD.
1026 * SEE ALSO
1027 * CoRegisterClassObject
1029 HRESULT WINAPI CoRevokeClassObject(
1030 DWORD dwRegister)
1032 HRESULT hr = E_INVALIDARG;
1033 RegisteredClass *curClass;
1034 APARTMENT *apt;
1036 TRACE("(%08x)\n",dwRegister);
1038 apt = COM_CurrentApt();
1039 if (!apt)
1041 ERR("COM was not initialized\n");
1042 return CO_E_NOTINITIALIZED;
1045 EnterCriticalSection( &csRegisteredClassList );
1047 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1050 * Check if we have a match on the cookie.
1052 if (curClass->dwCookie == dwRegister)
1054 if (curClass->apartment_id == apt->oxid)
1056 COM_RevokeRegisteredClassObject(curClass);
1057 hr = S_OK;
1059 else
1061 ERR("called from wrong apartment, should be called from %s\n",
1062 wine_dbgstr_longlong(curClass->apartment_id));
1063 hr = RPC_E_WRONG_THREAD;
1065 break;
1069 LeaveCriticalSection( &csRegisteredClassList );
1071 return hr;
1074 /* frees unused libraries loaded by apartment_getclassobject by calling the
1075 * DLL's DllCanUnloadNow entry point */
1076 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1078 struct apartment_loaded_dll *entry, *next;
1079 EnterCriticalSection(&apt->cs);
1080 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1082 if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1084 DWORD real_delay = delay;
1086 if (real_delay == INFINITE)
1088 /* DLLs that return multi-threaded objects aren't unloaded
1089 * straight away to cope for programs that have races between
1090 * last object destruction and threads in the DLLs that haven't
1091 * finished, despite DllCanUnloadNow returning S_OK */
1092 if (entry->multi_threaded)
1093 real_delay = 10 * 60 * 1000; /* 10 minutes */
1094 else
1095 real_delay = 0;
1098 if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1100 list_remove(&entry->entry);
1101 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1102 HeapFree(GetProcessHeap(), 0, entry);
1104 else
1106 entry->unload_time = GetTickCount() + real_delay;
1107 if (!entry->unload_time) entry->unload_time = 1;
1110 else if (entry->unload_time)
1111 entry->unload_time = 0;
1113 LeaveCriticalSection(&apt->cs);
1116 DWORD apartment_release(struct apartment *apt)
1118 DWORD ret;
1120 EnterCriticalSection(&csApartment);
1122 ret = InterlockedDecrement(&apt->refs);
1123 TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1124 /* destruction stuff that needs to happen under csApartment CS */
1125 if (ret == 0)
1127 if (apt == MTA) MTA = NULL;
1128 else if (apt == MainApartment) MainApartment = NULL;
1129 list_remove(&apt->entry);
1132 LeaveCriticalSection(&csApartment);
1134 if (ret == 0)
1136 struct list *cursor, *cursor2;
1138 TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1140 if(apt->local_server) {
1141 LocalServer *local_server = apt->local_server;
1142 LARGE_INTEGER zero;
1144 memset(&zero, 0, sizeof(zero));
1145 IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1146 CoReleaseMarshalData(local_server->marshal_stream);
1147 IStream_Release(local_server->marshal_stream);
1148 local_server->marshal_stream = NULL;
1150 apt->local_server = NULL;
1151 local_server->apt = NULL;
1152 IServiceProvider_Release(&local_server->IServiceProvider_iface);
1155 /* Release the references to the registered class objects */
1156 COM_RevokeAllClasses(apt);
1158 /* no locking is needed for this apartment, because no other thread
1159 * can access it at this point */
1161 apartment_disconnectproxies(apt);
1163 if (apt->win) DestroyWindow(apt->win);
1164 if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1166 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1168 struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1169 /* release the implicit reference given by the fact that the
1170 * stub has external references (it must do since it is in the
1171 * stub manager list in the apartment and all non-apartment users
1172 * must have a ref on the apartment and so it cannot be destroyed).
1174 stub_manager_int_release(stubmgr);
1177 LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
1179 struct registered_psclsid *registered_psclsid =
1180 LIST_ENTRY(cursor, struct registered_psclsid, entry);
1182 list_remove(&registered_psclsid->entry);
1183 HeapFree(GetProcessHeap(), 0, registered_psclsid);
1186 /* if this assert fires, then another thread took a reference to a
1187 * stub manager without taking a reference to the containing
1188 * apartment, which it must do. */
1189 assert(list_empty(&apt->stubmgrs));
1191 if (apt->filter) IMessageFilter_Release(apt->filter);
1193 /* free as many unused libraries as possible... */
1194 apartment_freeunusedlibraries(apt, 0);
1196 /* ... and free the memory for the apartment loaded dll entry and
1197 * release the dll list reference without freeing the library for the
1198 * rest */
1199 while ((cursor = list_head(&apt->loaded_dlls)))
1201 struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1202 COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1203 list_remove(cursor);
1204 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1207 DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1208 DeleteCriticalSection(&apt->cs);
1210 HeapFree(GetProcessHeap(), 0, apt);
1213 return ret;
1216 /* The given OXID must be local to this process:
1218 * The ref parameter is here mostly to ensure people remember that
1219 * they get one, you should normally take a ref for thread safety.
1221 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1223 APARTMENT *result = NULL;
1224 struct list *cursor;
1226 EnterCriticalSection(&csApartment);
1227 LIST_FOR_EACH( cursor, &apts )
1229 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1230 if (apt->oxid == oxid)
1232 result = apt;
1233 if (ref) apartment_addref(result);
1234 break;
1237 LeaveCriticalSection(&csApartment);
1239 return result;
1242 /* gets the apartment which has a given creator thread ID. The caller must
1243 * release the reference from the apartment as soon as the apartment pointer
1244 * is no longer required. */
1245 APARTMENT *apartment_findfromtid(DWORD tid)
1247 APARTMENT *result = NULL;
1248 struct list *cursor;
1250 EnterCriticalSection(&csApartment);
1251 LIST_FOR_EACH( cursor, &apts )
1253 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1254 if (apt->tid == tid)
1256 result = apt;
1257 apartment_addref(result);
1258 break;
1261 LeaveCriticalSection(&csApartment);
1263 return result;
1266 /* gets the main apartment if it exists. The caller must
1267 * release the reference from the apartment as soon as the apartment pointer
1268 * is no longer required. */
1269 static APARTMENT *apartment_findmain(void)
1271 APARTMENT *result;
1273 EnterCriticalSection(&csApartment);
1275 result = MainApartment;
1276 if (result) apartment_addref(result);
1278 LeaveCriticalSection(&csApartment);
1280 return result;
1283 /* gets the multi-threaded apartment if it exists. The caller must
1284 * release the reference from the apartment as soon as the apartment pointer
1285 * is no longer required. */
1286 static APARTMENT *apartment_find_multi_threaded(void)
1288 APARTMENT *result = NULL;
1289 struct list *cursor;
1291 EnterCriticalSection(&csApartment);
1293 LIST_FOR_EACH( cursor, &apts )
1295 struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1296 if (apt->multi_threaded)
1298 result = apt;
1299 apartment_addref(result);
1300 break;
1304 LeaveCriticalSection(&csApartment);
1305 return result;
1308 /* gets the specified class object by loading the appropriate DLL, if
1309 * necessary and calls the DllGetClassObject function for the DLL */
1310 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1311 BOOL apartment_threaded,
1312 REFCLSID rclsid, REFIID riid, void **ppv)
1314 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1315 HRESULT hr = S_OK;
1316 BOOL found = FALSE;
1317 struct apartment_loaded_dll *apartment_loaded_dll;
1319 if (!strcmpiW(dllpath, wszOle32))
1321 /* we don't need to control the lifetime of this dll, so use the local
1322 * implementation of DllGetClassObject directly */
1323 TRACE("calling ole32!DllGetClassObject\n");
1324 hr = DllGetClassObject(rclsid, riid, ppv);
1326 if (hr != S_OK)
1327 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1329 return hr;
1332 EnterCriticalSection(&apt->cs);
1334 LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1335 if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1337 TRACE("found %s already loaded\n", debugstr_w(dllpath));
1338 found = TRUE;
1339 break;
1342 if (!found)
1344 apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1345 if (!apartment_loaded_dll)
1346 hr = E_OUTOFMEMORY;
1347 if (SUCCEEDED(hr))
1349 apartment_loaded_dll->unload_time = 0;
1350 apartment_loaded_dll->multi_threaded = FALSE;
1351 hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1352 if (FAILED(hr))
1353 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1355 if (SUCCEEDED(hr))
1357 TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1358 list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1362 LeaveCriticalSection(&apt->cs);
1364 if (SUCCEEDED(hr))
1366 /* one component being multi-threaded overrides any number of
1367 * apartment-threaded components */
1368 if (!apartment_threaded)
1369 apartment_loaded_dll->multi_threaded = TRUE;
1371 TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1372 /* OK: get the ClassObject */
1373 hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1375 if (hr != S_OK)
1376 ERR("DllGetClassObject returned error 0x%08x\n", hr);
1379 return hr;
1382 /***********************************************************************
1383 * COM_RegReadPath [internal]
1385 * Reads a registry value and expands it when necessary
1387 static DWORD COM_RegReadPath(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1389 DWORD ret;
1391 if (regdata->hkey)
1393 DWORD keytype;
1394 WCHAR src[MAX_PATH];
1395 DWORD dwLength = dstlen * sizeof(WCHAR);
1397 if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1398 if (keytype == REG_EXPAND_SZ) {
1399 if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1400 } else {
1401 const WCHAR *quote_start;
1402 quote_start = strchrW(src, '\"');
1403 if (quote_start) {
1404 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1405 if (quote_end) {
1406 memmove(src, quote_start + 1,
1407 (quote_end - quote_start - 1) * sizeof(WCHAR));
1408 src[quote_end - quote_start - 1] = '\0';
1411 lstrcpynW(dst, src, dstlen);
1414 return ret;
1416 else
1418 ULONG_PTR cookie;
1419 WCHAR *nameW;
1421 *dst = 0;
1422 nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1423 ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1424 ret = SearchPathW(NULL, nameW, NULL, dstlen, dst, NULL);
1425 DeactivateActCtx(0, cookie);
1426 return !*dst;
1430 struct host_object_params
1432 struct class_reg_data regdata;
1433 CLSID clsid; /* clsid of object to marshal */
1434 IID iid; /* interface to marshal */
1435 HANDLE event; /* event signalling when ready for multi-threaded case */
1436 HRESULT hr; /* result for multi-threaded case */
1437 IStream *stream; /* stream that the object will be marshaled into */
1438 BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1441 static HRESULT apartment_hostobject(struct apartment *apt,
1442 const struct host_object_params *params)
1444 IUnknown *object;
1445 HRESULT hr;
1446 static const LARGE_INTEGER llZero;
1447 WCHAR dllpath[MAX_PATH+1];
1449 TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1451 if (COM_RegReadPath(&params->regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1453 /* failure: CLSID is not found in registry */
1454 WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1455 return REGDB_E_CLASSNOTREG;
1458 hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1459 &params->clsid, &params->iid, (void **)&object);
1460 if (FAILED(hr))
1461 return hr;
1463 hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1464 if (FAILED(hr))
1465 IUnknown_Release(object);
1466 IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1468 return hr;
1471 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1473 switch (msg)
1475 case DM_EXECUTERPC:
1476 RPC_ExecuteCall((struct dispatch_params *)lParam);
1477 return 0;
1478 case DM_HOSTOBJECT:
1479 return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1480 default:
1481 return DefWindowProcW(hWnd, msg, wParam, lParam);
1485 struct host_thread_params
1487 COINIT threading_model;
1488 HANDLE ready_event;
1489 HWND apartment_hwnd;
1492 /* thread for hosting an object to allow an object to appear to be created in
1493 * an apartment with an incompatible threading model */
1494 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1496 struct host_thread_params *params = p;
1497 MSG msg;
1498 HRESULT hr;
1499 struct apartment *apt;
1501 TRACE("\n");
1503 hr = CoInitializeEx(NULL, params->threading_model);
1504 if (FAILED(hr)) return hr;
1506 apt = COM_CurrentApt();
1507 if (params->threading_model == COINIT_APARTMENTTHREADED)
1509 apartment_createwindowifneeded(apt);
1510 params->apartment_hwnd = apartment_getwindow(apt);
1512 else
1513 params->apartment_hwnd = NULL;
1515 /* force the message queue to be created before signaling parent thread */
1516 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1518 SetEvent(params->ready_event);
1519 params = NULL; /* can't touch params after here as it may be invalid */
1521 while (GetMessageW(&msg, NULL, 0, 0))
1523 if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1525 struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1526 obj_params->hr = apartment_hostobject(apt, obj_params);
1527 SetEvent(obj_params->event);
1529 else
1531 TranslateMessage(&msg);
1532 DispatchMessageW(&msg);
1536 TRACE("exiting\n");
1538 CoUninitialize();
1540 return S_OK;
1543 /* finds or creates a host apartment, creates the object inside it and returns
1544 * a proxy to it so that the object can be used in the apartment of the
1545 * caller of this function */
1546 static HRESULT apartment_hostobject_in_hostapt(
1547 struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1548 const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1550 struct host_object_params params;
1551 HWND apartment_hwnd = NULL;
1552 DWORD apartment_tid = 0;
1553 HRESULT hr;
1555 if (!multi_threaded && main_apartment)
1557 APARTMENT *host_apt = apartment_findmain();
1558 if (host_apt)
1560 apartment_hwnd = apartment_getwindow(host_apt);
1561 apartment_release(host_apt);
1565 if (!apartment_hwnd)
1567 EnterCriticalSection(&apt->cs);
1569 if (!apt->host_apt_tid)
1571 struct host_thread_params thread_params;
1572 HANDLE handles[2];
1573 DWORD wait_value;
1575 thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1576 handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1577 thread_params.apartment_hwnd = NULL;
1578 handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1579 if (!handles[1])
1581 CloseHandle(handles[0]);
1582 LeaveCriticalSection(&apt->cs);
1583 return E_OUTOFMEMORY;
1585 wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1586 CloseHandle(handles[0]);
1587 CloseHandle(handles[1]);
1588 if (wait_value == WAIT_OBJECT_0)
1589 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1590 else
1592 LeaveCriticalSection(&apt->cs);
1593 return E_OUTOFMEMORY;
1597 if (multi_threaded || !main_apartment)
1599 apartment_hwnd = apt->host_apt_hwnd;
1600 apartment_tid = apt->host_apt_tid;
1603 LeaveCriticalSection(&apt->cs);
1606 /* another thread may have become the main apartment in the time it took
1607 * us to create the thread for the host apartment */
1608 if (!apartment_hwnd && !multi_threaded && main_apartment)
1610 APARTMENT *host_apt = apartment_findmain();
1611 if (host_apt)
1613 apartment_hwnd = apartment_getwindow(host_apt);
1614 apartment_release(host_apt);
1618 params.regdata = *regdata;
1619 params.clsid = *rclsid;
1620 params.iid = *riid;
1621 hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1622 if (FAILED(hr))
1623 return hr;
1624 params.apartment_threaded = !multi_threaded;
1625 if (multi_threaded)
1627 params.hr = S_OK;
1628 params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1629 if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1630 hr = E_OUTOFMEMORY;
1631 else
1633 WaitForSingleObject(params.event, INFINITE);
1634 hr = params.hr;
1636 CloseHandle(params.event);
1638 else
1640 if (!apartment_hwnd)
1642 ERR("host apartment didn't create window\n");
1643 hr = E_OUTOFMEMORY;
1645 else
1646 hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1648 if (SUCCEEDED(hr))
1649 hr = CoUnmarshalInterface(params.stream, riid, ppv);
1650 IStream_Release(params.stream);
1651 return hr;
1654 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1656 WNDCLASSW wclass;
1658 /* Dispatching to the correct thread in an apartment is done through
1659 * window messages rather than RPC transports. When an interface is
1660 * marshalled into another apartment in the same process, a window of the
1661 * following class is created. The *caller* of CoMarshalInterface (i.e., the
1662 * application) is responsible for pumping the message loop in that thread.
1663 * The WM_USER messages which point to the RPCs are then dispatched to
1664 * apartment_wndproc by the user's code from the apartment in which the
1665 * interface was unmarshalled.
1667 memset(&wclass, 0, sizeof(wclass));
1668 wclass.lpfnWndProc = apartment_wndproc;
1669 wclass.hInstance = hProxyDll;
1670 wclass.lpszClassName = wszAptWinClass;
1671 RegisterClassW(&wclass);
1672 return TRUE;
1675 /* create a window for the apartment or return the current one if one has
1676 * already been created */
1677 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1679 static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1681 if (apt->multi_threaded)
1682 return S_OK;
1684 if (!apt->win)
1686 HWND hwnd;
1688 InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1690 hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1691 HWND_MESSAGE, 0, hProxyDll, NULL);
1692 if (!hwnd)
1694 ERR("CreateWindow failed with error %d\n", GetLastError());
1695 return HRESULT_FROM_WIN32(GetLastError());
1697 if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1698 /* someone beat us to it */
1699 DestroyWindow(hwnd);
1702 return S_OK;
1705 /* retrieves the window for the main- or apartment-threaded apartment */
1706 HWND apartment_getwindow(const struct apartment *apt)
1708 assert(!apt->multi_threaded);
1709 return apt->win;
1712 void apartment_joinmta(void)
1714 apartment_addref(MTA);
1715 COM_CurrentInfo()->apt = MTA;
1718 static void COM_TlsDestroy(void)
1720 struct oletls *info = NtCurrentTeb()->ReservedForOle;
1721 if (info)
1723 if (info->apt) apartment_release(info->apt);
1724 if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1725 if (info->state) IUnknown_Release(info->state);
1726 if (info->spy) IInitializeSpy_Release(info->spy);
1727 if (info->context_token) IObjContext_Release(info->context_token);
1728 HeapFree(GetProcessHeap(), 0, info);
1729 NtCurrentTeb()->ReservedForOle = NULL;
1733 /******************************************************************************
1734 * CoBuildVersion [OLE32.@]
1736 * Gets the build version of the DLL.
1738 * PARAMS
1740 * RETURNS
1741 * Current build version, hiword is majornumber, loword is minornumber
1743 DWORD WINAPI CoBuildVersion(void)
1745 TRACE("Returning version %d, build %d.\n", rmm, rup);
1746 return (rmm<<16)+rup;
1749 /******************************************************************************
1750 * CoRegisterInitializeSpy [OLE32.@]
1752 * Add a Spy that watches CoInitializeEx calls
1754 * PARAMS
1755 * spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1756 * cookie [II] cookie receiver
1758 * RETURNS
1759 * Success: S_OK if not already initialized, S_FALSE otherwise.
1760 * Failure: HRESULT code.
1762 * SEE ALSO
1763 * CoInitializeEx
1765 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1767 struct oletls *info = COM_CurrentInfo();
1768 HRESULT hr;
1770 TRACE("(%p, %p)\n", spy, cookie);
1772 if (!spy || !cookie || !info)
1774 if (!info)
1775 WARN("Could not allocate tls\n");
1776 return E_INVALIDARG;
1779 if (info->spy)
1781 FIXME("Already registered?\n");
1782 return E_UNEXPECTED;
1785 hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1786 if (SUCCEEDED(hr))
1788 cookie->QuadPart = (DWORD_PTR)spy;
1789 return S_OK;
1791 return hr;
1794 /******************************************************************************
1795 * CoRevokeInitializeSpy [OLE32.@]
1797 * Remove a spy that previously watched CoInitializeEx calls
1799 * PARAMS
1800 * cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1802 * RETURNS
1803 * Success: S_OK if a spy is removed
1804 * Failure: E_INVALIDARG
1806 * SEE ALSO
1807 * CoInitializeEx
1809 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1811 struct oletls *info = COM_CurrentInfo();
1812 TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1814 if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1815 return E_INVALIDARG;
1817 IInitializeSpy_Release(info->spy);
1818 info->spy = NULL;
1819 return S_OK;
1823 /******************************************************************************
1824 * CoInitialize [OLE32.@]
1826 * Initializes the COM libraries by calling CoInitializeEx with
1827 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1829 * PARAMS
1830 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1832 * RETURNS
1833 * Success: S_OK if not already initialized, S_FALSE otherwise.
1834 * Failure: HRESULT code.
1836 * SEE ALSO
1837 * CoInitializeEx
1839 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1842 * Just delegate to the newer method.
1844 return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1847 /******************************************************************************
1848 * CoInitializeEx [OLE32.@]
1850 * Initializes the COM libraries.
1852 * PARAMS
1853 * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1854 * dwCoInit [I] One or more flags from the COINIT enumeration. See notes.
1856 * RETURNS
1857 * S_OK if successful,
1858 * S_FALSE if this function was called already.
1859 * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1860 * threading model.
1862 * NOTES
1864 * The behavior used to set the IMalloc used for memory management is
1865 * obsolete.
1866 * The dwCoInit parameter must specify one of the following apartment
1867 * threading models:
1868 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1869 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1870 * The parameter may also specify zero or more of the following flags:
1871 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1872 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1874 * SEE ALSO
1875 * CoUninitialize
1877 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1879 struct oletls *info = COM_CurrentInfo();
1880 HRESULT hr = S_OK;
1881 APARTMENT *apt;
1883 TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1885 if (lpReserved!=NULL)
1887 ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1891 * Check the lock count. If this is the first time going through the initialize
1892 * process, we have to initialize the libraries.
1894 * And crank-up that lock count.
1896 if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1899 * Initialize the various COM libraries and data structures.
1901 TRACE("() - Initializing the COM libraries\n");
1903 /* we may need to defer this until after apartment initialisation */
1904 RunningObjectTableImpl_Initialize();
1907 if (info->spy)
1908 IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1910 if (!(apt = info->apt))
1912 apt = apartment_get_or_create(dwCoInit);
1913 if (!apt) return E_OUTOFMEMORY;
1915 else if (!apartment_is_model(apt, dwCoInit))
1917 /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1918 code then we are probably using the wrong threading model to implement that API. */
1919 ERR("Attempt to change threading model of this apartment from %s to %s\n",
1920 apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1921 dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1922 return RPC_E_CHANGED_MODE;
1924 else
1925 hr = S_FALSE;
1927 info->inits++;
1929 if (info->spy)
1930 IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1932 return hr;
1935 /***********************************************************************
1936 * CoUninitialize [OLE32.@]
1938 * This method will decrement the refcount on the current apartment, freeing
1939 * the resources associated with it if it is the last thread in the apartment.
1940 * If the last apartment is freed, the function will additionally release
1941 * any COM resources associated with the process.
1943 * PARAMS
1945 * RETURNS
1946 * Nothing.
1948 * SEE ALSO
1949 * CoInitializeEx
1951 void WINAPI CoUninitialize(void)
1953 struct oletls * info = COM_CurrentInfo();
1954 LONG lCOMRefCnt;
1956 TRACE("()\n");
1958 /* will only happen on OOM */
1959 if (!info) return;
1961 if (info->spy)
1962 IInitializeSpy_PreUninitialize(info->spy, info->inits);
1964 /* sanity check */
1965 if (!info->inits)
1967 ERR("Mismatched CoUninitialize\n");
1969 if (info->spy)
1970 IInitializeSpy_PostUninitialize(info->spy, info->inits);
1971 return;
1974 if (!--info->inits)
1976 apartment_release(info->apt);
1977 info->apt = NULL;
1981 * Decrease the reference count.
1982 * If we are back to 0 locks on the COM library, make sure we free
1983 * all the associated data structures.
1985 lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1986 if (lCOMRefCnt==1)
1988 TRACE("() - Releasing the COM libraries\n");
1990 RunningObjectTableImpl_UnInitialize();
1992 else if (lCOMRefCnt<1) {
1993 ERR( "CoUninitialize() - not CoInitialized.\n" );
1994 InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1996 if (info->spy)
1997 IInitializeSpy_PostUninitialize(info->spy, info->inits);
2000 /******************************************************************************
2001 * CoDisconnectObject [OLE32.@]
2003 * Disconnects all connections to this object from remote processes. Dispatches
2004 * pending RPCs while blocking new RPCs from occurring, and then calls
2005 * IMarshal::DisconnectObject on the given object.
2007 * Typically called when the object server is forced to shut down, for instance by
2008 * the user.
2010 * PARAMS
2011 * lpUnk [I] The object whose stub should be disconnected.
2012 * reserved [I] Reserved. Should be set to 0.
2014 * RETURNS
2015 * Success: S_OK.
2016 * Failure: HRESULT code.
2018 * SEE ALSO
2019 * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2021 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2023 HRESULT hr;
2024 IMarshal *marshal;
2025 APARTMENT *apt;
2027 TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2029 if (!lpUnk) return E_INVALIDARG;
2031 hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2032 if (hr == S_OK)
2034 hr = IMarshal_DisconnectObject(marshal, reserved);
2035 IMarshal_Release(marshal);
2036 return hr;
2039 apt = COM_CurrentApt();
2040 if (!apt)
2041 return CO_E_NOTINITIALIZED;
2043 apartment_disconnectobject(apt, lpUnk);
2045 /* Note: native is pretty broken here because it just silently
2046 * fails, without returning an appropriate error code if the object was
2047 * not found, making apps think that the object was disconnected, when
2048 * it actually wasn't */
2050 return S_OK;
2053 /******************************************************************************
2054 * CoCreateGuid [OLE32.@]
2056 * Simply forwards to UuidCreate in RPCRT4.
2058 * PARAMS
2059 * pguid [O] Points to the GUID to initialize.
2061 * RETURNS
2062 * Success: S_OK.
2063 * Failure: HRESULT code.
2065 * SEE ALSO
2066 * UuidCreate
2068 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2070 DWORD status;
2072 if(!pguid) return E_INVALIDARG;
2074 status = UuidCreate(pguid);
2075 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2076 return HRESULT_FROM_WIN32( status );
2079 static inline BOOL is_valid_hex(WCHAR c)
2081 if (!(((c >= '0') && (c <= '9')) ||
2082 ((c >= 'a') && (c <= 'f')) ||
2083 ((c >= 'A') && (c <= 'F'))))
2084 return FALSE;
2085 return TRUE;
2088 static const BYTE guid_conv_table[256] =
2090 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2091 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2092 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2093 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2094 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2095 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2096 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* 0x60 */
2099 /* conversion helper for CLSIDFromString/IIDFromString */
2100 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2102 int i;
2104 if (!s || s[0]!='{') {
2105 memset( id, 0, sizeof (CLSID) );
2106 if(!s) return TRUE;
2107 return FALSE;
2110 TRACE("%s -> %p\n", debugstr_w(s), id);
2112 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2114 id->Data1 = 0;
2115 for (i = 1; i < 9; i++) {
2116 if (!is_valid_hex(s[i])) return FALSE;
2117 id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2119 if (s[9]!='-') return FALSE;
2121 id->Data2 = 0;
2122 for (i = 10; i < 14; i++) {
2123 if (!is_valid_hex(s[i])) return FALSE;
2124 id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2126 if (s[14]!='-') return FALSE;
2128 id->Data3 = 0;
2129 for (i = 15; i < 19; i++) {
2130 if (!is_valid_hex(s[i])) return FALSE;
2131 id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2133 if (s[19]!='-') return FALSE;
2135 for (i = 20; i < 37; i+=2) {
2136 if (i == 24) {
2137 if (s[i]!='-') return FALSE;
2138 i++;
2140 if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2141 id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2144 if (s[37] == '}' && s[38] == '\0')
2145 return TRUE;
2147 return FALSE;
2150 /*****************************************************************************/
2152 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2154 static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2155 WCHAR buf2[CHARS_IN_GUID];
2156 LONG buf2len = sizeof(buf2);
2157 HKEY xhkey;
2158 WCHAR *buf;
2160 memset(clsid, 0, sizeof(*clsid));
2161 buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2162 if (!buf) return E_OUTOFMEMORY;
2163 strcpyW( buf, progid );
2164 strcatW( buf, clsidW );
2165 if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2167 HeapFree(GetProcessHeap(),0,buf);
2168 WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2169 return CO_E_CLASSSTRING;
2171 HeapFree(GetProcessHeap(),0,buf);
2173 if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2175 RegCloseKey(xhkey);
2176 WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2177 return CO_E_CLASSSTRING;
2179 RegCloseKey(xhkey);
2180 return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2183 /******************************************************************************
2184 * CLSIDFromString [OLE32.@]
2186 * Converts a unique identifier from its string representation into
2187 * the GUID struct.
2189 * PARAMS
2190 * idstr [I] The string representation of the GUID.
2191 * id [O] GUID converted from the string.
2193 * RETURNS
2194 * S_OK on success
2195 * CO_E_CLASSSTRING if idstr is not a valid CLSID
2197 * SEE ALSO
2198 * StringFromCLSID
2200 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2202 HRESULT ret = CO_E_CLASSSTRING;
2203 CLSID tmp_id;
2205 if (!id)
2206 return E_INVALIDARG;
2208 if (guid_from_string(idstr, id))
2209 return S_OK;
2211 /* It appears a ProgID is also valid */
2212 ret = clsid_from_string_reg(idstr, &tmp_id);
2213 if(SUCCEEDED(ret))
2214 *id = tmp_id;
2216 return ret;
2219 /******************************************************************************
2220 * IIDFromString [OLE32.@]
2222 * Converts a interface identifier from its string representation into
2223 * the IID struct.
2225 * PARAMS
2226 * idstr [I] The string representation of the GUID.
2227 * id [O] IID converted from the string.
2229 * RETURNS
2230 * S_OK on success
2231 * CO_E_IIDSTRING if idstr is not a valid IID
2233 * SEE ALSO
2234 * StringFromIID
2236 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2238 TRACE("%s -> %p\n", debugstr_w(s), iid);
2240 if (!s)
2242 memset(iid, 0, sizeof(*iid));
2243 return S_OK;
2246 /* length mismatch is a special case */
2247 if (strlenW(s) + 1 != CHARS_IN_GUID)
2248 return E_INVALIDARG;
2250 if (s[0] != '{')
2251 return CO_E_IIDSTRING;
2253 return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2256 /******************************************************************************
2257 * StringFromCLSID [OLE32.@]
2258 * StringFromIID [OLE32.@]
2260 * Converts a GUID into the respective string representation.
2261 * The target string is allocated using the OLE IMalloc.
2263 * PARAMS
2264 * id [I] the GUID to be converted.
2265 * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2267 * RETURNS
2268 * S_OK
2269 * E_FAIL
2271 * SEE ALSO
2272 * StringFromGUID2, CLSIDFromString
2274 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2276 if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2277 StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2278 return S_OK;
2281 /******************************************************************************
2282 * StringFromGUID2 [OLE32.@]
2284 * Modified version of StringFromCLSID that allows you to specify max
2285 * buffer size.
2287 * PARAMS
2288 * id [I] GUID to convert to string.
2289 * str [O] Buffer where the result will be stored.
2290 * cmax [I] Size of the buffer in characters.
2292 * RETURNS
2293 * Success: The length of the resulting string in characters.
2294 * Failure: 0.
2296 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2298 static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2299 '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2300 '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2301 '%','0','2','X','%','0','2','X','}',0 };
2302 if (!id || cmax < CHARS_IN_GUID) return 0;
2303 sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2304 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2305 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2306 return CHARS_IN_GUID;
2309 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2310 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2312 static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2313 WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2314 LONG res;
2315 HKEY key;
2317 strcpyW(path, wszCLSIDSlash);
2318 StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2319 res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2320 if (res == ERROR_FILE_NOT_FOUND)
2321 return REGDB_E_CLASSNOTREG;
2322 else if (res != ERROR_SUCCESS)
2323 return REGDB_E_READREGDB;
2325 if (!keyname)
2327 *subkey = key;
2328 return S_OK;
2331 res = open_classes_key(key, keyname, access, subkey);
2332 RegCloseKey(key);
2333 if (res == ERROR_FILE_NOT_FOUND)
2334 return REGDB_E_KEYMISSING;
2335 else if (res != ERROR_SUCCESS)
2336 return REGDB_E_READREGDB;
2338 return S_OK;
2341 /* open HKCR\\AppId\\{string form of appid clsid} key */
2342 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2344 static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2345 static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2346 DWORD res;
2347 WCHAR buf[CHARS_IN_GUID];
2348 WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2349 DWORD size;
2350 HKEY hkey;
2351 DWORD type;
2352 HRESULT hr;
2354 /* read the AppID value under the class's key */
2355 hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2356 if (FAILED(hr))
2357 return hr;
2359 size = sizeof(buf);
2360 res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2361 RegCloseKey(hkey);
2362 if (res == ERROR_FILE_NOT_FOUND)
2363 return REGDB_E_KEYMISSING;
2364 else if (res != ERROR_SUCCESS || type!=REG_SZ)
2365 return REGDB_E_READREGDB;
2367 strcpyW(keyname, szAppIdKey);
2368 strcatW(keyname, buf);
2369 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2370 if (res == ERROR_FILE_NOT_FOUND)
2371 return REGDB_E_KEYMISSING;
2372 else if (res != ERROR_SUCCESS)
2373 return REGDB_E_READREGDB;
2375 return S_OK;
2378 /******************************************************************************
2379 * ProgIDFromCLSID [OLE32.@]
2381 * Converts a class id into the respective program ID.
2383 * PARAMS
2384 * clsid [I] Class ID, as found in registry.
2385 * ppszProgID [O] Associated ProgID.
2387 * RETURNS
2388 * S_OK
2389 * E_OUTOFMEMORY
2390 * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2392 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2394 static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2395 ACTCTX_SECTION_KEYED_DATA data;
2396 HKEY hkey;
2397 HRESULT ret;
2398 LONG progidlen = 0;
2400 if (!ppszProgID)
2401 return E_INVALIDARG;
2403 *ppszProgID = NULL;
2405 data.cbSize = sizeof(data);
2406 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2407 clsid, &data))
2409 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2410 if (comclass->progid_len)
2412 WCHAR *ptrW;
2414 *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2415 if (!*ppszProgID) return E_OUTOFMEMORY;
2417 ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2418 memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2419 return S_OK;
2421 else
2422 return REGDB_E_CLASSNOTREG;
2425 ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2426 if (FAILED(ret))
2427 return ret;
2429 if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2430 ret = REGDB_E_CLASSNOTREG;
2432 if (ret == S_OK)
2434 *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2435 if (*ppszProgID)
2437 if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2438 ret = REGDB_E_CLASSNOTREG;
2439 CoTaskMemFree(*ppszProgID);
2440 *ppszProgID = NULL;
2443 else
2444 ret = E_OUTOFMEMORY;
2447 RegCloseKey(hkey);
2448 return ret;
2451 /******************************************************************************
2452 * CLSIDFromProgID [OLE32.@]
2454 * Converts a program id into the respective GUID.
2456 * PARAMS
2457 * progid [I] Unicode program ID, as found in registry.
2458 * clsid [O] Associated CLSID.
2460 * RETURNS
2461 * Success: S_OK
2462 * Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2464 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2466 ACTCTX_SECTION_KEYED_DATA data;
2468 if (!progid || !clsid)
2469 return E_INVALIDARG;
2471 data.cbSize = sizeof(data);
2472 if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2473 progid, &data))
2475 struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2476 CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2477 *clsid = *alias;
2478 return S_OK;
2481 return clsid_from_string_reg(progid, clsid);
2484 /******************************************************************************
2485 * CLSIDFromProgIDEx [OLE32.@]
2487 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2489 FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2491 return CLSIDFromProgID(progid, clsid);
2494 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2496 HKEY hkey;
2497 WCHAR value[CHARS_IN_GUID];
2498 DWORD len;
2500 access |= KEY_READ;
2502 if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2503 return REGDB_E_IIDNOTREG;
2505 len = sizeof(value);
2506 if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2507 return REGDB_E_IIDNOTREG;
2508 RegCloseKey(hkey);
2510 if (CLSIDFromString(value, pclsid) != NOERROR)
2511 return REGDB_E_IIDNOTREG;
2513 return S_OK;
2516 /*****************************************************************************
2517 * CoGetPSClsid [OLE32.@]
2519 * Retrieves the CLSID of the proxy/stub factory that implements
2520 * IPSFactoryBuffer for the specified interface.
2522 * PARAMS
2523 * riid [I] Interface whose proxy/stub CLSID is to be returned.
2524 * pclsid [O] Where to store returned proxy/stub CLSID.
2526 * RETURNS
2527 * S_OK
2528 * E_OUTOFMEMORY
2529 * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2531 * NOTES
2533 * The standard marshaller activates the object with the CLSID
2534 * returned and uses the CreateProxy and CreateStub methods on its
2535 * IPSFactoryBuffer interface to construct the proxies and stubs for a
2536 * given object.
2538 * CoGetPSClsid determines this CLSID by searching the
2539 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2540 * in the registry and any interface id registered by
2541 * CoRegisterPSClsid within the current process.
2543 * BUGS
2545 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2546 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2547 * considered a bug in native unless an application depends on this (unlikely).
2549 * SEE ALSO
2550 * CoRegisterPSClsid.
2552 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2554 static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2555 static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2556 WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2557 APARTMENT *apt = COM_CurrentApt();
2558 struct registered_psclsid *registered_psclsid;
2559 ACTCTX_SECTION_KEYED_DATA data;
2560 HRESULT hr;
2561 REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2562 BOOL is_wow64;
2564 TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2566 if (!apt)
2568 ERR("apartment not initialised\n");
2569 return CO_E_NOTINITIALIZED;
2572 if (!pclsid)
2573 return E_INVALIDARG;
2575 EnterCriticalSection(&apt->cs);
2577 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2578 if (IsEqualIID(&registered_psclsid->iid, riid))
2580 *pclsid = registered_psclsid->clsid;
2581 LeaveCriticalSection(&apt->cs);
2582 return S_OK;
2585 LeaveCriticalSection(&apt->cs);
2587 data.cbSize = sizeof(data);
2588 if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2589 riid, &data))
2591 struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2592 *pclsid = ifaceps->iid;
2593 return S_OK;
2596 /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2597 strcpyW(path, wszInterface);
2598 StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2599 strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2601 hr = get_ps_clsid_from_registry(path, 0, pclsid);
2602 if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2603 (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2604 hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2606 if (hr == S_OK)
2607 TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2608 else
2609 WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2611 return hr;
2614 /*****************************************************************************
2615 * CoRegisterPSClsid [OLE32.@]
2617 * Register a proxy/stub CLSID for the given interface in the current process
2618 * only.
2620 * PARAMS
2621 * riid [I] Interface whose proxy/stub CLSID is to be registered.
2622 * rclsid [I] CLSID of the proxy/stub.
2624 * RETURNS
2625 * Success: S_OK
2626 * Failure: E_OUTOFMEMORY
2628 * NOTES
2630 * This function does not add anything to the registry and the effects are
2631 * limited to the lifetime of the current process.
2633 * SEE ALSO
2634 * CoGetPSClsid.
2636 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2638 APARTMENT *apt = COM_CurrentApt();
2639 struct registered_psclsid *registered_psclsid;
2641 TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2643 if (!apt)
2645 ERR("apartment not initialised\n");
2646 return CO_E_NOTINITIALIZED;
2649 EnterCriticalSection(&apt->cs);
2651 LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
2652 if (IsEqualIID(&registered_psclsid->iid, riid))
2654 registered_psclsid->clsid = *rclsid;
2655 LeaveCriticalSection(&apt->cs);
2656 return S_OK;
2659 registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2660 if (!registered_psclsid)
2662 LeaveCriticalSection(&apt->cs);
2663 return E_OUTOFMEMORY;
2666 registered_psclsid->iid = *riid;
2667 registered_psclsid->clsid = *rclsid;
2668 list_add_head(&apt->psclsids, &registered_psclsid->entry);
2670 LeaveCriticalSection(&apt->cs);
2672 return S_OK;
2676 /***
2677 * COM_GetRegisteredClassObject
2679 * This internal method is used to scan the registered class list to
2680 * find a class object.
2682 * Params:
2683 * rclsid Class ID of the class to find.
2684 * dwClsContext Class context to match.
2685 * ppv [out] returns a pointer to the class object. Complying
2686 * to normal COM usage, this method will increase the
2687 * reference count on this object.
2689 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2690 DWORD dwClsContext, LPUNKNOWN* ppUnk)
2692 HRESULT hr = S_FALSE;
2693 RegisteredClass *curClass;
2695 EnterCriticalSection( &csRegisteredClassList );
2697 LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2700 * Check if we have a match on the class ID and context.
2702 if ((apt->oxid == curClass->apartment_id) &&
2703 (dwClsContext & curClass->runContext) &&
2704 IsEqualGUID(&(curClass->classIdentifier), rclsid))
2707 * We have a match, return the pointer to the class object.
2709 *ppUnk = curClass->classObject;
2711 IUnknown_AddRef(curClass->classObject);
2713 hr = S_OK;
2714 break;
2718 LeaveCriticalSection( &csRegisteredClassList );
2720 return hr;
2723 /******************************************************************************
2724 * CoRegisterClassObject [OLE32.@]
2726 * Registers the class object for a given class ID. Servers housed in EXE
2727 * files use this method instead of exporting DllGetClassObject to allow
2728 * other code to connect to their objects.
2730 * PARAMS
2731 * rclsid [I] CLSID of the object to register.
2732 * pUnk [I] IUnknown of the object.
2733 * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2734 * flags [I] REGCLS flags indicating how connections are made.
2735 * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2737 * RETURNS
2738 * S_OK on success,
2739 * E_INVALIDARG if lpdwRegister or pUnk are NULL,
2740 * CO_E_OBJISREG if the object is already registered. We should not return this.
2742 * SEE ALSO
2743 * CoRevokeClassObject, CoGetClassObject
2745 * NOTES
2746 * In-process objects are only registered for the current apartment.
2747 * CoGetClassObject() and CoCreateInstance() will not return objects registered
2748 * in other apartments.
2750 * BUGS
2751 * MSDN claims that multiple interface registrations are legal, but we
2752 * can't do that with our current implementation.
2754 HRESULT WINAPI CoRegisterClassObject(
2755 REFCLSID rclsid,
2756 LPUNKNOWN pUnk,
2757 DWORD dwClsContext,
2758 DWORD flags,
2759 LPDWORD lpdwRegister)
2761 static LONG next_cookie;
2762 RegisteredClass* newClass;
2763 LPUNKNOWN foundObject;
2764 HRESULT hr;
2765 APARTMENT *apt;
2767 TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2768 debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2770 if ( (lpdwRegister==0) || (pUnk==0) )
2771 return E_INVALIDARG;
2773 apt = COM_CurrentApt();
2774 if (!apt)
2776 ERR("COM was not initialized\n");
2777 return CO_E_NOTINITIALIZED;
2780 *lpdwRegister = 0;
2782 /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2783 * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2784 if (flags & REGCLS_MULTIPLEUSE)
2785 dwClsContext |= CLSCTX_INPROC_SERVER;
2788 * First, check if the class is already registered.
2789 * If it is, this should cause an error.
2791 hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2792 if (hr == S_OK) {
2793 if (flags & REGCLS_MULTIPLEUSE) {
2794 if (dwClsContext & CLSCTX_LOCAL_SERVER)
2795 hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2796 IUnknown_Release(foundObject);
2797 return hr;
2799 IUnknown_Release(foundObject);
2800 ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2801 return CO_E_OBJISREG;
2804 newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2805 if ( newClass == NULL )
2806 return E_OUTOFMEMORY;
2808 newClass->classIdentifier = *rclsid;
2809 newClass->apartment_id = apt->oxid;
2810 newClass->runContext = dwClsContext;
2811 newClass->connectFlags = flags;
2812 newClass->RpcRegistration = NULL;
2814 if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2815 newClass->dwCookie = InterlockedIncrement( &next_cookie );
2818 * Since we're making a copy of the object pointer, we have to increase its
2819 * reference count.
2821 newClass->classObject = pUnk;
2822 IUnknown_AddRef(newClass->classObject);
2824 EnterCriticalSection( &csRegisteredClassList );
2825 list_add_tail(&RegisteredClassList, &newClass->entry);
2826 LeaveCriticalSection( &csRegisteredClassList );
2828 *lpdwRegister = newClass->dwCookie;
2830 if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2831 IStream *marshal_stream;
2833 hr = get_local_server_stream(apt, &marshal_stream);
2834 if(FAILED(hr))
2835 return hr;
2837 hr = RPC_StartLocalServer(&newClass->classIdentifier,
2838 marshal_stream,
2839 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2840 &newClass->RpcRegistration);
2841 IStream_Release(marshal_stream);
2843 return S_OK;
2846 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2848 if (data->hkey)
2850 static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2851 static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2852 static const WCHAR wszFree[] = {'F','r','e','e',0};
2853 static const WCHAR wszBoth[] = {'B','o','t','h',0};
2854 WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2855 DWORD dwLength = sizeof(threading_model);
2856 DWORD keytype;
2857 DWORD ret;
2859 ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2860 if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2861 threading_model[0] = '\0';
2863 if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2864 if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2865 if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2867 /* there's not specific handling for this case */
2868 if (threading_model[0]) return ThreadingModel_Neutral;
2869 return ThreadingModel_No;
2871 else
2872 return data->u.actctx.data->model;
2875 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2876 REFCLSID rclsid, REFIID riid,
2877 BOOL hostifnecessary, void **ppv)
2879 WCHAR dllpath[MAX_PATH+1];
2880 BOOL apartment_threaded;
2882 if (hostifnecessary)
2884 enum comclass_threadingmodel model = get_threading_model(regdata);
2886 if (model == ThreadingModel_Apartment)
2888 apartment_threaded = TRUE;
2889 if (apt->multi_threaded)
2890 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2892 else if (model == ThreadingModel_Free)
2894 apartment_threaded = FALSE;
2895 if (!apt->multi_threaded)
2896 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2898 /* everything except "Apartment", "Free" and "Both" */
2899 else if (model != ThreadingModel_Both)
2901 apartment_threaded = TRUE;
2902 /* everything else is main-threaded */
2903 if (model != ThreadingModel_No)
2904 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2906 if (apt->multi_threaded || !apt->main)
2907 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2909 else
2910 apartment_threaded = FALSE;
2912 else
2913 apartment_threaded = !apt->multi_threaded;
2915 if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2917 /* failure: CLSID is not found in registry */
2918 WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2919 return REGDB_E_CLASSNOTREG;
2922 return apartment_getclassobject(apt, dllpath, apartment_threaded,
2923 rclsid, riid, ppv);
2926 /***********************************************************************
2927 * CoGetClassObject [OLE32.@]
2929 * Creates an object of the specified class.
2931 * PARAMS
2932 * rclsid [I] Class ID to create an instance of.
2933 * dwClsContext [I] Flags to restrict the location of the created instance.
2934 * pServerInfo [I] Optional. Details for connecting to a remote server.
2935 * iid [I] The ID of the interface of the instance to return.
2936 * ppv [O] On returns, contains a pointer to the specified interface of the object.
2938 * RETURNS
2939 * Success: S_OK
2940 * Failure: HRESULT code.
2942 * NOTES
2943 * The dwClsContext parameter can be one or more of the following:
2944 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2945 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2946 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2947 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2949 * SEE ALSO
2950 * CoCreateInstance()
2952 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2953 REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2954 REFIID iid, LPVOID *ppv)
2956 struct class_reg_data clsreg;
2957 IUnknown *regClassObject;
2958 HRESULT hres = E_UNEXPECTED;
2959 APARTMENT *apt;
2960 BOOL release_apt = FALSE;
2962 TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2964 if (!ppv)
2965 return E_INVALIDARG;
2967 *ppv = NULL;
2969 if (!(apt = COM_CurrentApt()))
2971 if (!(apt = apartment_find_multi_threaded()))
2973 ERR("apartment not initialised\n");
2974 return CO_E_NOTINITIALIZED;
2976 release_apt = TRUE;
2979 if (pServerInfo) {
2980 FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2981 debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2984 if (CLSCTX_INPROC_SERVER & dwClsContext)
2986 if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2988 if (release_apt) apartment_release(apt);
2989 return FTMarshalCF_Create(iid, ppv);
2993 if (CLSCTX_INPROC & dwClsContext)
2995 ACTCTX_SECTION_KEYED_DATA data;
2997 data.cbSize = sizeof(data);
2998 /* search activation context first */
2999 if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3000 ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3001 rclsid, &data))
3003 struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3005 clsreg.u.actctx.hactctx = data.hActCtx;
3006 clsreg.u.actctx.data = data.lpData;
3007 clsreg.u.actctx.section = data.lpSectionBase;
3008 clsreg.hkey = FALSE;
3010 hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3011 ReleaseActCtx(data.hActCtx);
3012 if (release_apt) apartment_release(apt);
3013 return hres;
3018 * First, try and see if we can't match the class ID with one of the
3019 * registered classes.
3021 if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3022 &regClassObject))
3024 /* Get the required interface from the retrieved pointer. */
3025 hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3028 * Since QI got another reference on the pointer, we want to release the
3029 * one we already have. If QI was unsuccessful, this will release the object. This
3030 * is good since we are not returning it in the "out" parameter.
3032 IUnknown_Release(regClassObject);
3033 if (release_apt) apartment_release(apt);
3034 return hres;
3037 /* First try in-process server */
3038 if (CLSCTX_INPROC_SERVER & dwClsContext)
3040 static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3041 HKEY hkey;
3043 hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3044 if (FAILED(hres))
3046 if (hres == REGDB_E_CLASSNOTREG)
3047 ERR("class %s not registered\n", debugstr_guid(rclsid));
3048 else if (hres == REGDB_E_KEYMISSING)
3050 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3051 hres = REGDB_E_CLASSNOTREG;
3055 if (SUCCEEDED(hres))
3057 clsreg.u.hkey = hkey;
3058 clsreg.hkey = TRUE;
3060 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3061 RegCloseKey(hkey);
3064 /* return if we got a class, otherwise fall through to one of the
3065 * other types */
3066 if (SUCCEEDED(hres))
3068 if (release_apt) apartment_release(apt);
3069 return hres;
3073 /* Next try in-process handler */
3074 if (CLSCTX_INPROC_HANDLER & dwClsContext)
3076 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3077 HKEY hkey;
3079 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3080 if (FAILED(hres))
3082 if (hres == REGDB_E_CLASSNOTREG)
3083 ERR("class %s not registered\n", debugstr_guid(rclsid));
3084 else if (hres == REGDB_E_KEYMISSING)
3086 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3087 hres = REGDB_E_CLASSNOTREG;
3091 if (SUCCEEDED(hres))
3093 clsreg.u.hkey = hkey;
3094 clsreg.hkey = TRUE;
3096 hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3097 RegCloseKey(hkey);
3100 /* return if we got a class, otherwise fall through to one of the
3101 * other types */
3102 if (SUCCEEDED(hres))
3104 if (release_apt) apartment_release(apt);
3105 return hres;
3108 if (release_apt) apartment_release(apt);
3110 /* Next try out of process */
3111 if (CLSCTX_LOCAL_SERVER & dwClsContext)
3113 hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3114 if (SUCCEEDED(hres))
3115 return hres;
3118 /* Finally try remote: this requires networked DCOM (a lot of work) */
3119 if (CLSCTX_REMOTE_SERVER & dwClsContext)
3121 FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3122 hres = REGDB_E_CLASSNOTREG;
3125 if (FAILED(hres))
3126 ERR("no class object %s could be created for context 0x%x\n",
3127 debugstr_guid(rclsid), dwClsContext);
3128 return hres;
3131 /***********************************************************************
3132 * CoResumeClassObjects (OLE32.@)
3134 * Resumes all class objects registered with REGCLS_SUSPENDED.
3136 * RETURNS
3137 * Success: S_OK.
3138 * Failure: HRESULT code.
3140 HRESULT WINAPI CoResumeClassObjects(void)
3142 FIXME("stub\n");
3143 return S_OK;
3146 /***********************************************************************
3147 * CoCreateInstance [OLE32.@]
3149 * Creates an instance of the specified class.
3151 * PARAMS
3152 * rclsid [I] Class ID to create an instance of.
3153 * pUnkOuter [I] Optional outer unknown to allow aggregation with another object.
3154 * dwClsContext [I] Flags to restrict the location of the created instance.
3155 * iid [I] The ID of the interface of the instance to return.
3156 * ppv [O] On returns, contains a pointer to the specified interface of the instance.
3158 * RETURNS
3159 * Success: S_OK
3160 * Failure: HRESULT code.
3162 * NOTES
3163 * The dwClsContext parameter can be one or more of the following:
3164 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3165 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3166 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3167 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3169 * Aggregation is the concept of deferring the IUnknown of an object to another
3170 * object. This allows a separate object to behave as though it was part of
3171 * the object and to allow this the pUnkOuter parameter can be set. Note that
3172 * not all objects support having an outer of unknown.
3174 * SEE ALSO
3175 * CoGetClassObject()
3177 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3178 REFCLSID rclsid,
3179 LPUNKNOWN pUnkOuter,
3180 DWORD dwClsContext,
3181 REFIID iid,
3182 LPVOID *ppv)
3184 HRESULT hres;
3185 LPCLASSFACTORY lpclf = 0;
3186 APARTMENT *apt;
3187 CLSID clsid;
3189 TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3190 pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3192 if (ppv==0)
3193 return E_POINTER;
3195 hres = CoGetTreatAsClass(rclsid, &clsid);
3196 if(FAILED(hres))
3197 clsid = *rclsid;
3199 *ppv = 0;
3201 if (!(apt = COM_CurrentApt()))
3203 if (!(apt = apartment_find_multi_threaded()))
3205 ERR("apartment not initialised\n");
3206 return CO_E_NOTINITIALIZED;
3208 apartment_release(apt);
3212 * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3214 if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3216 IGlobalInterfaceTable *git = get_std_git();
3217 hres = IGlobalInterfaceTable_QueryInterface(git, iid, ppv);
3218 if (hres != S_OK) return hres;
3220 TRACE("Retrieved GIT (%p)\n", *ppv);
3221 return S_OK;
3224 if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent))
3225 return ManualResetEvent_Construct(pUnkOuter, iid, ppv);
3228 * Get a class factory to construct the object we want.
3230 hres = CoGetClassObject(&clsid,
3231 dwClsContext,
3232 NULL,
3233 &IID_IClassFactory,
3234 (LPVOID)&lpclf);
3236 if (FAILED(hres))
3237 return hres;
3240 * Create the object and don't forget to release the factory
3242 hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
3243 IClassFactory_Release(lpclf);
3244 if (FAILED(hres))
3246 if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3247 FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3248 else
3249 FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3250 debugstr_guid(iid),
3251 debugstr_guid(&clsid),hres);
3254 return hres;
3257 static void init_multi_qi(DWORD count, MULTI_QI *mqi)
3259 ULONG i;
3261 for (i = 0; i < count; i++)
3263 mqi[i].pItf = NULL;
3264 mqi[i].hr = E_NOINTERFACE;
3268 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi)
3270 ULONG index, fetched = 0;
3272 for (index = 0; index < count; index++)
3274 mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3275 if (mqi[index].hr == S_OK)
3276 fetched++;
3279 IUnknown_Release(unk);
3281 if (fetched == 0)
3282 return E_NOINTERFACE;
3284 return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3287 /***********************************************************************
3288 * CoCreateInstanceEx [OLE32.@]
3290 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3291 REFCLSID rclsid,
3292 LPUNKNOWN pUnkOuter,
3293 DWORD dwClsContext,
3294 COSERVERINFO* pServerInfo,
3295 ULONG cmq,
3296 MULTI_QI* pResults)
3298 IUnknown* pUnk = NULL;
3299 HRESULT hr;
3302 * Sanity check
3304 if ( (cmq==0) || (pResults==NULL))
3305 return E_INVALIDARG;
3307 if (pServerInfo!=NULL)
3308 FIXME("() non-NULL pServerInfo not supported!\n");
3310 init_multi_qi(cmq, pResults);
3313 * Get the object and get its IUnknown pointer.
3315 hr = CoCreateInstance(rclsid,
3316 pUnkOuter,
3317 dwClsContext,
3318 &IID_IUnknown,
3319 (VOID**)&pUnk);
3321 if (hr != S_OK)
3322 return hr;
3324 return return_multi_qi(pUnk, cmq, pResults);
3327 /***********************************************************************
3328 * CoGetInstanceFromFile [OLE32.@]
3330 HRESULT WINAPI CoGetInstanceFromFile(
3331 COSERVERINFO *server_info,
3332 CLSID *rclsid,
3333 IUnknown *outer,
3334 DWORD cls_context,
3335 DWORD grfmode,
3336 OLECHAR *filename,
3337 DWORD count,
3338 MULTI_QI *results
3341 IPersistFile *pf = NULL;
3342 IUnknown* unk = NULL;
3343 CLSID clsid;
3344 HRESULT hr;
3346 if (count == 0 || !results)
3347 return E_INVALIDARG;
3349 if (server_info)
3350 FIXME("() non-NULL server_info not supported\n");
3352 init_multi_qi(count, results);
3354 /* optionally get CLSID from a file */
3355 if (!rclsid)
3357 hr = GetClassFile(filename, &clsid);
3358 if (FAILED(hr))
3360 ERR("failed to get CLSID from a file\n");
3361 return hr;
3364 rclsid = &clsid;
3367 hr = CoCreateInstance(rclsid,
3368 outer,
3369 cls_context,
3370 &IID_IUnknown,
3371 (void**)&unk);
3373 if (hr != S_OK)
3374 return hr;
3376 /* init from file */
3377 hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3378 if (FAILED(hr))
3379 ERR("failed to get IPersistFile\n");
3381 if (pf)
3383 IPersistFile_Load(pf, filename, grfmode);
3384 IPersistFile_Release(pf);
3387 return return_multi_qi(unk, count, results);
3390 /***********************************************************************
3391 * CoGetInstanceFromIStorage [OLE32.@]
3393 HRESULT WINAPI CoGetInstanceFromIStorage(
3394 COSERVERINFO *server_info,
3395 CLSID *rclsid,
3396 IUnknown *outer,
3397 DWORD cls_context,
3398 IStorage *storage,
3399 DWORD count,
3400 MULTI_QI *results
3403 IPersistStorage *ps = NULL;
3404 IUnknown* unk = NULL;
3405 STATSTG stat;
3406 HRESULT hr;
3408 if (count == 0 || !results || !storage)
3409 return E_INVALIDARG;
3411 if (server_info)
3412 FIXME("() non-NULL server_info not supported\n");
3414 init_multi_qi(count, results);
3416 /* optionally get CLSID from a file */
3417 if (!rclsid)
3419 memset(&stat.clsid, 0, sizeof(stat.clsid));
3420 hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3421 if (FAILED(hr))
3423 ERR("failed to get CLSID from a file\n");
3424 return hr;
3427 rclsid = &stat.clsid;
3430 hr = CoCreateInstance(rclsid,
3431 outer,
3432 cls_context,
3433 &IID_IUnknown,
3434 (void**)&unk);
3436 if (hr != S_OK)
3437 return hr;
3439 /* init from IStorage */
3440 hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3441 if (FAILED(hr))
3442 ERR("failed to get IPersistStorage\n");
3444 if (ps)
3446 IPersistStorage_Load(ps, storage);
3447 IPersistStorage_Release(ps);
3450 return return_multi_qi(unk, count, results);
3453 /***********************************************************************
3454 * CoLoadLibrary (OLE32.@)
3456 * Loads a library.
3458 * PARAMS
3459 * lpszLibName [I] Path to library.
3460 * bAutoFree [I] Whether the library should automatically be freed.
3462 * RETURNS
3463 * Success: Handle to loaded library.
3464 * Failure: NULL.
3466 * SEE ALSO
3467 * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3469 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3471 TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3473 return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3476 /***********************************************************************
3477 * CoFreeLibrary [OLE32.@]
3479 * Unloads a library from memory.
3481 * PARAMS
3482 * hLibrary [I] Handle to library to unload.
3484 * RETURNS
3485 * Nothing
3487 * SEE ALSO
3488 * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3490 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3492 FreeLibrary(hLibrary);
3496 /***********************************************************************
3497 * CoFreeAllLibraries [OLE32.@]
3499 * Function for backwards compatibility only. Does nothing.
3501 * RETURNS
3502 * Nothing.
3504 * SEE ALSO
3505 * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3507 void WINAPI CoFreeAllLibraries(void)
3509 /* NOP */
3512 /***********************************************************************
3513 * CoFreeUnusedLibrariesEx [OLE32.@]
3515 * Frees any previously unused libraries whose delay has expired and marks
3516 * currently unused libraries for unloading. Unused are identified as those that
3517 * return S_OK from their DllCanUnloadNow function.
3519 * PARAMS
3520 * dwUnloadDelay [I] Unload delay in milliseconds.
3521 * dwReserved [I] Reserved. Set to 0.
3523 * RETURNS
3524 * Nothing.
3526 * SEE ALSO
3527 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3529 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3531 struct apartment *apt = COM_CurrentApt();
3532 if (!apt)
3534 ERR("apartment not initialised\n");
3535 return;
3538 apartment_freeunusedlibraries(apt, dwUnloadDelay);
3541 /***********************************************************************
3542 * CoFreeUnusedLibraries [OLE32.@]
3544 * Frees any unused libraries. Unused are identified as those that return
3545 * S_OK from their DllCanUnloadNow function.
3547 * RETURNS
3548 * Nothing.
3550 * SEE ALSO
3551 * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3553 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3555 CoFreeUnusedLibrariesEx(INFINITE, 0);
3558 /***********************************************************************
3559 * CoFileTimeNow [OLE32.@]
3561 * Retrieves the current time in FILETIME format.
3563 * PARAMS
3564 * lpFileTime [O] The current time.
3566 * RETURNS
3567 * S_OK.
3569 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3571 GetSystemTimeAsFileTime( lpFileTime );
3572 return S_OK;
3575 /******************************************************************************
3576 * CoLockObjectExternal [OLE32.@]
3578 * Increments or decrements the external reference count of a stub object.
3580 * PARAMS
3581 * pUnk [I] Stub object.
3582 * fLock [I] If TRUE then increments the external ref-count,
3583 * otherwise decrements.
3584 * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3585 * calling CoDisconnectObject.
3587 * RETURNS
3588 * Success: S_OK.
3589 * Failure: HRESULT code.
3591 * NOTES
3592 * If fLock is TRUE and an object is passed in that doesn't have a stub
3593 * manager then a new stub manager is created for the object.
3595 HRESULT WINAPI CoLockObjectExternal(
3596 LPUNKNOWN pUnk,
3597 BOOL fLock,
3598 BOOL fLastUnlockReleases)
3600 struct stub_manager *stubmgr;
3601 struct apartment *apt;
3603 TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3604 pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3606 apt = COM_CurrentApt();
3607 if (!apt) return CO_E_NOTINITIALIZED;
3609 stubmgr = get_stub_manager_from_object(apt, pUnk);
3611 if (stubmgr)
3613 if (fLock)
3614 stub_manager_ext_addref(stubmgr, 1, FALSE);
3615 else
3616 stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3618 stub_manager_int_release(stubmgr);
3620 return S_OK;
3622 else if (fLock)
3624 stubmgr = new_stub_manager(apt, pUnk);
3626 if (stubmgr)
3628 stub_manager_ext_addref(stubmgr, 1, FALSE);
3629 stub_manager_int_release(stubmgr);
3632 return S_OK;
3634 else
3636 WARN("stub object not found %p\n", pUnk);
3637 /* Note: native is pretty broken here because it just silently
3638 * fails, without returning an appropriate error code, making apps
3639 * think that the object was disconnected, when it actually wasn't */
3640 return S_OK;
3644 /***********************************************************************
3645 * CoInitializeWOW (OLE32.@)
3647 * WOW equivalent of CoInitialize?
3649 * PARAMS
3650 * x [I] Unknown.
3651 * y [I] Unknown.
3653 * RETURNS
3654 * Unknown.
3656 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3658 FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3659 return 0;
3662 /***********************************************************************
3663 * CoGetState [OLE32.@]
3665 * Retrieves the thread state object previously stored by CoSetState().
3667 * PARAMS
3668 * ppv [I] Address where pointer to object will be stored.
3670 * RETURNS
3671 * Success: S_OK.
3672 * Failure: E_OUTOFMEMORY.
3674 * NOTES
3675 * Crashes on all invalid ppv addresses, including NULL.
3676 * If the function returns a non-NULL object then the caller must release its
3677 * reference on the object when the object is no longer required.
3679 * SEE ALSO
3680 * CoSetState().
3682 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3684 struct oletls *info = COM_CurrentInfo();
3685 if (!info) return E_OUTOFMEMORY;
3687 *ppv = NULL;
3689 if (info->state)
3691 IUnknown_AddRef(info->state);
3692 *ppv = info->state;
3693 TRACE("apt->state=%p\n", info->state);
3696 return S_OK;
3699 /***********************************************************************
3700 * CoSetState [OLE32.@]
3702 * Sets the thread state object.
3704 * PARAMS
3705 * pv [I] Pointer to state object to be stored.
3707 * NOTES
3708 * The system keeps a reference on the object while the object stored.
3710 * RETURNS
3711 * Success: S_OK.
3712 * Failure: E_OUTOFMEMORY.
3714 HRESULT WINAPI CoSetState(IUnknown * pv)
3716 struct oletls *info = COM_CurrentInfo();
3717 if (!info) return E_OUTOFMEMORY;
3719 if (pv) IUnknown_AddRef(pv);
3721 if (info->state)
3723 TRACE("-- release %p now\n", info->state);
3724 IUnknown_Release(info->state);
3727 info->state = pv;
3729 return S_OK;
3733 /******************************************************************************
3734 * CoTreatAsClass [OLE32.@]
3736 * Sets the TreatAs value of a class.
3738 * PARAMS
3739 * clsidOld [I] Class to set TreatAs value on.
3740 * clsidNew [I] The class the clsidOld should be treated as.
3742 * RETURNS
3743 * Success: S_OK.
3744 * Failure: HRESULT code.
3746 * SEE ALSO
3747 * CoGetTreatAsClass
3749 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3751 static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3752 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3753 HKEY hkey = NULL;
3754 WCHAR szClsidNew[CHARS_IN_GUID];
3755 HRESULT res = S_OK;
3756 WCHAR auto_treat_as[CHARS_IN_GUID];
3757 LONG auto_treat_as_size = sizeof(auto_treat_as);
3758 CLSID id;
3760 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3761 if (FAILED(res))
3762 goto done;
3764 if (IsEqualGUID( clsidOld, clsidNew ))
3766 if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3767 CLSIDFromString(auto_treat_as, &id) == S_OK)
3769 if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3771 res = REGDB_E_WRITEREGDB;
3772 goto done;
3775 else
3777 if(RegDeleteKeyW(hkey, wszTreatAs))
3778 res = REGDB_E_WRITEREGDB;
3779 goto done;
3782 else
3784 if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3785 RegDeleteKeyW(hkey, wszTreatAs);
3786 }else{
3787 if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3788 WARN("StringFromGUID2 failed\n");
3789 res = E_FAIL;
3790 goto done;
3793 if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3794 WARN("RegSetValue failed\n");
3795 res = REGDB_E_WRITEREGDB;
3796 goto done;
3801 done:
3802 if (hkey) RegCloseKey(hkey);
3803 return res;
3806 /******************************************************************************
3807 * CoGetTreatAsClass [OLE32.@]
3809 * Gets the TreatAs value of a class.
3811 * PARAMS
3812 * clsidOld [I] Class to get the TreatAs value of.
3813 * clsidNew [I] The class the clsidOld should be treated as.
3815 * RETURNS
3816 * Success: S_OK.
3817 * Failure: HRESULT code.
3819 * SEE ALSO
3820 * CoSetTreatAsClass
3822 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3824 static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3825 HKEY hkey = NULL;
3826 WCHAR szClsidNew[CHARS_IN_GUID];
3827 HRESULT res = S_OK;
3828 LONG len = sizeof(szClsidNew);
3830 TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3831 *clsidNew = *clsidOld; /* copy over old value */
3833 res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3834 if (FAILED(res))
3836 res = S_FALSE;
3837 goto done;
3839 if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3841 res = S_FALSE;
3842 goto done;
3844 res = CLSIDFromString(szClsidNew,clsidNew);
3845 if (FAILED(res))
3846 ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3847 done:
3848 if (hkey) RegCloseKey(hkey);
3849 return res;
3852 /******************************************************************************
3853 * CoGetCurrentProcess [OLE32.@]
3855 * Gets the current process ID.
3857 * RETURNS
3858 * The current process ID.
3860 * NOTES
3861 * Is DWORD really the correct return type for this function?
3863 DWORD WINAPI CoGetCurrentProcess(void)
3865 return GetCurrentProcessId();
3868 /******************************************************************************
3869 * CoRegisterMessageFilter [OLE32.@]
3871 * Registers a message filter.
3873 * PARAMS
3874 * lpMessageFilter [I] Pointer to interface.
3875 * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3877 * RETURNS
3878 * Success: S_OK.
3879 * Failure: HRESULT code.
3881 * NOTES
3882 * Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3883 * lpMessageFilter removes the message filter.
3885 * If lplpMessageFilter is not NULL the previous message filter will be
3886 * returned in the memory pointer to this parameter and the caller is
3887 * responsible for releasing the object.
3889 * The current thread be in an apartment otherwise the function will crash.
3891 HRESULT WINAPI CoRegisterMessageFilter(
3892 LPMESSAGEFILTER lpMessageFilter,
3893 LPMESSAGEFILTER *lplpMessageFilter)
3895 struct apartment *apt;
3896 IMessageFilter *lpOldMessageFilter;
3898 TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3900 apt = COM_CurrentApt();
3902 /* can't set a message filter in a multi-threaded apartment */
3903 if (!apt || apt->multi_threaded)
3905 WARN("can't set message filter in MTA or uninitialized apt\n");
3906 return CO_E_NOT_SUPPORTED;
3909 if (lpMessageFilter)
3910 IMessageFilter_AddRef(lpMessageFilter);
3912 EnterCriticalSection(&apt->cs);
3914 lpOldMessageFilter = apt->filter;
3915 apt->filter = lpMessageFilter;
3917 LeaveCriticalSection(&apt->cs);
3919 if (lplpMessageFilter)
3920 *lplpMessageFilter = lpOldMessageFilter;
3921 else if (lpOldMessageFilter)
3922 IMessageFilter_Release(lpOldMessageFilter);
3924 return S_OK;
3927 /***********************************************************************
3928 * CoIsOle1Class [OLE32.@]
3930 * Determines whether the specified class an OLE v1 class.
3932 * PARAMS
3933 * clsid [I] Class to test.
3935 * RETURNS
3936 * TRUE if the class is an OLE v1 class, or FALSE otherwise.
3938 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3940 FIXME("%s\n", debugstr_guid(clsid));
3941 return FALSE;
3944 /***********************************************************************
3945 * IsEqualGUID [OLE32.@]
3947 * Compares two Unique Identifiers.
3949 * PARAMS
3950 * rguid1 [I] The first GUID to compare.
3951 * rguid2 [I] The other GUID to compare.
3953 * RETURNS
3954 * TRUE if equal
3956 #undef IsEqualGUID
3957 BOOL WINAPI IsEqualGUID(
3958 REFGUID rguid1,
3959 REFGUID rguid2)
3961 return !memcmp(rguid1,rguid2,sizeof(GUID));
3964 /***********************************************************************
3965 * CoInitializeSecurity [OLE32.@]
3967 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3968 SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3969 void* pReserved1, DWORD dwAuthnLevel,
3970 DWORD dwImpLevel, void* pReserved2,
3971 DWORD dwCapabilities, void* pReserved3)
3973 FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3974 asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3975 dwCapabilities, pReserved3);
3976 return S_OK;
3979 /***********************************************************************
3980 * CoSuspendClassObjects [OLE32.@]
3982 * Suspends all registered class objects to prevent further requests coming in
3983 * for those objects.
3985 * RETURNS
3986 * Success: S_OK.
3987 * Failure: HRESULT code.
3989 HRESULT WINAPI CoSuspendClassObjects(void)
3991 FIXME("\n");
3992 return S_OK;
3995 /***********************************************************************
3996 * CoAddRefServerProcess [OLE32.@]
3998 * Helper function for incrementing the reference count of a local-server
3999 * process.
4001 * RETURNS
4002 * New reference count.
4004 * SEE ALSO
4005 * CoReleaseServerProcess().
4007 ULONG WINAPI CoAddRefServerProcess(void)
4009 ULONG refs;
4011 TRACE("\n");
4013 EnterCriticalSection(&csRegisteredClassList);
4014 refs = ++s_COMServerProcessReferences;
4015 LeaveCriticalSection(&csRegisteredClassList);
4017 TRACE("refs before: %d\n", refs - 1);
4019 return refs;
4022 /***********************************************************************
4023 * CoReleaseServerProcess [OLE32.@]
4025 * Helper function for decrementing the reference count of a local-server
4026 * process.
4028 * RETURNS
4029 * New reference count.
4031 * NOTES
4032 * When reference count reaches 0, this function suspends all registered
4033 * classes so no new connections are accepted.
4035 * SEE ALSO
4036 * CoAddRefServerProcess(), CoSuspendClassObjects().
4038 ULONG WINAPI CoReleaseServerProcess(void)
4040 ULONG refs;
4042 TRACE("\n");
4044 EnterCriticalSection(&csRegisteredClassList);
4046 refs = --s_COMServerProcessReferences;
4047 /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4049 LeaveCriticalSection(&csRegisteredClassList);
4051 TRACE("refs after: %d\n", refs);
4053 return refs;
4056 /***********************************************************************
4057 * CoIsHandlerConnected [OLE32.@]
4059 * Determines whether a proxy is connected to a remote stub.
4061 * PARAMS
4062 * pUnk [I] Pointer to object that may or may not be connected.
4064 * RETURNS
4065 * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4066 * FALSE otherwise.
4068 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4070 FIXME("%p\n", pUnk);
4072 return TRUE;
4075 /***********************************************************************
4076 * CoAllowSetForegroundWindow [OLE32.@]
4079 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4081 FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4082 return S_OK;
4085 /***********************************************************************
4086 * CoQueryProxyBlanket [OLE32.@]
4088 * Retrieves the security settings being used by a proxy.
4090 * PARAMS
4091 * pProxy [I] Pointer to the proxy object.
4092 * pAuthnSvc [O] The type of authentication service.
4093 * pAuthzSvc [O] The type of authorization service.
4094 * ppServerPrincName [O] Optional. The server prinicple name.
4095 * pAuthnLevel [O] The authentication level.
4096 * pImpLevel [O] The impersonation level.
4097 * ppAuthInfo [O] Information specific to the authorization/authentication service.
4098 * pCapabilities [O] Flags affecting the security behaviour.
4100 * RETURNS
4101 * Success: S_OK.
4102 * Failure: HRESULT code.
4104 * SEE ALSO
4105 * CoCopyProxy, CoSetProxyBlanket.
4107 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4108 DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4109 DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4111 IClientSecurity *pCliSec;
4112 HRESULT hr;
4114 TRACE("%p\n", pProxy);
4116 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4117 if (SUCCEEDED(hr))
4119 hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4120 pAuthzSvc, ppServerPrincName,
4121 pAuthnLevel, pImpLevel, ppAuthInfo,
4122 pCapabilities);
4123 IClientSecurity_Release(pCliSec);
4126 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4127 return hr;
4130 /***********************************************************************
4131 * CoSetProxyBlanket [OLE32.@]
4133 * Sets the security settings for a proxy.
4135 * PARAMS
4136 * pProxy [I] Pointer to the proxy object.
4137 * AuthnSvc [I] The type of authentication service.
4138 * AuthzSvc [I] The type of authorization service.
4139 * pServerPrincName [I] The server prinicple name.
4140 * AuthnLevel [I] The authentication level.
4141 * ImpLevel [I] The impersonation level.
4142 * pAuthInfo [I] Information specific to the authorization/authentication service.
4143 * Capabilities [I] Flags affecting the security behaviour.
4145 * RETURNS
4146 * Success: S_OK.
4147 * Failure: HRESULT code.
4149 * SEE ALSO
4150 * CoQueryProxyBlanket, CoCopyProxy.
4152 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4153 DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4154 DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4156 IClientSecurity *pCliSec;
4157 HRESULT hr;
4159 TRACE("%p\n", pProxy);
4161 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4162 if (SUCCEEDED(hr))
4164 hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4165 AuthzSvc, pServerPrincName,
4166 AuthnLevel, ImpLevel, pAuthInfo,
4167 Capabilities);
4168 IClientSecurity_Release(pCliSec);
4171 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4172 return hr;
4175 /***********************************************************************
4176 * CoCopyProxy [OLE32.@]
4178 * Copies a proxy.
4180 * PARAMS
4181 * pProxy [I] Pointer to the proxy object.
4182 * ppCopy [O] Copy of the proxy.
4184 * RETURNS
4185 * Success: S_OK.
4186 * Failure: HRESULT code.
4188 * SEE ALSO
4189 * CoQueryProxyBlanket, CoSetProxyBlanket.
4191 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4193 IClientSecurity *pCliSec;
4194 HRESULT hr;
4196 TRACE("%p\n", pProxy);
4198 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4199 if (SUCCEEDED(hr))
4201 hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4202 IClientSecurity_Release(pCliSec);
4205 if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4206 return hr;
4210 /***********************************************************************
4211 * CoGetCallContext [OLE32.@]
4213 * Gets the context of the currently executing server call in the current
4214 * thread.
4216 * PARAMS
4217 * riid [I] Context interface to return.
4218 * ppv [O] Pointer to memory that will receive the context on return.
4220 * RETURNS
4221 * Success: S_OK.
4222 * Failure: HRESULT code.
4224 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4226 struct oletls *info = COM_CurrentInfo();
4228 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4230 if (!info)
4231 return E_OUTOFMEMORY;
4233 if (!info->call_state)
4234 return RPC_E_CALL_COMPLETE;
4236 return IUnknown_QueryInterface(info->call_state, riid, ppv);
4239 /***********************************************************************
4240 * CoSwitchCallContext [OLE32.@]
4242 * Switches the context of the currently executing server call in the current
4243 * thread.
4245 * PARAMS
4246 * pObject [I] Pointer to new context object
4247 * ppOldObject [O] Pointer to memory that will receive old context object pointer
4249 * RETURNS
4250 * Success: S_OK.
4251 * Failure: HRESULT code.
4253 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4255 struct oletls *info = COM_CurrentInfo();
4257 TRACE("(%p, %p)\n", pObject, ppOldObject);
4259 if (!info)
4260 return E_OUTOFMEMORY;
4262 *ppOldObject = info->call_state;
4263 info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4265 return S_OK;
4268 /***********************************************************************
4269 * CoQueryClientBlanket [OLE32.@]
4271 * Retrieves the authentication information about the client of the currently
4272 * executing server call in the current thread.
4274 * PARAMS
4275 * pAuthnSvc [O] Optional. The type of authentication service.
4276 * pAuthzSvc [O] Optional. The type of authorization service.
4277 * pServerPrincName [O] Optional. The server prinicple name.
4278 * pAuthnLevel [O] Optional. The authentication level.
4279 * pImpLevel [O] Optional. The impersonation level.
4280 * pPrivs [O] Optional. Information about the privileges of the client.
4281 * pCapabilities [IO] Optional. Flags affecting the security behaviour.
4283 * RETURNS
4284 * Success: S_OK.
4285 * Failure: HRESULT code.
4287 * SEE ALSO
4288 * CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4290 HRESULT WINAPI CoQueryClientBlanket(
4291 DWORD *pAuthnSvc,
4292 DWORD *pAuthzSvc,
4293 OLECHAR **pServerPrincName,
4294 DWORD *pAuthnLevel,
4295 DWORD *pImpLevel,
4296 RPC_AUTHZ_HANDLE *pPrivs,
4297 DWORD *pCapabilities)
4299 IServerSecurity *pSrvSec;
4300 HRESULT hr;
4302 TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4303 pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4304 pPrivs, pCapabilities);
4306 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4307 if (SUCCEEDED(hr))
4309 hr = IServerSecurity_QueryBlanket(
4310 pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4311 pImpLevel, pPrivs, pCapabilities);
4312 IServerSecurity_Release(pSrvSec);
4315 return hr;
4318 /***********************************************************************
4319 * CoImpersonateClient [OLE32.@]
4321 * Impersonates the client of the currently executing server call in the
4322 * current thread.
4324 * PARAMS
4325 * None.
4327 * RETURNS
4328 * Success: S_OK.
4329 * Failure: HRESULT code.
4331 * NOTES
4332 * If this function fails then the current thread will not be impersonating
4333 * the client and all actions will take place on behalf of the server.
4334 * Therefore, it is important to check the return value from this function.
4336 * SEE ALSO
4337 * CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4339 HRESULT WINAPI CoImpersonateClient(void)
4341 IServerSecurity *pSrvSec;
4342 HRESULT hr;
4344 TRACE("\n");
4346 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4347 if (SUCCEEDED(hr))
4349 hr = IServerSecurity_ImpersonateClient(pSrvSec);
4350 IServerSecurity_Release(pSrvSec);
4353 return hr;
4356 /***********************************************************************
4357 * CoRevertToSelf [OLE32.@]
4359 * Ends the impersonation of the client of the currently executing server
4360 * call in the current thread.
4362 * PARAMS
4363 * None.
4365 * RETURNS
4366 * Success: S_OK.
4367 * Failure: HRESULT code.
4369 * SEE ALSO
4370 * CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4372 HRESULT WINAPI CoRevertToSelf(void)
4374 IServerSecurity *pSrvSec;
4375 HRESULT hr;
4377 TRACE("\n");
4379 hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4380 if (SUCCEEDED(hr))
4382 hr = IServerSecurity_RevertToSelf(pSrvSec);
4383 IServerSecurity_Release(pSrvSec);
4386 return hr;
4389 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4391 /* first try to retrieve messages for incoming COM calls to the apartment window */
4392 return PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD) ||
4393 /* next retrieve other messages necessary for the app to remain responsive */
4394 PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4395 PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4398 /***********************************************************************
4399 * CoWaitForMultipleHandles [OLE32.@]
4401 * Waits for one or more handles to become signaled.
4403 * PARAMS
4404 * dwFlags [I] Flags. See notes.
4405 * dwTimeout [I] Timeout in milliseconds.
4406 * cHandles [I] Number of handles pointed to by pHandles.
4407 * pHandles [I] Handles to wait for.
4408 * lpdwindex [O] Index of handle that was signaled.
4410 * RETURNS
4411 * Success: S_OK.
4412 * Failure: RPC_S_CALLPENDING on timeout.
4414 * NOTES
4416 * The dwFlags parameter can be zero or more of the following:
4417 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4418 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4420 * SEE ALSO
4421 * MsgWaitForMultipleObjects, WaitForMultipleObjects.
4423 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4424 ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4426 HRESULT hr = S_OK;
4427 DWORD start_time = GetTickCount();
4428 APARTMENT *apt = COM_CurrentApt();
4429 BOOL message_loop = apt && !apt->multi_threaded;
4431 TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4432 pHandles, lpdwindex);
4434 while (TRUE)
4436 DWORD now = GetTickCount();
4437 DWORD res;
4439 if (now - start_time > dwTimeout)
4441 hr = RPC_S_CALLPENDING;
4442 break;
4445 if (message_loop)
4447 DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4448 ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4450 TRACE("waiting for rpc completion or window message\n");
4452 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4453 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4454 QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4456 if (res == WAIT_OBJECT_0 + cHandles) /* messages available */
4458 MSG msg;
4459 int count = 0;
4461 /* call message filter */
4463 if (COM_CurrentApt()->filter)
4465 PENDINGTYPE pendingtype =
4466 COM_CurrentInfo()->pending_call_count_server ?
4467 PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4468 DWORD be_handled = IMessageFilter_MessagePending(
4469 COM_CurrentApt()->filter, 0 /* FIXME */,
4470 now - start_time, pendingtype);
4471 TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4472 switch (be_handled)
4474 case PENDINGMSG_CANCELCALL:
4475 WARN("call canceled\n");
4476 hr = RPC_E_CALL_CANCELED;
4477 break;
4478 case PENDINGMSG_WAITNOPROCESS:
4479 case PENDINGMSG_WAITDEFPROCESS:
4480 default:
4481 /* FIXME: MSDN is very vague about the difference
4482 * between WAITNOPROCESS and WAITDEFPROCESS - there
4483 * appears to be none, so it is possibly a left-over
4484 * from the 16-bit world. */
4485 break;
4489 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4490 * so after processing 100 messages we go back to checking the wait handles */
4491 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4493 TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4494 TranslateMessage(&msg);
4495 DispatchMessageW(&msg);
4496 if (msg.message == WM_QUIT)
4498 TRACE("resending WM_QUIT to outer message loop\n");
4499 PostQuitMessage(msg.wParam);
4500 /* no longer need to process messages */
4501 message_loop = FALSE;
4502 break;
4505 continue;
4508 else
4510 TRACE("waiting for rpc completion\n");
4512 res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4513 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4514 (dwFlags & COWAIT_ALERTABLE) != 0);
4517 switch (res)
4519 case WAIT_TIMEOUT:
4520 hr = RPC_S_CALLPENDING;
4521 break;
4522 case WAIT_FAILED:
4523 hr = HRESULT_FROM_WIN32( GetLastError() );
4524 break;
4525 default:
4526 *lpdwindex = res;
4527 break;
4529 break;
4531 TRACE("-- 0x%08x\n", hr);
4532 return hr;
4536 /***********************************************************************
4537 * CoGetObject [OLE32.@]
4539 * Gets the object named by converting the name to a moniker and binding to it.
4541 * PARAMS
4542 * pszName [I] String representing the object.
4543 * pBindOptions [I] Parameters affecting the binding to the named object.
4544 * riid [I] Interface to bind to on the objecct.
4545 * ppv [O] On output, the interface riid of the object represented
4546 * by pszName.
4548 * RETURNS
4549 * Success: S_OK.
4550 * Failure: HRESULT code.
4552 * SEE ALSO
4553 * MkParseDisplayName.
4555 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4556 REFIID riid, void **ppv)
4558 IBindCtx *pbc;
4559 HRESULT hr;
4561 *ppv = NULL;
4563 hr = CreateBindCtx(0, &pbc);
4564 if (SUCCEEDED(hr))
4566 if (pBindOptions)
4567 hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4569 if (SUCCEEDED(hr))
4571 ULONG chEaten;
4572 IMoniker *pmk;
4574 hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4575 if (SUCCEEDED(hr))
4577 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4578 IMoniker_Release(pmk);
4582 IBindCtx_Release(pbc);
4584 return hr;
4587 /***********************************************************************
4588 * CoRegisterChannelHook [OLE32.@]
4590 * Registers a process-wide hook that is called during ORPC calls.
4592 * PARAMS
4593 * guidExtension [I] GUID of the channel hook to register.
4594 * pChannelHook [I] Channel hook object to register.
4596 * RETURNS
4597 * Success: S_OK.
4598 * Failure: HRESULT code.
4600 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4602 TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4604 return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4607 typedef struct Context
4609 IComThreadingInfo IComThreadingInfo_iface;
4610 IContextCallback IContextCallback_iface;
4611 IObjContext IObjContext_iface;
4612 LONG refs;
4613 APTTYPE apttype;
4614 } Context;
4616 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4618 return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4621 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4623 return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4626 static inline Context *impl_from_IObjContext( IObjContext *iface )
4628 return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4631 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4633 *ppv = NULL;
4635 if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4636 IsEqualIID(riid, &IID_IUnknown))
4638 *ppv = &iface->IComThreadingInfo_iface;
4640 else if (IsEqualIID(riid, &IID_IContextCallback))
4642 *ppv = &iface->IContextCallback_iface;
4644 else if (IsEqualIID(riid, &IID_IObjContext))
4646 *ppv = &iface->IObjContext_iface;
4649 if (*ppv)
4651 IUnknown_AddRef((IUnknown*)*ppv);
4652 return S_OK;
4655 FIXME("interface not implemented %s\n", debugstr_guid(riid));
4656 return E_NOINTERFACE;
4659 static ULONG Context_AddRef(Context *This)
4661 return InterlockedIncrement(&This->refs);
4664 static ULONG Context_Release(Context *This)
4666 ULONG refs = InterlockedDecrement(&This->refs);
4667 if (!refs)
4668 HeapFree(GetProcessHeap(), 0, This);
4669 return refs;
4672 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4674 Context *This = impl_from_IComThreadingInfo(iface);
4675 return Context_QueryInterface(This, riid, ppv);
4678 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4680 Context *This = impl_from_IComThreadingInfo(iface);
4681 return Context_AddRef(This);
4684 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4686 Context *This = impl_from_IComThreadingInfo(iface);
4687 return Context_Release(This);
4690 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4692 Context *This = impl_from_IComThreadingInfo(iface);
4694 TRACE("(%p)\n", apttype);
4696 *apttype = This->apttype;
4697 return S_OK;
4700 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4702 Context *This = impl_from_IComThreadingInfo(iface);
4704 TRACE("(%p)\n", thdtype);
4706 switch (This->apttype)
4708 case APTTYPE_STA:
4709 case APTTYPE_MAINSTA:
4710 *thdtype = THDTYPE_PROCESSMESSAGES;
4711 break;
4712 default:
4713 *thdtype = THDTYPE_BLOCKMESSAGES;
4714 break;
4716 return S_OK;
4719 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4721 FIXME("(%p): stub\n", logical_thread_id);
4722 return E_NOTIMPL;
4725 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4727 FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4728 return E_NOTIMPL;
4731 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4733 Context_CTI_QueryInterface,
4734 Context_CTI_AddRef,
4735 Context_CTI_Release,
4736 Context_CTI_GetCurrentApartmentType,
4737 Context_CTI_GetCurrentThreadType,
4738 Context_CTI_GetCurrentLogicalThreadId,
4739 Context_CTI_SetCurrentLogicalThreadId
4742 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4744 Context *This = impl_from_IContextCallback(iface);
4745 return Context_QueryInterface(This, riid, ppv);
4748 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4750 Context *This = impl_from_IContextCallback(iface);
4751 return Context_AddRef(This);
4754 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4756 Context *This = impl_from_IContextCallback(iface);
4757 return Context_Release(This);
4760 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4761 ComCallData *param, REFIID riid, int method, IUnknown *punk)
4763 Context *This = impl_from_IContextCallback(iface);
4765 FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4766 return E_NOTIMPL;
4769 static const IContextCallbackVtbl Context_Callback_Vtbl =
4771 Context_CC_QueryInterface,
4772 Context_CC_AddRef,
4773 Context_CC_Release,
4774 Context_CC_ContextCallback
4777 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4779 Context *This = impl_from_IObjContext(iface);
4780 return Context_QueryInterface(This, riid, ppv);
4783 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4785 Context *This = impl_from_IObjContext(iface);
4786 return Context_AddRef(This);
4789 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4791 Context *This = impl_from_IObjContext(iface);
4792 return Context_Release(This);
4795 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4797 Context *This = impl_from_IObjContext(iface);
4799 FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4800 return E_NOTIMPL;
4803 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4805 Context *This = impl_from_IObjContext(iface);
4807 FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4808 return E_NOTIMPL;
4811 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4813 Context *This = impl_from_IObjContext(iface);
4815 FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4816 return E_NOTIMPL;
4819 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4821 Context *This = impl_from_IObjContext(iface);
4823 FIXME("(%p/%p)->(%p)\n", This, iface, props);
4824 return E_NOTIMPL;
4827 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4829 Context *This = impl_from_IObjContext(iface);
4830 FIXME("(%p/%p)\n", This, iface);
4833 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4835 Context *This = impl_from_IObjContext(iface);
4836 FIXME("(%p/%p)\n", This, iface);
4839 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4841 Context *This = impl_from_IObjContext(iface);
4842 FIXME("(%p/%p)\n", This, iface);
4845 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4847 Context *This = impl_from_IObjContext(iface);
4848 FIXME("(%p/%p)\n", This, iface);
4851 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4853 Context *This = impl_from_IObjContext(iface);
4854 FIXME("(%p/%p)\n", This, iface);
4857 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4859 Context *This = impl_from_IObjContext(iface);
4860 FIXME("(%p/%p)\n", This, iface);
4863 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4865 Context *This = impl_from_IObjContext(iface);
4866 FIXME("(%p/%p)\n", This, iface);
4869 static const IObjContextVtbl Context_Object_Vtbl =
4871 Context_OC_QueryInterface,
4872 Context_OC_AddRef,
4873 Context_OC_Release,
4874 Context_OC_SetProperty,
4875 Context_OC_RemoveProperty,
4876 Context_OC_GetProperty,
4877 Context_OC_EnumContextProps,
4878 Context_OC_Reserved1,
4879 Context_OC_Reserved2,
4880 Context_OC_Reserved3,
4881 Context_OC_Reserved4,
4882 Context_OC_Reserved5,
4883 Context_OC_Reserved6,
4884 Context_OC_Reserved7
4887 /***********************************************************************
4888 * CoGetObjectContext [OLE32.@]
4890 * Retrieves an object associated with the current context (i.e. apartment).
4892 * PARAMS
4893 * riid [I] ID of the interface of the object to retrieve.
4894 * ppv [O] Address where object will be stored on return.
4896 * RETURNS
4897 * Success: S_OK.
4898 * Failure: HRESULT code.
4900 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4902 APARTMENT *apt = COM_CurrentApt();
4903 Context *context;
4904 HRESULT hr;
4906 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4908 *ppv = NULL;
4909 if (!apt)
4911 if (!(apt = apartment_find_multi_threaded()))
4913 ERR("apartment not initialised\n");
4914 return CO_E_NOTINITIALIZED;
4916 apartment_release(apt);
4919 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4920 if (!context)
4921 return E_OUTOFMEMORY;
4923 context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4924 context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4925 context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4926 context->refs = 1;
4927 if (apt->multi_threaded)
4928 context->apttype = APTTYPE_MTA;
4929 else if (apt->main)
4930 context->apttype = APTTYPE_MAINSTA;
4931 else
4932 context->apttype = APTTYPE_STA;
4934 hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4935 IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4937 return hr;
4941 /***********************************************************************
4942 * CoGetContextToken [OLE32.@]
4944 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4946 struct oletls *info = COM_CurrentInfo();
4948 TRACE("(%p)\n", token);
4950 if (!info)
4951 return E_OUTOFMEMORY;
4953 if (!info->apt)
4955 APARTMENT *apt;
4956 if (!(apt = apartment_find_multi_threaded()))
4958 ERR("apartment not initialised\n");
4959 return CO_E_NOTINITIALIZED;
4961 apartment_release(apt);
4964 if (!token)
4965 return E_POINTER;
4967 if (!info->context_token)
4969 HRESULT hr;
4970 IObjContext *ctx;
4972 hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4973 if (FAILED(hr)) return hr;
4974 info->context_token = ctx;
4977 *token = (ULONG_PTR)info->context_token;
4978 TRACE("apt->context_token=%p\n", info->context_token);
4980 return S_OK;
4983 /***********************************************************************
4984 * CoGetDefaultContext [OLE32.@]
4986 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
4988 FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
4989 return E_NOINTERFACE;
4992 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4994 static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4995 HKEY hkey;
4996 HRESULT hres;
4998 hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4999 if (SUCCEEDED(hres))
5001 struct class_reg_data regdata;
5002 WCHAR dllpath[MAX_PATH+1];
5004 regdata.u.hkey = hkey;
5005 regdata.hkey = TRUE;
5007 if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
5009 static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5010 if (!strcmpiW(dllpath, wszOle32))
5012 RegCloseKey(hkey);
5013 return HandlerCF_Create(rclsid, riid, ppv);
5016 else
5017 WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5018 RegCloseKey(hkey);
5021 return CLASS_E_CLASSNOTAVAILABLE;
5024 /***********************************************************************
5025 * DllMain (OLE32.@)
5027 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5029 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5031 switch(fdwReason) {
5032 case DLL_PROCESS_ATTACH:
5033 hProxyDll = hinstDLL;
5034 break;
5036 case DLL_PROCESS_DETACH:
5037 if (reserved) break;
5038 release_std_git();
5039 UnregisterClassW( wszAptWinClass, hProxyDll );
5040 RPC_UnregisterAllChannelHooks();
5041 COMPOBJ_DllList_Free();
5042 DeleteCriticalSection(&csRegisteredClassList);
5043 DeleteCriticalSection(&csApartment);
5044 break;
5046 case DLL_THREAD_DETACH:
5047 COM_TlsDestroy();
5048 break;
5050 return TRUE;
5053 /***********************************************************************
5054 * DllRegisterServer (OLE32.@)
5056 HRESULT WINAPI DllRegisterServer(void)
5058 return OLE32_DllRegisterServer();
5061 /***********************************************************************
5062 * DllUnregisterServer (OLE32.@)
5064 HRESULT WINAPI DllUnregisterServer(void)
5066 return OLE32_DllUnregisterServer();