xref: /reactos/dll/win32/ole32/compobj.c (revision 64daf542)
1 /*
2  *	COMPOBJ library
3  *
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)
11  *
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.
16  *
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.
21  *
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
25  *
26  * Note
27  * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28  *    Therefore do not test against COINIT_MULTITHREADED
29  *
30  * TODO list:           (items bunched together depend on each other)
31  *
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
36  *
37  */
38 
39 #include "precomp.h"
40 
41 #include <ctxtcall.h>
42 #include <dde.h>
43 
44 WINE_DEFAULT_DEBUG_CHANNEL(ole);
45 
46 #undef ARRAYSIZE
47 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
48 
49 /****************************************************************************
50  * This section defines variables internal to the COM module.
51  */
52 
53 static APARTMENT *MTA; /* protected by csApartment */
54 static APARTMENT *MainApartment; /* the first STA apartment */
55 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
56 
57 static CRITICAL_SECTION csApartment;
58 static CRITICAL_SECTION_DEBUG critsect_debug =
59 {
60     0, 0, &csApartment,
61     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
62       0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
63 };
64 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
65 
66 enum comclass_threadingmodel
67 {
68     ThreadingModel_Apartment = 1,
69     ThreadingModel_Free      = 2,
70     ThreadingModel_No        = 3,
71     ThreadingModel_Both      = 4,
72     ThreadingModel_Neutral   = 5
73 };
74 
75 enum comclass_miscfields
76 {
77     MiscStatus          = 1,
78     MiscStatusIcon      = 2,
79     MiscStatusContent   = 4,
80     MiscStatusThumbnail = 8,
81     MiscStatusDocPrint  = 16
82 };
83 
84 struct comclassredirect_data
85 {
86     ULONG size;
87     BYTE  res;
88     BYTE  miscmask;
89     BYTE  res1[2];
90     DWORD model;
91     GUID  clsid;
92     GUID  alias;
93     GUID  clsid2;
94     GUID  tlbid;
95     ULONG name_len;
96     ULONG name_offset;
97     ULONG progid_len;
98     ULONG progid_offset;
99     ULONG clrdata_len;
100     ULONG clrdata_offset;
101     DWORD miscstatus;
102     DWORD miscstatuscontent;
103     DWORD miscstatusthumbnail;
104     DWORD miscstatusicon;
105     DWORD miscstatusdocprint;
106 };
107 
108 struct ifacepsredirect_data
109 {
110     ULONG size;
111     DWORD mask;
112     GUID  iid;
113     ULONG nummethods;
114     GUID  tlbid;
115     GUID  base;
116     ULONG name_len;
117     ULONG name_offset;
118 };
119 
120 struct progidredirect_data
121 {
122     ULONG size;
123     DWORD reserved;
124     ULONG clsid_offset;
125 };
126 
127 struct class_reg_data
128 {
129     union
130     {
131         struct
132         {
133             struct comclassredirect_data *data;
134             void *section;
135             HANDLE hactctx;
136         } actctx;
137         HKEY hkey;
138     } u;
139     BOOL hkey;
140 };
141 
142 struct registered_psclsid
143 {
144     struct list entry;
145     IID iid;
146     CLSID clsid;
147 };
148 
149 static struct list registered_psclsid_list = LIST_INIT(registered_psclsid_list);
150 
151 static CRITICAL_SECTION cs_registered_psclsid_list;
152 static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
153 {
154     0, 0, &cs_registered_psclsid_list,
155     { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
156       0, 0, { (DWORD_PTR)(__FILE__ ": cs_registered_psclsid_list") }
157 };
158 static CRITICAL_SECTION cs_registered_psclsid_list = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
159 
160 /*
161  * This is a marshallable object exposing registered local servers.
162  * IServiceProvider is used only because it happens meet requirements
163  * and already has proxy/stub code. If more functionality is needed,
164  * a custom interface may be used instead.
165  */
166 struct LocalServer
167 {
168     IServiceProvider IServiceProvider_iface;
169     LONG ref;
170     APARTMENT *apt;
171     IStream *marshal_stream;
172 };
173 
174 /*
175  * This lock count counts the number of times CoInitialize is called. It is
176  * decreased every time CoUninitialize is called. When it hits 0, the COM
177  * libraries are freed
178  */
179 static LONG s_COMLockCount = 0;
180 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
181 static LONG s_COMServerProcessReferences = 0;
182 
183 /*
184  * This linked list contains the list of registered class objects. These
185  * are mostly used to register the factories for out-of-proc servers of OLE
186  * objects.
187  *
188  * TODO: Make this data structure aware of inter-process communication. This
189  *       means that parts of this will be exported to rpcss.
190  */
191 typedef struct tagRegisteredClass
192 {
193   struct list entry;
194   CLSID     classIdentifier;
195   OXID      apartment_id;
196   LPUNKNOWN classObject;
197   DWORD     runContext;
198   DWORD     connectFlags;
199   DWORD     dwCookie;
200   void     *RpcRegistration;
201 } RegisteredClass;
202 
203 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
204 
205 static CRITICAL_SECTION csRegisteredClassList;
206 static CRITICAL_SECTION_DEBUG class_cs_debug =
207 {
208     0, 0, &csRegisteredClassList,
209     { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
210       0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
211 };
212 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
213 
214 static inline enum comclass_miscfields dvaspect_to_miscfields(DWORD aspect)
215 {
216     switch (aspect)
217     {
218     case DVASPECT_CONTENT:
219         return MiscStatusContent;
220     case DVASPECT_THUMBNAIL:
221         return MiscStatusThumbnail;
222     case DVASPECT_ICON:
223         return MiscStatusIcon;
224     case DVASPECT_DOCPRINT:
225         return MiscStatusDocPrint;
226     default:
227         return MiscStatus;
228     };
229 }
230 
231 BOOL actctx_get_miscstatus(const CLSID *clsid, DWORD aspect, DWORD *status)
232 {
233     ACTCTX_SECTION_KEYED_DATA data;
234 
235     data.cbSize = sizeof(data);
236     if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
237                               clsid, &data))
238     {
239         struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
240         enum comclass_miscfields misc = dvaspect_to_miscfields(aspect);
241 
242         if (!(comclass->miscmask & misc))
243         {
244             if (!(comclass->miscmask & MiscStatus))
245             {
246                 *status = 0;
247                 return TRUE;
248             }
249             misc = MiscStatus;
250         }
251 
252         switch (misc)
253         {
254         case MiscStatus:
255             *status = comclass->miscstatus;
256             break;
257         case MiscStatusIcon:
258             *status = comclass->miscstatusicon;
259             break;
260         case MiscStatusContent:
261             *status = comclass->miscstatuscontent;
262             break;
263         case MiscStatusThumbnail:
264             *status = comclass->miscstatusthumbnail;
265             break;
266         case MiscStatusDocPrint:
267             *status = comclass->miscstatusdocprint;
268             break;
269         default:
270            ;
271         };
272 
273         return TRUE;
274     }
275     else
276         return FALSE;
277 }
278 
279 /* wrapper for NtCreateKey that creates the key recursively if necessary */
280 static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
281 {
282     NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
283 
284     if (status == STATUS_OBJECT_NAME_NOT_FOUND)
285     {
286         HANDLE subkey, root = attr->RootDirectory;
287         WCHAR *buffer = attr->ObjectName->Buffer;
288         DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
289         UNICODE_STRING str;
290 
291         while (i < len && buffer[i] != '\\') i++;
292         if (i == len) return status;
293 
294         attrs = attr->Attributes;
295         attr->ObjectName = &str;
296 
297         while (i < len)
298         {
299             str.Buffer = buffer + pos;
300             str.Length = (i - pos) * sizeof(WCHAR);
301             status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
302             if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
303             if (status) return status;
304             attr->RootDirectory = subkey;
305             while (i < len && buffer[i] == '\\') i++;
306             pos = i;
307             while (i < len && buffer[i] != '\\') i++;
308         }
309         str.Buffer = buffer + pos;
310         str.Length = (i - pos) * sizeof(WCHAR);
311         attr->Attributes = attrs;
312         status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
313         if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
314     }
315     return status;
316 }
317 
318 #ifdef __REACTOS__
319 static const WCHAR classes_rootW[] = L"\\REGISTRY\\Machine\\Software\\Classes";
320 #else
321 static const WCHAR classes_rootW[] =
322     {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',
323      '\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
324 #endif
325 
326 static HKEY classes_root_hkey;
327 
328 /* create the special HKEY_CLASSES_ROOT key */
329 static HKEY create_classes_root_hkey(DWORD access)
330 {
331     HKEY hkey, ret = 0;
332     OBJECT_ATTRIBUTES attr;
333     UNICODE_STRING name;
334 
335     attr.Length = sizeof(attr);
336     attr.RootDirectory = 0;
337     attr.ObjectName = &name;
338     attr.Attributes = 0;
339     attr.SecurityDescriptor = NULL;
340     attr.SecurityQualityOfService = NULL;
341     RtlInitUnicodeString( &name, classes_rootW );
342     if (create_key( &hkey, access, &attr )) return 0;
343     TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
344 
345     if (!(access & KEY_WOW64_64KEY))
346     {
347         if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
348             ret = hkey;
349         else
350             NtClose( hkey );  /* somebody beat us to it */
351     }
352     else
353         ret = hkey;
354     return ret;
355 }
356 
357 /* map the hkey from special root to normal key if necessary */
358 static inline HKEY get_classes_root_hkey( HKEY hkey, REGSAM access )
359 {
360     HKEY ret = hkey;
361     const BOOL is_win64 = sizeof(void*) > sizeof(int);
362     const BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY);
363 
364     if (hkey == HKEY_CLASSES_ROOT &&
365         ((access & KEY_WOW64_64KEY) || !(ret = classes_root_hkey)))
366         ret = create_classes_root_hkey(MAXIMUM_ALLOWED | (access & KEY_WOW64_64KEY));
367     if (force_wow32 && ret && ret == classes_root_hkey)
368     {
369         static const WCHAR wow6432nodeW[] = {'W','o','w','6','4','3','2','N','o','d','e',0};
370         access &= ~KEY_WOW64_32KEY;
371         if (create_classes_key(classes_root_hkey, wow6432nodeW, access, &hkey))
372             return 0;
373         ret = hkey;
374     }
375 
376     return ret;
377 }
378 
379 LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
380 {
381     OBJECT_ATTRIBUTES attr;
382     UNICODE_STRING nameW;
383 
384     if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
385 
386     attr.Length = sizeof(attr);
387     attr.RootDirectory = hkey;
388     attr.ObjectName = &nameW;
389     attr.Attributes = 0;
390     attr.SecurityDescriptor = NULL;
391     attr.SecurityQualityOfService = NULL;
392     RtlInitUnicodeString( &nameW, name );
393 
394     return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
395 }
396 
397 LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
398 {
399     OBJECT_ATTRIBUTES attr;
400     UNICODE_STRING nameW;
401 
402     if (!(hkey = get_classes_root_hkey( hkey, access ))) return ERROR_INVALID_HANDLE;
403 
404     attr.Length = sizeof(attr);
405     attr.RootDirectory = hkey;
406     attr.ObjectName = &nameW;
407     attr.Attributes = 0;
408     attr.SecurityDescriptor = NULL;
409     attr.SecurityQualityOfService = NULL;
410     RtlInitUnicodeString( &nameW, name );
411 
412     return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
413 }
414 
415 /*****************************************************************************
416  * This section contains OpenDllList definitions
417  *
418  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
419  * other functions that do LoadLibrary _without_ giving back a HMODULE.
420  * Without this list these handles would never be freed.
421  *
422  * FIXME: a DLL that says OK when asked for unloading is unloaded in the
423  * next unload-call but not before 600 sec.
424  */
425 
426 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
427 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
428 
429 typedef struct tagOpenDll
430 {
431   LONG refs;
432   LPWSTR library_name;
433   HANDLE library;
434   DllGetClassObjectFunc DllGetClassObject;
435   DllCanUnloadNowFunc DllCanUnloadNow;
436   struct list entry;
437 } OpenDll;
438 
439 static struct list openDllList = LIST_INIT(openDllList);
440 
441 static CRITICAL_SECTION csOpenDllList;
442 static CRITICAL_SECTION_DEBUG dll_cs_debug =
443 {
444     0, 0, &csOpenDllList,
445     { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
446       0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
447 };
448 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
449 
450 struct apartment_loaded_dll
451 {
452     struct list entry;
453     OpenDll *dll;
454     DWORD unload_time;
455     BOOL multi_threaded;
456 };
457 
458 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',0};
459 
460 /*****************************************************************************
461  * This section contains OpenDllList implementation
462  */
463 
464 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
465 {
466     OpenDll *ptr;
467     OpenDll *ret = NULL;
468     EnterCriticalSection(&csOpenDllList);
469     LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
470     {
471         if (!strcmpiW(library_name, ptr->library_name) &&
472             (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
473         {
474             ret = ptr;
475             break;
476         }
477     }
478     LeaveCriticalSection(&csOpenDllList);
479     return ret;
480 }
481 
482 /* caller must ensure that library_name is not already in the open dll list */
483 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
484 {
485     OpenDll *entry;
486     int len;
487     HRESULT hr = S_OK;
488     HANDLE hLibrary;
489     DllCanUnloadNowFunc DllCanUnloadNow;
490     DllGetClassObjectFunc DllGetClassObject;
491 
492     TRACE("%s\n", debugstr_w(library_name));
493 
494     *ret = COMPOBJ_DllList_Get(library_name);
495     if (*ret) return S_OK;
496 
497     /* do this outside the csOpenDllList to avoid creating a lock dependency on
498      * the loader lock */
499     hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
500     if (!hLibrary)
501     {
502         ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
503         /* failure: DLL could not be loaded */
504         return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
505     }
506 
507     DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
508     /* Note: failing to find DllCanUnloadNow is not a failure */
509     DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
510     if (!DllGetClassObject)
511     {
512         /* failure: the dll did not export DllGetClassObject */
513         ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
514         FreeLibrary(hLibrary);
515         return CO_E_DLLNOTFOUND;
516     }
517 
518     EnterCriticalSection( &csOpenDllList );
519 
520     *ret = COMPOBJ_DllList_Get(library_name);
521     if (*ret)
522     {
523         /* another caller to this function already added the dll while we
524          * weren't in the critical section */
525         FreeLibrary(hLibrary);
526     }
527     else
528     {
529         len = strlenW(library_name);
530         entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
531         if (entry)
532             entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
533         if (entry && entry->library_name)
534         {
535             memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
536             entry->library = hLibrary;
537             entry->refs = 1;
538             entry->DllCanUnloadNow = DllCanUnloadNow;
539             entry->DllGetClassObject = DllGetClassObject;
540             list_add_tail(&openDllList, &entry->entry);
541             *ret = entry;
542         }
543         else
544         {
545             HeapFree(GetProcessHeap(), 0, entry);
546             hr = E_OUTOFMEMORY;
547             FreeLibrary(hLibrary);
548         }
549     }
550 
551     LeaveCriticalSection( &csOpenDllList );
552 
553     return hr;
554 }
555 
556 /* pass FALSE for free_entry to release a reference without destroying the
557  * entry if it reaches zero or TRUE otherwise */
558 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
559 {
560     if (!InterlockedDecrement(&entry->refs) && free_entry)
561     {
562         EnterCriticalSection(&csOpenDllList);
563         list_remove(&entry->entry);
564         LeaveCriticalSection(&csOpenDllList);
565 
566         TRACE("freeing %p\n", entry->library);
567         FreeLibrary(entry->library);
568 
569         HeapFree(GetProcessHeap(), 0, entry->library_name);
570         HeapFree(GetProcessHeap(), 0, entry);
571     }
572 }
573 
574 /* frees memory associated with active dll list */
575 static void COMPOBJ_DllList_Free(void)
576 {
577     OpenDll *entry, *cursor2;
578     EnterCriticalSection(&csOpenDllList);
579     LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
580     {
581         list_remove(&entry->entry);
582 
583         HeapFree(GetProcessHeap(), 0, entry->library_name);
584         HeapFree(GetProcessHeap(), 0, entry);
585     }
586     LeaveCriticalSection(&csOpenDllList);
587     DeleteCriticalSection(&csOpenDllList);
588 }
589 
590 /******************************************************************************
591  * Manage apartments.
592  */
593 
594 static DWORD apartment_addref(struct apartment *apt)
595 {
596     DWORD refs = InterlockedIncrement(&apt->refs);
597     TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
598     return refs;
599 }
600 
601 /* allocates memory and fills in the necessary fields for a new apartment
602  * object. must be called inside apartment cs */
603 static APARTMENT *apartment_construct(DWORD model)
604 {
605     APARTMENT *apt;
606 
607     TRACE("creating new apartment, model=%d\n", model);
608 
609     apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
610     apt->tid = GetCurrentThreadId();
611 
612     list_init(&apt->proxies);
613     list_init(&apt->stubmgrs);
614     list_init(&apt->loaded_dlls);
615     apt->ipidc = 0;
616     apt->refs = 1;
617     apt->remunk_exported = FALSE;
618     apt->oidc = 1;
619     InitializeCriticalSection(&apt->cs);
620     DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
621 
622     apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
623 
624     if (apt->multi_threaded)
625     {
626         /* FIXME: should be randomly generated by in an RPC call to rpcss */
627         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
628     }
629     else
630     {
631         /* FIXME: should be randomly generated by in an RPC call to rpcss */
632         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
633     }
634 
635     TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
636 
637     list_add_head(&apts, &apt->entry);
638 
639     return apt;
640 }
641 
642 /* gets and existing apartment if one exists or otherwise creates an apartment
643  * structure which stores OLE apartment-local information and stores a pointer
644  * to it in the thread-local storage */
645 static APARTMENT *apartment_get_or_create(DWORD model)
646 {
647     APARTMENT *apt = COM_CurrentApt();
648 
649     if (!apt)
650     {
651         if (model & COINIT_APARTMENTTHREADED)
652         {
653             EnterCriticalSection(&csApartment);
654 
655             apt = apartment_construct(model);
656             if (!MainApartment)
657             {
658                 MainApartment = apt;
659                 apt->main = TRUE;
660                 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
661             }
662 
663             LeaveCriticalSection(&csApartment);
664 
665             if (apt->main)
666                 apartment_createwindowifneeded(apt);
667         }
668         else
669         {
670             EnterCriticalSection(&csApartment);
671 
672             /* The multi-threaded apartment (MTA) contains zero or more threads interacting
673              * with free threaded (ie thread safe) COM objects. There is only ever one MTA
674              * in a process */
675             if (MTA)
676             {
677                 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
678                 apartment_addref(MTA);
679             }
680             else
681                 MTA = apartment_construct(model);
682 
683             apt = MTA;
684 
685             LeaveCriticalSection(&csApartment);
686         }
687         COM_CurrentInfo()->apt = apt;
688     }
689 
690     return apt;
691 }
692 
693 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
694 {
695     return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
696 }
697 
698 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
699 {
700     list_remove(&curClass->entry);
701 
702     if (curClass->runContext & CLSCTX_LOCAL_SERVER)
703         RPC_StopLocalServer(curClass->RpcRegistration);
704 
705     IUnknown_Release(curClass->classObject);
706     HeapFree(GetProcessHeap(), 0, curClass);
707 }
708 
709 static void COM_RevokeAllClasses(const struct apartment *apt)
710 {
711   RegisteredClass *curClass, *cursor;
712 
713   EnterCriticalSection( &csRegisteredClassList );
714 
715   LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
716   {
717     if (curClass->apartment_id == apt->oxid)
718       COM_RevokeRegisteredClassObject(curClass);
719   }
720 
721   LeaveCriticalSection( &csRegisteredClassList );
722 }
723 
724 static void revoke_registered_psclsids(void)
725 {
726     struct registered_psclsid *psclsid, *psclsid2;
727 
728     EnterCriticalSection( &cs_registered_psclsid_list );
729 
730     LIST_FOR_EACH_ENTRY_SAFE(psclsid, psclsid2, &registered_psclsid_list, struct registered_psclsid, entry)
731     {
732         list_remove(&psclsid->entry);
733         HeapFree(GetProcessHeap(), 0, psclsid);
734     }
735 
736     LeaveCriticalSection( &cs_registered_psclsid_list );
737 }
738 
739 /******************************************************************************
740  * Implementation of the manual reset event object. (CLSID_ManualResetEvent)
741  */
742 
743 typedef struct ManualResetEvent {
744     ISynchronize        ISynchronize_iface;
745     ISynchronizeHandle  ISynchronizeHandle_iface;
746     LONG ref;
747     HANDLE event;
748 } MREImpl;
749 
750 static inline MREImpl *impl_from_ISynchronize(ISynchronize *iface)
751 {
752     return CONTAINING_RECORD(iface, MREImpl, ISynchronize_iface);
753 }
754 
755 static HRESULT WINAPI ISynchronize_fnQueryInterface(ISynchronize *iface, REFIID riid, void **ppv)
756 {
757     MREImpl *This = impl_from_ISynchronize(iface);
758 
759     TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppv);
760 
761     if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISynchronize)) {
762         *ppv = &This->ISynchronize_iface;
763     }else if(IsEqualGUID(riid, &IID_ISynchronizeHandle)) {
764         *ppv = &This->ISynchronizeHandle_iface;
765     }else {
766         ERR("Unknown interface %s requested.\n", debugstr_guid(riid));
767         *ppv = NULL;
768         return E_NOINTERFACE;
769     }
770 
771     IUnknown_AddRef((IUnknown*)*ppv);
772     return S_OK;
773 }
774 
775 static ULONG WINAPI ISynchronize_fnAddRef(ISynchronize *iface)
776 {
777     MREImpl *This = impl_from_ISynchronize(iface);
778     LONG ref = InterlockedIncrement(&This->ref);
779     TRACE("%p - ref %d\n", This, ref);
780 
781     return ref;
782 }
783 
784 static ULONG WINAPI ISynchronize_fnRelease(ISynchronize *iface)
785 {
786     MREImpl *This = impl_from_ISynchronize(iface);
787     LONG ref = InterlockedDecrement(&This->ref);
788     TRACE("%p - ref %d\n", This, ref);
789 
790     if(!ref)
791     {
792         CloseHandle(This->event);
793         HeapFree(GetProcessHeap(), 0, This);
794     }
795 
796     return ref;
797 }
798 
799 static HRESULT WINAPI ISynchronize_fnWait(ISynchronize *iface, DWORD dwFlags, DWORD dwMilliseconds)
800 {
801     MREImpl *This = impl_from_ISynchronize(iface);
802     UINT index;
803     TRACE("%p (%08x, %08x)\n", This, dwFlags, dwMilliseconds);
804     return CoWaitForMultipleHandles(dwFlags, dwMilliseconds, 1, &This->event, &index);
805 }
806 
807 static HRESULT WINAPI ISynchronize_fnSignal(ISynchronize *iface)
808 {
809     MREImpl *This = impl_from_ISynchronize(iface);
810     TRACE("%p\n", This);
811     SetEvent(This->event);
812     return S_OK;
813 }
814 
815 static HRESULT WINAPI ISynchronize_fnReset(ISynchronize *iface)
816 {
817     MREImpl *This = impl_from_ISynchronize(iface);
818     TRACE("%p\n", This);
819     ResetEvent(This->event);
820     return S_OK;
821 }
822 
823 static ISynchronizeVtbl vt_ISynchronize = {
824     ISynchronize_fnQueryInterface,
825     ISynchronize_fnAddRef,
826     ISynchronize_fnRelease,
827     ISynchronize_fnWait,
828     ISynchronize_fnSignal,
829     ISynchronize_fnReset
830 };
831 
832 static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface)
833 {
834     return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface);
835 }
836 
837 static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv)
838 {
839     MREImpl *This = impl_from_ISynchronizeHandle(iface);
840     return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv);
841 }
842 
843 static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface)
844 {
845     MREImpl *This = impl_from_ISynchronizeHandle(iface);
846     return ISynchronize_AddRef(&This->ISynchronize_iface);
847 }
848 
849 static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface)
850 {
851     MREImpl *This = impl_from_ISynchronizeHandle(iface);
852     return ISynchronize_Release(&This->ISynchronize_iface);
853 }
854 
855 static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph)
856 {
857     MREImpl *This = impl_from_ISynchronizeHandle(iface);
858 
859     *ph = This->event;
860     return S_OK;
861 }
862 
863 static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = {
864     SynchronizeHandle_QueryInterface,
865     SynchronizeHandle_AddRef,
866     SynchronizeHandle_Release,
867     SynchronizeHandle_GetHandle
868 };
869 
870 static HRESULT ManualResetEvent_Construct(IUnknown *punkouter, REFIID iid, void **ppv)
871 {
872     MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl));
873     HRESULT hr;
874 
875     if(punkouter)
876         FIXME("Aggregation not implemented.\n");
877 
878     This->ref = 1;
879     This->ISynchronize_iface.lpVtbl = &vt_ISynchronize;
880     This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl;
881     This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
882 
883     hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv);
884     ISynchronize_Release(&This->ISynchronize_iface);
885     return hr;
886 }
887 
888 static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface)
889 {
890     return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface);
891 }
892 
893 static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
894 {
895     LocalServer *This = impl_from_IServiceProvider(iface);
896 
897     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
898 
899     if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) {
900         *ppv = &This->IServiceProvider_iface;
901     }else {
902         *ppv = NULL;
903         return E_NOINTERFACE;
904     }
905 
906     IUnknown_AddRef((IUnknown*)*ppv);
907     return S_OK;
908 }
909 
910 static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface)
911 {
912     LocalServer *This = impl_from_IServiceProvider(iface);
913     LONG ref = InterlockedIncrement(&This->ref);
914 
915     TRACE("(%p) ref=%d\n", This, ref);
916 
917     return ref;
918 }
919 
920 static ULONG WINAPI LocalServer_Release(IServiceProvider *iface)
921 {
922     LocalServer *This = impl_from_IServiceProvider(iface);
923     LONG ref = InterlockedDecrement(&This->ref);
924 
925     TRACE("(%p) ref=%d\n", This, ref);
926 
927     if(!ref) {
928         assert(!This->apt);
929         HeapFree(GetProcessHeap(), 0, This);
930     }
931 
932     return ref;
933 }
934 
935 static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv)
936 {
937     LocalServer *This = impl_from_IServiceProvider(iface);
938     APARTMENT *apt = COM_CurrentApt();
939     RegisteredClass *iter;
940     HRESULT hres = E_FAIL;
941 
942     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv);
943 
944     if(!This->apt)
945         return E_UNEXPECTED;
946 
947     EnterCriticalSection(&csRegisteredClassList);
948 
949     LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) {
950         if(iter->apartment_id == apt->oxid
951            && (iter->runContext & CLSCTX_LOCAL_SERVER)
952            && IsEqualGUID(&iter->classIdentifier, guid)) {
953             hres = IUnknown_QueryInterface(iter->classObject, riid, ppv);
954             break;
955         }
956     }
957 
958     LeaveCriticalSection( &csRegisteredClassList );
959 
960     return hres;
961 }
962 
963 static const IServiceProviderVtbl LocalServerVtbl = {
964     LocalServer_QueryInterface,
965     LocalServer_AddRef,
966     LocalServer_Release,
967     LocalServer_QueryService
968 };
969 
970 static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret)
971 {
972     HRESULT hres = S_OK;
973 
974     EnterCriticalSection(&apt->cs);
975 
976     if(!apt->local_server) {
977         LocalServer *obj;
978 
979         obj = heap_alloc(sizeof(*obj));
980         if(obj) {
981             obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl;
982             obj->ref = 1;
983             obj->apt = apt;
984 
985             hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream);
986             if(SUCCEEDED(hres)) {
987                 hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface,
988                         MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
989                 if(FAILED(hres))
990                     IStream_Release(obj->marshal_stream);
991             }
992 
993             if(SUCCEEDED(hres))
994                 apt->local_server = obj;
995             else
996                 heap_free(obj);
997         }else {
998             hres = E_OUTOFMEMORY;
999         }
1000     }
1001 
1002     if(SUCCEEDED(hres))
1003         hres = IStream_Clone(apt->local_server->marshal_stream, ret);
1004 
1005     LeaveCriticalSection(&apt->cs);
1006 
1007     if(FAILED(hres))
1008         ERR("Failed: %08x\n", hres);
1009     return hres;
1010 }
1011 
1012 /***********************************************************************
1013  *           CoRevokeClassObject [OLE32.@]
1014  *
1015  * Removes a class object from the class registry.
1016  *
1017  * PARAMS
1018  *  dwRegister [I] Cookie returned from CoRegisterClassObject().
1019  *
1020  * RETURNS
1021  *  Success: S_OK.
1022  *  Failure: HRESULT code.
1023  *
1024  * NOTES
1025  *  Must be called from the same apartment that called CoRegisterClassObject(),
1026  *  otherwise it will fail with RPC_E_WRONG_THREAD.
1027  *
1028  * SEE ALSO
1029  *  CoRegisterClassObject
1030  */
1031 HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(
1032         DWORD dwRegister)
1033 {
1034   HRESULT hr = E_INVALIDARG;
1035   RegisteredClass *curClass;
1036   APARTMENT *apt;
1037 
1038   TRACE("(%08x)\n",dwRegister);
1039 
1040   apt = COM_CurrentApt();
1041   if (!apt)
1042   {
1043     ERR("COM was not initialized\n");
1044     return CO_E_NOTINITIALIZED;
1045   }
1046 
1047   EnterCriticalSection( &csRegisteredClassList );
1048 
1049   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1050   {
1051     /*
1052      * Check if we have a match on the cookie.
1053      */
1054     if (curClass->dwCookie == dwRegister)
1055     {
1056       if (curClass->apartment_id == apt->oxid)
1057       {
1058           COM_RevokeRegisteredClassObject(curClass);
1059           hr = S_OK;
1060       }
1061       else
1062       {
1063           ERR("called from wrong apartment, should be called from %s\n",
1064               wine_dbgstr_longlong(curClass->apartment_id));
1065           hr = RPC_E_WRONG_THREAD;
1066       }
1067       break;
1068     }
1069   }
1070 
1071   LeaveCriticalSection( &csRegisteredClassList );
1072 
1073   return hr;
1074 }
1075 
1076 /* frees unused libraries loaded by apartment_getclassobject by calling the
1077  * DLL's DllCanUnloadNow entry point */
1078 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
1079 {
1080     struct apartment_loaded_dll *entry, *next;
1081     EnterCriticalSection(&apt->cs);
1082     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1083     {
1084 	if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
1085         {
1086             DWORD real_delay = delay;
1087 
1088             if (real_delay == INFINITE)
1089             {
1090                 /* DLLs that return multi-threaded objects aren't unloaded
1091                  * straight away to cope for programs that have races between
1092                  * last object destruction and threads in the DLLs that haven't
1093                  * finished, despite DllCanUnloadNow returning S_OK */
1094                 if (entry->multi_threaded)
1095                     real_delay = 10 * 60 * 1000; /* 10 minutes */
1096                 else
1097                     real_delay = 0;
1098             }
1099 
1100             if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0)))
1101             {
1102                 list_remove(&entry->entry);
1103                 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
1104                 HeapFree(GetProcessHeap(), 0, entry);
1105             }
1106             else
1107             {
1108                 entry->unload_time = GetTickCount() + real_delay;
1109                 if (!entry->unload_time) entry->unload_time = 1;
1110             }
1111         }
1112         else if (entry->unload_time)
1113             entry->unload_time = 0;
1114     }
1115     LeaveCriticalSection(&apt->cs);
1116 }
1117 
1118 DWORD apartment_release(struct apartment *apt)
1119 {
1120     DWORD ret;
1121 
1122     EnterCriticalSection(&csApartment);
1123 
1124     ret = InterlockedDecrement(&apt->refs);
1125     TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
1126     /* destruction stuff that needs to happen under csApartment CS */
1127     if (ret == 0)
1128     {
1129         if (apt == MTA) MTA = NULL;
1130         else if (apt == MainApartment) MainApartment = NULL;
1131         list_remove(&apt->entry);
1132     }
1133 
1134     LeaveCriticalSection(&csApartment);
1135 
1136     if (ret == 0)
1137     {
1138         struct list *cursor, *cursor2;
1139 
1140         TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
1141 
1142         if(apt->local_server) {
1143             LocalServer *local_server = apt->local_server;
1144             LARGE_INTEGER zero;
1145 
1146             memset(&zero, 0, sizeof(zero));
1147             IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL);
1148             CoReleaseMarshalData(local_server->marshal_stream);
1149             IStream_Release(local_server->marshal_stream);
1150             local_server->marshal_stream = NULL;
1151 
1152             apt->local_server = NULL;
1153             local_server->apt = NULL;
1154             IServiceProvider_Release(&local_server->IServiceProvider_iface);
1155         }
1156 
1157         /* Release the references to the registered class objects */
1158         COM_RevokeAllClasses(apt);
1159 
1160         /* no locking is needed for this apartment, because no other thread
1161          * can access it at this point */
1162 
1163         apartment_disconnectproxies(apt);
1164 
1165         if (apt->win) DestroyWindow(apt->win);
1166         if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
1167 
1168         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
1169         {
1170             struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
1171             /* release the implicit reference given by the fact that the
1172              * stub has external references (it must do since it is in the
1173              * stub manager list in the apartment and all non-apartment users
1174              * must have a ref on the apartment and so it cannot be destroyed).
1175              */
1176             stub_manager_int_release(stubmgr);
1177         }
1178 
1179         /* if this assert fires, then another thread took a reference to a
1180          * stub manager without taking a reference to the containing
1181          * apartment, which it must do. */
1182         assert(list_empty(&apt->stubmgrs));
1183 
1184         if (apt->filter) IMessageFilter_Release(apt->filter);
1185 
1186         /* free as many unused libraries as possible... */
1187         apartment_freeunusedlibraries(apt, 0);
1188 
1189         /* ... and free the memory for the apartment loaded dll entry and
1190          * release the dll list reference without freeing the library for the
1191          * rest */
1192         while ((cursor = list_head(&apt->loaded_dlls)))
1193         {
1194             struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
1195             COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
1196             list_remove(cursor);
1197             HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1198         }
1199 
1200         DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
1201         DeleteCriticalSection(&apt->cs);
1202 
1203         HeapFree(GetProcessHeap(), 0, apt);
1204     }
1205 
1206     return ret;
1207 }
1208 
1209 /* The given OXID must be local to this process:
1210  *
1211  * The ref parameter is here mostly to ensure people remember that
1212  * they get one, you should normally take a ref for thread safety.
1213  */
1214 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
1215 {
1216     APARTMENT *result = NULL;
1217     struct list *cursor;
1218 
1219     EnterCriticalSection(&csApartment);
1220     LIST_FOR_EACH( cursor, &apts )
1221     {
1222         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1223         if (apt->oxid == oxid)
1224         {
1225             result = apt;
1226             if (ref) apartment_addref(result);
1227             break;
1228         }
1229     }
1230     LeaveCriticalSection(&csApartment);
1231 
1232     return result;
1233 }
1234 
1235 /* gets the apartment which has a given creator thread ID. The caller must
1236  * release the reference from the apartment as soon as the apartment pointer
1237  * is no longer required. */
1238 APARTMENT *apartment_findfromtid(DWORD tid)
1239 {
1240     APARTMENT *result = NULL;
1241     struct list *cursor;
1242 
1243     EnterCriticalSection(&csApartment);
1244     LIST_FOR_EACH( cursor, &apts )
1245     {
1246         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1247         if (apt->tid == tid)
1248         {
1249             result = apt;
1250             apartment_addref(result);
1251             break;
1252         }
1253     }
1254     LeaveCriticalSection(&csApartment);
1255 
1256     return result;
1257 }
1258 
1259 /* gets the main apartment if it exists. The caller must
1260  * release the reference from the apartment as soon as the apartment pointer
1261  * is no longer required. */
1262 static APARTMENT *apartment_findmain(void)
1263 {
1264     APARTMENT *result;
1265 
1266     EnterCriticalSection(&csApartment);
1267 
1268     result = MainApartment;
1269     if (result) apartment_addref(result);
1270 
1271     LeaveCriticalSection(&csApartment);
1272 
1273     return result;
1274 }
1275 
1276 /* gets the multi-threaded apartment if it exists. The caller must
1277  * release the reference from the apartment as soon as the apartment pointer
1278  * is no longer required. */
1279 static APARTMENT *apartment_find_multi_threaded(void)
1280 {
1281     APARTMENT *result = NULL;
1282     struct list *cursor;
1283 
1284     EnterCriticalSection(&csApartment);
1285 
1286     LIST_FOR_EACH( cursor, &apts )
1287     {
1288         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
1289         if (apt->multi_threaded)
1290         {
1291             result = apt;
1292             apartment_addref(result);
1293             break;
1294         }
1295     }
1296 
1297     LeaveCriticalSection(&csApartment);
1298     return result;
1299 }
1300 
1301 /* gets the specified class object by loading the appropriate DLL, if
1302  * necessary and calls the DllGetClassObject function for the DLL */
1303 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
1304                                         BOOL apartment_threaded,
1305                                         REFCLSID rclsid, REFIID riid, void **ppv)
1306 {
1307     static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
1308     HRESULT hr = S_OK;
1309     BOOL found = FALSE;
1310     struct apartment_loaded_dll *apartment_loaded_dll;
1311 
1312     if (!strcmpiW(dllpath, wszOle32))
1313     {
1314         /* we don't need to control the lifetime of this dll, so use the local
1315          * implementation of DllGetClassObject directly */
1316         TRACE("calling ole32!DllGetClassObject\n");
1317         hr = DllGetClassObject(rclsid, riid, ppv);
1318 
1319         if (hr != S_OK)
1320             ERR("DllGetClassObject returned error 0x%08x\n", hr);
1321 
1322         return hr;
1323     }
1324 
1325     EnterCriticalSection(&apt->cs);
1326 
1327     LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
1328         if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
1329         {
1330             TRACE("found %s already loaded\n", debugstr_w(dllpath));
1331             found = TRUE;
1332             break;
1333         }
1334 
1335     if (!found)
1336     {
1337         apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
1338         if (!apartment_loaded_dll)
1339             hr = E_OUTOFMEMORY;
1340         if (SUCCEEDED(hr))
1341         {
1342             apartment_loaded_dll->unload_time = 0;
1343             apartment_loaded_dll->multi_threaded = FALSE;
1344             hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
1345             if (FAILED(hr))
1346                 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
1347         }
1348         if (SUCCEEDED(hr))
1349         {
1350             TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
1351             list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
1352         }
1353     }
1354 
1355     LeaveCriticalSection(&apt->cs);
1356 
1357     if (SUCCEEDED(hr))
1358     {
1359         /* one component being multi-threaded overrides any number of
1360          * apartment-threaded components */
1361         if (!apartment_threaded)
1362             apartment_loaded_dll->multi_threaded = TRUE;
1363 
1364         TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
1365         /* OK: get the ClassObject */
1366         hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
1367 
1368         if (hr != S_OK)
1369             ERR("DllGetClassObject returned error 0x%08x\n", hr);
1370     }
1371 
1372     return hr;
1373 }
1374 
1375 /***********************************************************************
1376  *	COM_RegReadPath	[internal]
1377  *
1378  *	Reads a registry value and expands it when necessary
1379  */
1380 static DWORD COM_RegReadPath(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen)
1381 {
1382     DWORD ret;
1383 
1384     if (regdata->hkey)
1385     {
1386 	DWORD keytype;
1387 	WCHAR src[MAX_PATH];
1388 	DWORD dwLength = dstlen * sizeof(WCHAR);
1389 
1390         if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) {
1391             if (keytype == REG_EXPAND_SZ) {
1392               if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
1393             } else {
1394               const WCHAR *quote_start;
1395               quote_start = strchrW(src, '\"');
1396               if (quote_start) {
1397                 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
1398                 if (quote_end) {
1399                   memmove(src, quote_start + 1,
1400                           (quote_end - quote_start - 1) * sizeof(WCHAR));
1401                   src[quote_end - quote_start - 1] = '\0';
1402                 }
1403               }
1404               lstrcpynW(dst, src, dstlen);
1405             }
1406         }
1407 	return ret;
1408     }
1409     else
1410     {
1411         ULONG_PTR cookie;
1412         WCHAR *nameW;
1413 
1414         *dst = 0;
1415         nameW = (WCHAR*)((BYTE*)regdata->u.actctx.section + regdata->u.actctx.data->name_offset);
1416         ActivateActCtx(regdata->u.actctx.hactctx, &cookie);
1417         ret = SearchPathW(NULL, nameW, NULL, dstlen, dst, NULL);
1418         DeactivateActCtx(0, cookie);
1419         return !*dst;
1420     }
1421 }
1422 
1423 struct host_object_params
1424 {
1425     struct class_reg_data regdata;
1426     CLSID clsid; /* clsid of object to marshal */
1427     IID iid; /* interface to marshal */
1428     HANDLE event; /* event signalling when ready for multi-threaded case */
1429     HRESULT hr; /* result for multi-threaded case */
1430     IStream *stream; /* stream that the object will be marshaled into */
1431     BOOL apartment_threaded; /* is the component purely apartment-threaded? */
1432 };
1433 
1434 static HRESULT apartment_hostobject(struct apartment *apt,
1435                                     const struct host_object_params *params)
1436 {
1437     IUnknown *object;
1438     HRESULT hr;
1439     static const LARGE_INTEGER llZero;
1440     WCHAR dllpath[MAX_PATH+1];
1441 
1442     TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
1443 
1444     if (COM_RegReadPath(&params->regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
1445     {
1446         /* failure: CLSID is not found in registry */
1447         WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
1448         return REGDB_E_CLASSNOTREG;
1449     }
1450 
1451     hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
1452                                   &params->clsid, &params->iid, (void **)&object);
1453     if (FAILED(hr))
1454         return hr;
1455 
1456     hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1457     if (FAILED(hr))
1458         IUnknown_Release(object);
1459     IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
1460 
1461     return hr;
1462 }
1463 
1464 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1465 {
1466     switch (msg)
1467     {
1468     case DM_EXECUTERPC:
1469         RPC_ExecuteCall((struct dispatch_params *)lParam);
1470         return 0;
1471     case DM_HOSTOBJECT:
1472         return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
1473     default:
1474         return DefWindowProcW(hWnd, msg, wParam, lParam);
1475     }
1476 }
1477 
1478 struct host_thread_params
1479 {
1480     COINIT threading_model;
1481     HANDLE ready_event;
1482     HWND apartment_hwnd;
1483 };
1484 
1485 /* thread for hosting an object to allow an object to appear to be created in
1486  * an apartment with an incompatible threading model */
1487 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
1488 {
1489     struct host_thread_params *params = p;
1490     MSG msg;
1491     HRESULT hr;
1492     struct apartment *apt;
1493 
1494     TRACE("\n");
1495 
1496     hr = CoInitializeEx(NULL, params->threading_model);
1497     if (FAILED(hr)) return hr;
1498 
1499     apt = COM_CurrentApt();
1500     if (params->threading_model == COINIT_APARTMENTTHREADED)
1501     {
1502         apartment_createwindowifneeded(apt);
1503         params->apartment_hwnd = apartment_getwindow(apt);
1504     }
1505     else
1506         params->apartment_hwnd = NULL;
1507 
1508     /* force the message queue to be created before signaling parent thread */
1509     PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1510 
1511     SetEvent(params->ready_event);
1512     params = NULL; /* can't touch params after here as it may be invalid */
1513 
1514     while (GetMessageW(&msg, NULL, 0, 0))
1515     {
1516         if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
1517         {
1518             struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
1519             obj_params->hr = apartment_hostobject(apt, obj_params);
1520             SetEvent(obj_params->event);
1521         }
1522         else
1523         {
1524             TranslateMessage(&msg);
1525             DispatchMessageW(&msg);
1526         }
1527     }
1528 
1529     TRACE("exiting\n");
1530 
1531     CoUninitialize();
1532 
1533     return S_OK;
1534 }
1535 
1536 /* finds or creates a host apartment, creates the object inside it and returns
1537  * a proxy to it so that the object can be used in the apartment of the
1538  * caller of this function */
1539 static HRESULT apartment_hostobject_in_hostapt(
1540     struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
1541     const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv)
1542 {
1543     struct host_object_params params;
1544     HWND apartment_hwnd = NULL;
1545     DWORD apartment_tid = 0;
1546     HRESULT hr;
1547 
1548     if (!multi_threaded && main_apartment)
1549     {
1550         APARTMENT *host_apt = apartment_findmain();
1551         if (host_apt)
1552         {
1553             apartment_hwnd = apartment_getwindow(host_apt);
1554             apartment_release(host_apt);
1555         }
1556     }
1557 
1558     if (!apartment_hwnd)
1559     {
1560         EnterCriticalSection(&apt->cs);
1561 
1562         if (!apt->host_apt_tid)
1563         {
1564             struct host_thread_params thread_params;
1565             HANDLE handles[2];
1566             DWORD wait_value;
1567 
1568             thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
1569             handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1570             thread_params.apartment_hwnd = NULL;
1571             handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1572             if (!handles[1])
1573             {
1574                 CloseHandle(handles[0]);
1575                 LeaveCriticalSection(&apt->cs);
1576                 return E_OUTOFMEMORY;
1577             }
1578             wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1579             CloseHandle(handles[0]);
1580             CloseHandle(handles[1]);
1581             if (wait_value == WAIT_OBJECT_0)
1582                 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1583             else
1584             {
1585                 LeaveCriticalSection(&apt->cs);
1586                 return E_OUTOFMEMORY;
1587             }
1588         }
1589 
1590         if (multi_threaded || !main_apartment)
1591         {
1592             apartment_hwnd = apt->host_apt_hwnd;
1593             apartment_tid = apt->host_apt_tid;
1594         }
1595 
1596         LeaveCriticalSection(&apt->cs);
1597     }
1598 
1599     /* another thread may have become the main apartment in the time it took
1600      * us to create the thread for the host apartment */
1601     if (!apartment_hwnd && !multi_threaded && main_apartment)
1602     {
1603         APARTMENT *host_apt = apartment_findmain();
1604         if (host_apt)
1605         {
1606             apartment_hwnd = apartment_getwindow(host_apt);
1607             apartment_release(host_apt);
1608         }
1609     }
1610 
1611     params.regdata = *regdata;
1612     params.clsid = *rclsid;
1613     params.iid = *riid;
1614     hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1615     if (FAILED(hr))
1616         return hr;
1617     params.apartment_threaded = !multi_threaded;
1618     if (multi_threaded)
1619     {
1620         params.hr = S_OK;
1621         params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1622         if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1623             hr = E_OUTOFMEMORY;
1624         else
1625         {
1626             WaitForSingleObject(params.event, INFINITE);
1627             hr = params.hr;
1628         }
1629         CloseHandle(params.event);
1630     }
1631     else
1632     {
1633         if (!apartment_hwnd)
1634         {
1635             ERR("host apartment didn't create window\n");
1636             hr = E_OUTOFMEMORY;
1637         }
1638         else
1639             hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1640     }
1641     if (SUCCEEDED(hr))
1642         hr = CoUnmarshalInterface(params.stream, riid, ppv);
1643     IStream_Release(params.stream);
1644     return hr;
1645 }
1646 
1647 static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context )
1648 {
1649     WNDCLASSW wclass;
1650 
1651     /* Dispatching to the correct thread in an apartment is done through
1652      * window messages rather than RPC transports. When an interface is
1653      * marshalled into another apartment in the same process, a window of the
1654      * following class is created. The *caller* of CoMarshalInterface (i.e., the
1655      * application) is responsible for pumping the message loop in that thread.
1656      * The WM_USER messages which point to the RPCs are then dispatched to
1657      * apartment_wndproc by the user's code from the apartment in which the
1658      * interface was unmarshalled.
1659      */
1660     memset(&wclass, 0, sizeof(wclass));
1661     wclass.lpfnWndProc = apartment_wndproc;
1662     wclass.hInstance = hProxyDll;
1663     wclass.lpszClassName = wszAptWinClass;
1664     RegisterClassW(&wclass);
1665     return TRUE;
1666 }
1667 
1668 /* create a window for the apartment or return the current one if one has
1669  * already been created */
1670 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1671 {
1672     static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
1673 
1674     if (apt->multi_threaded)
1675         return S_OK;
1676 
1677     if (!apt->win)
1678     {
1679         HWND hwnd;
1680 
1681         InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL );
1682 
1683         hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0,
1684                              HWND_MESSAGE, 0, hProxyDll, NULL);
1685         if (!hwnd)
1686         {
1687             ERR("CreateWindow failed with error %d\n", GetLastError());
1688             return HRESULT_FROM_WIN32(GetLastError());
1689         }
1690         if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1691             /* someone beat us to it */
1692             DestroyWindow(hwnd);
1693     }
1694 
1695     return S_OK;
1696 }
1697 
1698 /* retrieves the window for the main- or apartment-threaded apartment */
1699 HWND apartment_getwindow(const struct apartment *apt)
1700 {
1701     assert(!apt->multi_threaded);
1702     return apt->win;
1703 }
1704 
1705 static void COM_TlsDestroy(void)
1706 {
1707     struct oletls *info = NtCurrentTeb()->ReservedForOle;
1708     if (info)
1709     {
1710         if (info->apt) apartment_release(info->apt);
1711         if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1712         if (info->state) IUnknown_Release(info->state);
1713         if (info->spy) IInitializeSpy_Release(info->spy);
1714         if (info->context_token) IObjContext_Release(info->context_token);
1715         HeapFree(GetProcessHeap(), 0, info);
1716         NtCurrentTeb()->ReservedForOle = NULL;
1717     }
1718 }
1719 
1720 /******************************************************************************
1721  *           CoBuildVersion [OLE32.@]
1722  *
1723  * Gets the build version of the DLL.
1724  *
1725  * PARAMS
1726  *
1727  * RETURNS
1728  *	Current build version, hiword is majornumber, loword is minornumber
1729  */
1730 DWORD WINAPI CoBuildVersion(void)
1731 {
1732     TRACE("Returning version %d, build %d.\n", rmm, rup);
1733     return (rmm<<16)+rup;
1734 }
1735 
1736 /******************************************************************************
1737  *              CoRegisterInitializeSpy [OLE32.@]
1738  *
1739  * Add a Spy that watches CoInitializeEx calls
1740  *
1741  * PARAMS
1742  *  spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1743  *  cookie [II] cookie receiver
1744  *
1745  * RETURNS
1746  *  Success: S_OK if not already initialized, S_FALSE otherwise.
1747  *  Failure: HRESULT code.
1748  *
1749  * SEE ALSO
1750  *   CoInitializeEx
1751  */
1752 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1753 {
1754     struct oletls *info = COM_CurrentInfo();
1755     HRESULT hr;
1756 
1757     TRACE("(%p, %p)\n", spy, cookie);
1758 
1759     if (!spy || !cookie || !info)
1760     {
1761         if (!info)
1762             WARN("Could not allocate tls\n");
1763         return E_INVALIDARG;
1764     }
1765 
1766     if (info->spy)
1767     {
1768         FIXME("Already registered?\n");
1769         return E_UNEXPECTED;
1770     }
1771 
1772     hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1773     if (SUCCEEDED(hr))
1774     {
1775         cookie->QuadPart = (DWORD_PTR)spy;
1776         return S_OK;
1777     }
1778     return hr;
1779 }
1780 
1781 /******************************************************************************
1782  *              CoRevokeInitializeSpy [OLE32.@]
1783  *
1784  * Remove a spy that previously watched CoInitializeEx calls
1785  *
1786  * PARAMS
1787  *  cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1788  *
1789  * RETURNS
1790  *  Success: S_OK if a spy is removed
1791  *  Failure: E_INVALIDARG
1792  *
1793  * SEE ALSO
1794  *   CoInitializeEx
1795  */
1796 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1797 {
1798     struct oletls *info = COM_CurrentInfo();
1799     TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1800 
1801     if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1802         return E_INVALIDARG;
1803 
1804     IInitializeSpy_Release(info->spy);
1805     info->spy = NULL;
1806     return S_OK;
1807 }
1808 
1809 HRESULT enter_apartment( struct oletls *info, DWORD model )
1810 {
1811     HRESULT hr = S_OK;
1812 
1813     if (!info->apt)
1814     {
1815         if (!apartment_get_or_create( model ))
1816             return E_OUTOFMEMORY;
1817     }
1818     else if (!apartment_is_model( info->apt, model ))
1819     {
1820         WARN( "Attempt to change threading model of this apartment from %s to %s\n",
1821               info->apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1822               model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" );
1823         return RPC_E_CHANGED_MODE;
1824     }
1825     else
1826         hr = S_FALSE;
1827 
1828     info->inits++;
1829 
1830     return hr;
1831 }
1832 
1833 void leave_apartment( struct oletls *info )
1834 {
1835     if (!--info->inits)
1836     {
1837         if (info->ole_inits)
1838             WARN( "Uninitializing apartment while Ole is still initialized\n" );
1839         apartment_release( info->apt );
1840         info->apt = NULL;
1841     }
1842 }
1843 
1844 /******************************************************************************
1845  *		CoInitialize	[OLE32.@]
1846  *
1847  * Initializes the COM libraries by calling CoInitializeEx with
1848  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1849  *
1850  * PARAMS
1851  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1852  *
1853  * RETURNS
1854  *  Success: S_OK if not already initialized, S_FALSE otherwise.
1855  *  Failure: HRESULT code.
1856  *
1857  * SEE ALSO
1858  *   CoInitializeEx
1859  */
1860 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1861 {
1862   /*
1863    * Just delegate to the newer method.
1864    */
1865   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1866 }
1867 
1868 /******************************************************************************
1869  *		CoInitializeEx	[OLE32.@]
1870  *
1871  * Initializes the COM libraries.
1872  *
1873  * PARAMS
1874  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1875  *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
1876  *
1877  * RETURNS
1878  *  S_OK               if successful,
1879  *  S_FALSE            if this function was called already.
1880  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1881  *                     threading model.
1882  *
1883  * NOTES
1884  *
1885  * The behavior used to set the IMalloc used for memory management is
1886  * obsolete.
1887  * The dwCoInit parameter must specify one of the following apartment
1888  * threading models:
1889  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1890  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1891  * The parameter may also specify zero or more of the following flags:
1892  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1893  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1894  *
1895  * SEE ALSO
1896  *   CoUninitialize
1897  */
1898 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1899 {
1900   struct oletls *info = COM_CurrentInfo();
1901   HRESULT hr;
1902 
1903   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1904 
1905   if (lpReserved!=NULL)
1906   {
1907     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1908   }
1909 
1910   /*
1911    * Check the lock count. If this is the first time going through the initialize
1912    * process, we have to initialize the libraries.
1913    *
1914    * And crank-up that lock count.
1915    */
1916   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1917   {
1918     /*
1919      * Initialize the various COM libraries and data structures.
1920      */
1921     TRACE("() - Initializing the COM libraries\n");
1922 
1923     /* we may need to defer this until after apartment initialisation */
1924     RunningObjectTableImpl_Initialize();
1925   }
1926 
1927   if (info->spy)
1928       IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1929 
1930   hr = enter_apartment( info, dwCoInit );
1931 
1932   if (info->spy)
1933       IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1934 
1935   return hr;
1936 }
1937 
1938 /***********************************************************************
1939  *           CoUninitialize   [OLE32.@]
1940  *
1941  * This method will decrement the refcount on the current apartment, freeing
1942  * the resources associated with it if it is the last thread in the apartment.
1943  * If the last apartment is freed, the function will additionally release
1944  * any COM resources associated with the process.
1945  *
1946  * PARAMS
1947  *
1948  * RETURNS
1949  *  Nothing.
1950  *
1951  * SEE ALSO
1952  *   CoInitializeEx
1953  */
1954 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
1955 {
1956   struct oletls * info = COM_CurrentInfo();
1957   LONG lCOMRefCnt;
1958 
1959   TRACE("()\n");
1960 
1961   /* will only happen on OOM */
1962   if (!info) return;
1963 
1964   if (info->spy)
1965       IInitializeSpy_PreUninitialize(info->spy, info->inits);
1966 
1967   /* sanity check */
1968   if (!info->inits)
1969   {
1970     ERR("Mismatched CoUninitialize\n");
1971 
1972     if (info->spy)
1973         IInitializeSpy_PostUninitialize(info->spy, info->inits);
1974     return;
1975   }
1976 
1977   leave_apartment( info );
1978 
1979   /*
1980    * Decrease the reference count.
1981    * If we are back to 0 locks on the COM library, make sure we free
1982    * all the associated data structures.
1983    */
1984   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1985   if (lCOMRefCnt==1)
1986   {
1987     TRACE("() - Releasing the COM libraries\n");
1988 
1989     revoke_registered_psclsids();
1990     RunningObjectTableImpl_UnInitialize();
1991   }
1992   else if (lCOMRefCnt<1) {
1993     ERR( "CoUninitialize() - not CoInitialized.\n" );
1994     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1995   }
1996   if (info->spy)
1997       IInitializeSpy_PostUninitialize(info->spy, info->inits);
1998 }
1999 
2000 /******************************************************************************
2001  *		CoDisconnectObject	[OLE32.@]
2002  *
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.
2006  *
2007  * Typically called when the object server is forced to shut down, for instance by
2008  * the user.
2009  *
2010  * PARAMS
2011  *  lpUnk    [I] The object whose stub should be disconnected.
2012  *  reserved [I] Reserved. Should be set to 0.
2013  *
2014  * RETURNS
2015  *  Success: S_OK.
2016  *  Failure: HRESULT code.
2017  *
2018  * SEE ALSO
2019  *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2020  */
2021 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2022 {
2023     struct stub_manager *manager;
2024     HRESULT hr;
2025     IMarshal *marshal;
2026     APARTMENT *apt;
2027 
2028     TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2029 
2030     if (!lpUnk) return E_INVALIDARG;
2031 
2032     hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2033     if (hr == S_OK)
2034     {
2035         hr = IMarshal_DisconnectObject(marshal, reserved);
2036         IMarshal_Release(marshal);
2037         return hr;
2038     }
2039 
2040     apt = COM_CurrentApt();
2041     if (!apt)
2042         return CO_E_NOTINITIALIZED;
2043 
2044     manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2045     if (manager) {
2046         stub_manager_disconnect(manager);
2047         /* Release stub manager twice, to remove the apartment reference. */
2048         stub_manager_int_release(manager);
2049         stub_manager_int_release(manager);
2050     }
2051 
2052     /* Note: native is pretty broken here because it just silently
2053      * fails, without returning an appropriate error code if the object was
2054      * not found, making apps think that the object was disconnected, when
2055      * it actually wasn't */
2056 
2057     return S_OK;
2058 }
2059 
2060 /******************************************************************************
2061  *		CoCreateGuid [OLE32.@]
2062  *
2063  * Simply forwards to UuidCreate in RPCRT4.
2064  *
2065  * PARAMS
2066  *  pguid [O] Points to the GUID to initialize.
2067  *
2068  * RETURNS
2069  *  Success: S_OK.
2070  *  Failure: HRESULT code.
2071  *
2072  * SEE ALSO
2073  *   UuidCreate
2074  */
2075 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2076 {
2077     DWORD status;
2078 
2079     if(!pguid) return E_INVALIDARG;
2080 
2081     status = UuidCreate(pguid);
2082     if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2083     return HRESULT_FROM_WIN32( status );
2084 }
2085 
2086 static inline BOOL is_valid_hex(WCHAR c)
2087 {
2088     if (!(((c >= '0') && (c <= '9'))  ||
2089           ((c >= 'a') && (c <= 'f'))  ||
2090           ((c >= 'A') && (c <= 'F'))))
2091         return FALSE;
2092     return TRUE;
2093 }
2094 
2095 static const BYTE guid_conv_table[256] =
2096 {
2097   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2098   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2099   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2100   0,   1,   2,   3,   4,   5,   6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2101   0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2102   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2103   0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf                             /* 0x60 */
2104 };
2105 
2106 /* conversion helper for CLSIDFromString/IIDFromString */
2107 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2108 {
2109   int	i;
2110 
2111   if (!s || s[0]!='{') {
2112     memset( id, 0, sizeof (CLSID) );
2113     if(!s) return TRUE;
2114     return FALSE;
2115   }
2116 
2117   TRACE("%s -> %p\n", debugstr_w(s), id);
2118 
2119   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2120 
2121   id->Data1 = 0;
2122   for (i = 1; i < 9; i++) {
2123     if (!is_valid_hex(s[i])) return FALSE;
2124     id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2125   }
2126   if (s[9]!='-') return FALSE;
2127 
2128   id->Data2 = 0;
2129   for (i = 10; i < 14; i++) {
2130     if (!is_valid_hex(s[i])) return FALSE;
2131     id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2132   }
2133   if (s[14]!='-') return FALSE;
2134 
2135   id->Data3 = 0;
2136   for (i = 15; i < 19; i++) {
2137     if (!is_valid_hex(s[i])) return FALSE;
2138     id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2139   }
2140   if (s[19]!='-') return FALSE;
2141 
2142   for (i = 20; i < 37; i+=2) {
2143     if (i == 24) {
2144       if (s[i]!='-') return FALSE;
2145       i++;
2146     }
2147     if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2148     id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2149   }
2150 
2151   if (s[37] == '}' && s[38] == '\0')
2152     return TRUE;
2153 
2154   return FALSE;
2155 }
2156 
2157 /*****************************************************************************/
2158 
2159 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2160 {
2161     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2162     WCHAR buf2[CHARS_IN_GUID];
2163     LONG buf2len = sizeof(buf2);
2164     HKEY xhkey;
2165     WCHAR *buf;
2166 
2167     memset(clsid, 0, sizeof(*clsid));
2168     buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2169     if (!buf) return E_OUTOFMEMORY;
2170     strcpyW( buf, progid );
2171     strcatW( buf, clsidW );
2172     if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2173     {
2174         HeapFree(GetProcessHeap(),0,buf);
2175         WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2176         return CO_E_CLASSSTRING;
2177     }
2178     HeapFree(GetProcessHeap(),0,buf);
2179 
2180     if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2181     {
2182         RegCloseKey(xhkey);
2183         WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2184         return CO_E_CLASSSTRING;
2185     }
2186     RegCloseKey(xhkey);
2187     return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2188 }
2189 
2190 /******************************************************************************
2191  *		CLSIDFromString	[OLE32.@]
2192  *
2193  * Converts a unique identifier from its string representation into
2194  * the GUID struct.
2195  *
2196  * PARAMS
2197  *  idstr [I] The string representation of the GUID.
2198  *  id    [O] GUID converted from the string.
2199  *
2200  * RETURNS
2201  *   S_OK on success
2202  *   CO_E_CLASSSTRING if idstr is not a valid CLSID
2203  *
2204  * SEE ALSO
2205  *  StringFromCLSID
2206  */
2207 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2208 {
2209     HRESULT ret = CO_E_CLASSSTRING;
2210     CLSID tmp_id;
2211 
2212     if (!id)
2213         return E_INVALIDARG;
2214 
2215     if (guid_from_string(idstr, id))
2216         return S_OK;
2217 
2218     /* It appears a ProgID is also valid */
2219     ret = clsid_from_string_reg(idstr, &tmp_id);
2220     if(SUCCEEDED(ret))
2221         *id = tmp_id;
2222 
2223     return ret;
2224 }
2225 
2226 /******************************************************************************
2227  *		IIDFromString   [OLE32.@]
2228  *
2229  * Converts an interface identifier from its string representation to
2230  * the IID struct.
2231  *
2232  * PARAMS
2233  *  idstr [I] The string representation of the GUID.
2234  *  id    [O] IID converted from the string.
2235  *
2236  * RETURNS
2237  *   S_OK on success
2238  *   CO_E_IIDSTRING if idstr is not a valid IID
2239  *
2240  * SEE ALSO
2241  *  StringFromIID
2242  */
2243 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2244 {
2245   TRACE("%s -> %p\n", debugstr_w(s), iid);
2246 
2247   if (!s)
2248   {
2249       memset(iid, 0, sizeof(*iid));
2250       return S_OK;
2251   }
2252 
2253   /* length mismatch is a special case */
2254   if (strlenW(s) + 1 != CHARS_IN_GUID)
2255       return E_INVALIDARG;
2256 
2257   if (s[0] != '{')
2258       return CO_E_IIDSTRING;
2259 
2260   return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2261 }
2262 
2263 /******************************************************************************
2264  *		StringFromCLSID	[OLE32.@]
2265  *		StringFromIID   [OLE32.@]
2266  *
2267  * Converts a GUID into the respective string representation.
2268  * The target string is allocated using the OLE IMalloc.
2269  *
2270  * PARAMS
2271  *  id    [I] the GUID to be converted.
2272  *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2273  *
2274  * RETURNS
2275  *   S_OK
2276  *   E_FAIL
2277  *
2278  * SEE ALSO
2279  *  StringFromGUID2, CLSIDFromString
2280  */
2281 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2282 {
2283     if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2284     StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2285     return S_OK;
2286 }
2287 
2288 /******************************************************************************
2289  *		StringFromGUID2	[OLE32.@]
2290  *
2291  * Modified version of StringFromCLSID that allows you to specify max
2292  * buffer size.
2293  *
2294  * PARAMS
2295  *  id   [I] GUID to convert to string.
2296  *  str  [O] Buffer where the result will be stored.
2297  *  cmax [I] Size of the buffer in characters.
2298  *
2299  * RETURNS
2300  *	Success: The length of the resulting string in characters.
2301  *  Failure: 0.
2302  */
2303 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2304 {
2305     static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2306                                      '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2307                                      '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2308                                      '%','0','2','X','%','0','2','X','}',0 };
2309     if (!id || cmax < CHARS_IN_GUID) return 0;
2310     sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2311               id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2312               id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2313     return CHARS_IN_GUID;
2314 }
2315 
2316 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2317 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2318 {
2319     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2320     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2321     LONG res;
2322     HKEY key;
2323 
2324     strcpyW(path, wszCLSIDSlash);
2325     StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2326     res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2327     if (res == ERROR_FILE_NOT_FOUND)
2328         return REGDB_E_CLASSNOTREG;
2329     else if (res != ERROR_SUCCESS)
2330         return REGDB_E_READREGDB;
2331 
2332     if (!keyname)
2333     {
2334         *subkey = key;
2335         return S_OK;
2336     }
2337 
2338     res = open_classes_key(key, keyname, access, subkey);
2339     RegCloseKey(key);
2340     if (res == ERROR_FILE_NOT_FOUND)
2341         return REGDB_E_KEYMISSING;
2342     else if (res != ERROR_SUCCESS)
2343         return REGDB_E_READREGDB;
2344 
2345     return S_OK;
2346 }
2347 
2348 /* open HKCR\\AppId\\{string form of appid clsid} key */
2349 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2350 {
2351     static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2352     static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2353     DWORD res;
2354     WCHAR buf[CHARS_IN_GUID];
2355     WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2356     DWORD size;
2357     HKEY hkey;
2358     DWORD type;
2359     HRESULT hr;
2360 
2361     /* read the AppID value under the class's key */
2362     hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2363     if (FAILED(hr))
2364         return hr;
2365 
2366     size = sizeof(buf);
2367     res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2368     RegCloseKey(hkey);
2369     if (res == ERROR_FILE_NOT_FOUND)
2370         return REGDB_E_KEYMISSING;
2371     else if (res != ERROR_SUCCESS || type!=REG_SZ)
2372         return REGDB_E_READREGDB;
2373 
2374     strcpyW(keyname, szAppIdKey);
2375     strcatW(keyname, buf);
2376     res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2377     if (res == ERROR_FILE_NOT_FOUND)
2378         return REGDB_E_KEYMISSING;
2379     else if (res != ERROR_SUCCESS)
2380         return REGDB_E_READREGDB;
2381 
2382     return S_OK;
2383 }
2384 
2385 /******************************************************************************
2386  *               ProgIDFromCLSID [OLE32.@]
2387  *
2388  * Converts a class id into the respective program ID.
2389  *
2390  * PARAMS
2391  *  clsid        [I] Class ID, as found in registry.
2392  *  ppszProgID [O] Associated ProgID.
2393  *
2394  * RETURNS
2395  *   S_OK
2396  *   E_OUTOFMEMORY
2397  *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2398  */
2399 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2400 {
2401     static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2402     ACTCTX_SECTION_KEYED_DATA data;
2403     HKEY     hkey;
2404     HRESULT  ret;
2405     LONG progidlen = 0;
2406 
2407     if (!ppszProgID)
2408         return E_INVALIDARG;
2409 
2410     *ppszProgID = NULL;
2411 
2412     data.cbSize = sizeof(data);
2413     if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2414                               clsid, &data))
2415     {
2416         struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2417         if (comclass->progid_len)
2418         {
2419             WCHAR *ptrW;
2420 
2421             *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2422             if (!*ppszProgID) return E_OUTOFMEMORY;
2423 
2424             ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2425             memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2426             return S_OK;
2427         }
2428         else
2429             return REGDB_E_CLASSNOTREG;
2430     }
2431 
2432     ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2433     if (FAILED(ret))
2434         return ret;
2435 
2436     if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2437       ret = REGDB_E_CLASSNOTREG;
2438 
2439     if (ret == S_OK)
2440     {
2441       *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2442       if (*ppszProgID)
2443       {
2444         if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2445           ret = REGDB_E_CLASSNOTREG;
2446           CoTaskMemFree(*ppszProgID);
2447           *ppszProgID = NULL;
2448         }
2449       }
2450       else
2451         ret = E_OUTOFMEMORY;
2452     }
2453 
2454     RegCloseKey(hkey);
2455     return ret;
2456 }
2457 
2458 /******************************************************************************
2459  *		CLSIDFromProgID	[OLE32.@]
2460  *
2461  * Converts a program id into the respective GUID.
2462  *
2463  * PARAMS
2464  *  progid [I] Unicode program ID, as found in registry.
2465  *  clsid  [O] Associated CLSID.
2466  *
2467  * RETURNS
2468  *	Success: S_OK
2469  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2470  */
2471 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2472 {
2473     ACTCTX_SECTION_KEYED_DATA data;
2474 
2475     if (!progid || !clsid)
2476         return E_INVALIDARG;
2477 
2478     data.cbSize = sizeof(data);
2479     if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2480                                  progid, &data))
2481     {
2482         struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2483         CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2484         *clsid = *alias;
2485         return S_OK;
2486     }
2487 
2488     return clsid_from_string_reg(progid, clsid);
2489 }
2490 
2491 /******************************************************************************
2492  *              CLSIDFromProgIDEx [OLE32.@]
2493  */
2494 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2495 {
2496     FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2497 
2498     return CLSIDFromProgID(progid, clsid);
2499 }
2500 
2501 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2502 {
2503     HKEY hkey;
2504     WCHAR value[CHARS_IN_GUID];
2505     DWORD len;
2506 
2507     access |= KEY_READ;
2508 
2509     if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2510         return REGDB_E_IIDNOTREG;
2511 
2512     len = sizeof(value);
2513     if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2514         return REGDB_E_IIDNOTREG;
2515     RegCloseKey(hkey);
2516 
2517     if (CLSIDFromString(value, pclsid) != NOERROR)
2518         return REGDB_E_IIDNOTREG;
2519 
2520     return S_OK;
2521 }
2522 
2523 /*****************************************************************************
2524  *             CoGetPSClsid [OLE32.@]
2525  *
2526  * Retrieves the CLSID of the proxy/stub factory that implements
2527  * IPSFactoryBuffer for the specified interface.
2528  *
2529  * PARAMS
2530  *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
2531  *  pclsid [O] Where to store returned proxy/stub CLSID.
2532  *
2533  * RETURNS
2534  *   S_OK
2535  *   E_OUTOFMEMORY
2536  *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2537  *
2538  * NOTES
2539  *
2540  * The standard marshaller activates the object with the CLSID
2541  * returned and uses the CreateProxy and CreateStub methods on its
2542  * IPSFactoryBuffer interface to construct the proxies and stubs for a
2543  * given object.
2544  *
2545  * CoGetPSClsid determines this CLSID by searching the
2546  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2547  * in the registry and any interface id registered by
2548  * CoRegisterPSClsid within the current process.
2549  *
2550  * BUGS
2551  *
2552  * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2553  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2554  * considered a bug in native unless an application depends on this (unlikely).
2555  *
2556  * SEE ALSO
2557  *  CoRegisterPSClsid.
2558  */
2559 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2560 {
2561     static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2562     static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2563     WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2564     APARTMENT *apt = COM_CurrentApt();
2565     struct registered_psclsid *registered_psclsid;
2566     ACTCTX_SECTION_KEYED_DATA data;
2567     HRESULT hr;
2568     REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2569     BOOL is_wow64;
2570 
2571     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2572 
2573     if (!apt)
2574     {
2575         ERR("apartment not initialised\n");
2576         return CO_E_NOTINITIALIZED;
2577     }
2578 
2579     if (!pclsid)
2580         return E_INVALIDARG;
2581 
2582     EnterCriticalSection(&cs_registered_psclsid_list);
2583 
2584     LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2585         if (IsEqualIID(&registered_psclsid->iid, riid))
2586         {
2587             *pclsid = registered_psclsid->clsid;
2588             LeaveCriticalSection(&cs_registered_psclsid_list);
2589             return S_OK;
2590         }
2591 
2592     LeaveCriticalSection(&cs_registered_psclsid_list);
2593 
2594     data.cbSize = sizeof(data);
2595     if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2596                               riid, &data))
2597     {
2598         struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2599         *pclsid = ifaceps->iid;
2600         return S_OK;
2601     }
2602 
2603     /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2604     strcpyW(path, wszInterface);
2605     StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2606     strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2607 
2608     hr = get_ps_clsid_from_registry(path, 0, pclsid);
2609     if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2610                        (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2611         hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2612 
2613     if (hr == S_OK)
2614         TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2615     else
2616         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2617 
2618     return hr;
2619 }
2620 
2621 /*****************************************************************************
2622  *             CoRegisterPSClsid [OLE32.@]
2623  *
2624  * Register a proxy/stub CLSID for the given interface in the current process
2625  * only.
2626  *
2627  * PARAMS
2628  *  riid   [I] Interface whose proxy/stub CLSID is to be registered.
2629  *  rclsid [I] CLSID of the proxy/stub.
2630  *
2631  * RETURNS
2632  *   Success: S_OK
2633  *   Failure: E_OUTOFMEMORY
2634  *
2635  * NOTES
2636  *
2637  * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2638  * will be returned from other apartments in the same process.
2639  *
2640  * This function does not add anything to the registry and the effects are
2641  * limited to the lifetime of the current process.
2642  *
2643  * SEE ALSO
2644  *  CoGetPSClsid.
2645  */
2646 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2647 {
2648     APARTMENT *apt = COM_CurrentApt();
2649     struct registered_psclsid *registered_psclsid;
2650 
2651     TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2652 
2653     if (!apt)
2654     {
2655         ERR("apartment not initialised\n");
2656         return CO_E_NOTINITIALIZED;
2657     }
2658 
2659     EnterCriticalSection(&cs_registered_psclsid_list);
2660 
2661     LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2662         if (IsEqualIID(&registered_psclsid->iid, riid))
2663         {
2664             registered_psclsid->clsid = *rclsid;
2665             LeaveCriticalSection(&cs_registered_psclsid_list);
2666             return S_OK;
2667         }
2668 
2669     registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2670     if (!registered_psclsid)
2671     {
2672         LeaveCriticalSection(&cs_registered_psclsid_list);
2673         return E_OUTOFMEMORY;
2674     }
2675 
2676     registered_psclsid->iid = *riid;
2677     registered_psclsid->clsid = *rclsid;
2678     list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2679 
2680     LeaveCriticalSection(&cs_registered_psclsid_list);
2681 
2682     return S_OK;
2683 }
2684 
2685 
2686 /***
2687  * COM_GetRegisteredClassObject
2688  *
2689  * This internal method is used to scan the registered class list to
2690  * find a class object.
2691  *
2692  * Params:
2693  *   rclsid        Class ID of the class to find.
2694  *   dwClsContext  Class context to match.
2695  *   ppv           [out] returns a pointer to the class object. Complying
2696  *                 to normal COM usage, this method will increase the
2697  *                 reference count on this object.
2698  */
2699 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2700                                             DWORD dwClsContext, LPUNKNOWN* ppUnk)
2701 {
2702   HRESULT hr = S_FALSE;
2703   RegisteredClass *curClass;
2704 
2705   EnterCriticalSection( &csRegisteredClassList );
2706 
2707   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2708   {
2709     /*
2710      * Check if we have a match on the class ID and context.
2711      */
2712     if ((apt->oxid == curClass->apartment_id) &&
2713         (dwClsContext & curClass->runContext) &&
2714         IsEqualGUID(&(curClass->classIdentifier), rclsid))
2715     {
2716       /*
2717        * We have a match, return the pointer to the class object.
2718        */
2719       *ppUnk = curClass->classObject;
2720 
2721       IUnknown_AddRef(curClass->classObject);
2722 
2723       hr = S_OK;
2724       break;
2725     }
2726   }
2727 
2728   LeaveCriticalSection( &csRegisteredClassList );
2729 
2730   return hr;
2731 }
2732 
2733 /******************************************************************************
2734  *		CoRegisterClassObject	[OLE32.@]
2735  *
2736  * Registers the class object for a given class ID. Servers housed in EXE
2737  * files use this method instead of exporting DllGetClassObject to allow
2738  * other code to connect to their objects.
2739  *
2740  * PARAMS
2741  *  rclsid       [I] CLSID of the object to register.
2742  *  pUnk         [I] IUnknown of the object.
2743  *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2744  *  flags        [I] REGCLS flags indicating how connections are made.
2745  *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2746  *
2747  * RETURNS
2748  *   S_OK on success,
2749  *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
2750  *   CO_E_OBJISREG if the object is already registered. We should not return this.
2751  *
2752  * SEE ALSO
2753  *   CoRevokeClassObject, CoGetClassObject
2754  *
2755  * NOTES
2756  *  In-process objects are only registered for the current apartment.
2757  *  CoGetClassObject() and CoCreateInstance() will not return objects registered
2758  *  in other apartments.
2759  *
2760  * BUGS
2761  *  MSDN claims that multiple interface registrations are legal, but we
2762  *  can't do that with our current implementation.
2763  */
2764 HRESULT WINAPI CoRegisterClassObject(
2765     REFCLSID rclsid,
2766     LPUNKNOWN pUnk,
2767     DWORD dwClsContext,
2768     DWORD flags,
2769     LPDWORD lpdwRegister)
2770 {
2771   static LONG next_cookie;
2772   RegisteredClass* newClass;
2773   LPUNKNOWN        foundObject;
2774   HRESULT          hr;
2775   APARTMENT *apt;
2776 
2777   TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2778 	debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2779 
2780   if ( (lpdwRegister==0) || (pUnk==0) )
2781     return E_INVALIDARG;
2782 
2783   apt = COM_CurrentApt();
2784   if (!apt)
2785   {
2786       ERR("COM was not initialized\n");
2787       return CO_E_NOTINITIALIZED;
2788   }
2789 
2790   *lpdwRegister = 0;
2791 
2792   /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2793    * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2794   if (flags & REGCLS_MULTIPLEUSE)
2795     dwClsContext |= CLSCTX_INPROC_SERVER;
2796 
2797   /*
2798    * First, check if the class is already registered.
2799    * If it is, this should cause an error.
2800    */
2801   hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2802   if (hr == S_OK) {
2803     if (flags & REGCLS_MULTIPLEUSE) {
2804       if (dwClsContext & CLSCTX_LOCAL_SERVER)
2805         hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2806       IUnknown_Release(foundObject);
2807       return hr;
2808     }
2809     IUnknown_Release(foundObject);
2810     ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2811     return CO_E_OBJISREG;
2812   }
2813 
2814   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2815   if ( newClass == NULL )
2816     return E_OUTOFMEMORY;
2817 
2818   newClass->classIdentifier = *rclsid;
2819   newClass->apartment_id    = apt->oxid;
2820   newClass->runContext      = dwClsContext;
2821   newClass->connectFlags    = flags;
2822   newClass->RpcRegistration = NULL;
2823 
2824   if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2825       newClass->dwCookie = InterlockedIncrement( &next_cookie );
2826 
2827   /*
2828    * Since we're making a copy of the object pointer, we have to increase its
2829    * reference count.
2830    */
2831   newClass->classObject     = pUnk;
2832   IUnknown_AddRef(newClass->classObject);
2833 
2834   EnterCriticalSection( &csRegisteredClassList );
2835   list_add_tail(&RegisteredClassList, &newClass->entry);
2836   LeaveCriticalSection( &csRegisteredClassList );
2837 
2838   *lpdwRegister = newClass->dwCookie;
2839 
2840   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2841       IStream *marshal_stream;
2842 
2843       hr = get_local_server_stream(apt, &marshal_stream);
2844       if(FAILED(hr))
2845           return hr;
2846 
2847       hr = RPC_StartLocalServer(&newClass->classIdentifier,
2848                                 marshal_stream,
2849                                 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2850                                 &newClass->RpcRegistration);
2851       IStream_Release(marshal_stream);
2852   }
2853   return S_OK;
2854 }
2855 
2856 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2857 {
2858     if (data->hkey)
2859     {
2860         static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2861         static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2862         static const WCHAR wszFree[] = {'F','r','e','e',0};
2863         static const WCHAR wszBoth[] = {'B','o','t','h',0};
2864         WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2865         DWORD dwLength = sizeof(threading_model);
2866         DWORD keytype;
2867         DWORD ret;
2868 
2869         ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2870         if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2871             threading_model[0] = '\0';
2872 
2873         if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2874         if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2875         if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2876 
2877         /* there's not specific handling for this case */
2878         if (threading_model[0]) return ThreadingModel_Neutral;
2879         return ThreadingModel_No;
2880     }
2881     else
2882         return data->u.actctx.data->model;
2883 }
2884 
2885 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2886                                        REFCLSID rclsid, REFIID riid,
2887                                        BOOL hostifnecessary, void **ppv)
2888 {
2889     WCHAR dllpath[MAX_PATH+1];
2890     BOOL apartment_threaded;
2891 
2892     if (hostifnecessary)
2893     {
2894         enum comclass_threadingmodel model = get_threading_model(regdata);
2895 
2896         if (model == ThreadingModel_Apartment)
2897         {
2898             apartment_threaded = TRUE;
2899             if (apt->multi_threaded)
2900                 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2901         }
2902         else if (model == ThreadingModel_Free)
2903         {
2904             apartment_threaded = FALSE;
2905             if (!apt->multi_threaded)
2906                 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2907         }
2908         /* everything except "Apartment", "Free" and "Both" */
2909         else if (model != ThreadingModel_Both)
2910         {
2911             apartment_threaded = TRUE;
2912             /* everything else is main-threaded */
2913             if (model != ThreadingModel_No)
2914                 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2915 
2916             if (apt->multi_threaded || !apt->main)
2917                 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2918         }
2919         else
2920             apartment_threaded = FALSE;
2921     }
2922     else
2923         apartment_threaded = !apt->multi_threaded;
2924 
2925     if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2926     {
2927         /* failure: CLSID is not found in registry */
2928         WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2929         return REGDB_E_CLASSNOTREG;
2930     }
2931 
2932     return apartment_getclassobject(apt, dllpath, apartment_threaded,
2933                                     rclsid, riid, ppv);
2934 }
2935 
2936 /***********************************************************************
2937  *           CoGetClassObject [OLE32.@]
2938  *
2939  * Creates an object of the specified class.
2940  *
2941  * PARAMS
2942  *  rclsid       [I] Class ID to create an instance of.
2943  *  dwClsContext [I] Flags to restrict the location of the created instance.
2944  *  pServerInfo  [I] Optional. Details for connecting to a remote server.
2945  *  iid          [I] The ID of the interface of the instance to return.
2946  *  ppv          [O] On returns, contains a pointer to the specified interface of the object.
2947  *
2948  * RETURNS
2949  *  Success: S_OK
2950  *  Failure: HRESULT code.
2951  *
2952  * NOTES
2953  *  The dwClsContext parameter can be one or more of the following:
2954  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2955  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2956  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2957  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2958  *
2959  * SEE ALSO
2960  *  CoCreateInstance()
2961  */
2962 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2963     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2964     REFIID iid, LPVOID *ppv)
2965 {
2966     struct class_reg_data clsreg;
2967     IUnknown *regClassObject;
2968     HRESULT	hres = E_UNEXPECTED;
2969     APARTMENT  *apt;
2970     BOOL release_apt = FALSE;
2971 
2972     TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2973 
2974     if (!ppv)
2975         return E_INVALIDARG;
2976 
2977     *ppv = NULL;
2978 
2979     if (!(apt = COM_CurrentApt()))
2980     {
2981         if (!(apt = apartment_find_multi_threaded()))
2982         {
2983             ERR("apartment not initialised\n");
2984             return CO_E_NOTINITIALIZED;
2985         }
2986         release_apt = TRUE;
2987     }
2988 
2989     if (pServerInfo) {
2990 	FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2991               debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2992     }
2993 
2994     if (CLSCTX_INPROC_SERVER & dwClsContext)
2995     {
2996         if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2997         {
2998             if (release_apt) apartment_release(apt);
2999             return FTMarshalCF_Create(iid, ppv);
3000         }
3001         if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
3002             return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
3003     }
3004 
3005     if (CLSCTX_INPROC & dwClsContext)
3006     {
3007         ACTCTX_SECTION_KEYED_DATA data;
3008 
3009         data.cbSize = sizeof(data);
3010         /* search activation context first */
3011         if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3012                                   ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3013                                   rclsid, &data))
3014         {
3015             struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3016 
3017             clsreg.u.actctx.hactctx = data.hActCtx;
3018             clsreg.u.actctx.data = data.lpData;
3019             clsreg.u.actctx.section = data.lpSectionBase;
3020             clsreg.hkey = FALSE;
3021 
3022             hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3023             ReleaseActCtx(data.hActCtx);
3024             if (release_apt) apartment_release(apt);
3025             return hres;
3026         }
3027     }
3028 
3029     /*
3030      * First, try and see if we can't match the class ID with one of the
3031      * registered classes.
3032      */
3033     if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3034                                              &regClassObject))
3035     {
3036       /* Get the required interface from the retrieved pointer. */
3037       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3038 
3039       /*
3040        * Since QI got another reference on the pointer, we want to release the
3041        * one we already have. If QI was unsuccessful, this will release the object. This
3042        * is good since we are not returning it in the "out" parameter.
3043        */
3044       IUnknown_Release(regClassObject);
3045       if (release_apt) apartment_release(apt);
3046       return hres;
3047     }
3048 
3049     /* First try in-process server */
3050     if (CLSCTX_INPROC_SERVER & dwClsContext)
3051     {
3052         static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3053         HKEY hkey;
3054 
3055         hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3056         if (FAILED(hres))
3057         {
3058             if (hres == REGDB_E_CLASSNOTREG)
3059                 ERR("class %s not registered\n", debugstr_guid(rclsid));
3060             else if (hres == REGDB_E_KEYMISSING)
3061             {
3062                 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3063                 hres = REGDB_E_CLASSNOTREG;
3064             }
3065         }
3066 
3067         if (SUCCEEDED(hres))
3068         {
3069             clsreg.u.hkey = hkey;
3070             clsreg.hkey = TRUE;
3071 
3072             hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3073             RegCloseKey(hkey);
3074         }
3075 
3076         /* return if we got a class, otherwise fall through to one of the
3077          * other types */
3078         if (SUCCEEDED(hres))
3079         {
3080             if (release_apt) apartment_release(apt);
3081             return hres;
3082         }
3083     }
3084 
3085     /* Next try in-process handler */
3086     if (CLSCTX_INPROC_HANDLER & dwClsContext)
3087     {
3088         static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3089         HKEY hkey;
3090 
3091         hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3092         if (FAILED(hres))
3093         {
3094             if (hres == REGDB_E_CLASSNOTREG)
3095                 ERR("class %s not registered\n", debugstr_guid(rclsid));
3096             else if (hres == REGDB_E_KEYMISSING)
3097             {
3098                 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3099                 hres = REGDB_E_CLASSNOTREG;
3100             }
3101         }
3102 
3103         if (SUCCEEDED(hres))
3104         {
3105             clsreg.u.hkey = hkey;
3106             clsreg.hkey = TRUE;
3107 
3108             hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3109             RegCloseKey(hkey);
3110         }
3111 
3112         /* return if we got a class, otherwise fall through to one of the
3113          * other types */
3114         if (SUCCEEDED(hres))
3115         {
3116             if (release_apt) apartment_release(apt);
3117             return hres;
3118         }
3119     }
3120     if (release_apt) apartment_release(apt);
3121 
3122     /* Next try out of process */
3123     if (CLSCTX_LOCAL_SERVER & dwClsContext)
3124     {
3125         hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3126         if (SUCCEEDED(hres))
3127             return hres;
3128     }
3129 
3130     /* Finally try remote: this requires networked DCOM (a lot of work) */
3131     if (CLSCTX_REMOTE_SERVER & dwClsContext)
3132     {
3133         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3134         hres = REGDB_E_CLASSNOTREG;
3135     }
3136 
3137     if (FAILED(hres))
3138         ERR("no class object %s could be created for context 0x%x\n",
3139             debugstr_guid(rclsid), dwClsContext);
3140     return hres;
3141 }
3142 
3143 /***********************************************************************
3144  *        CoResumeClassObjects (OLE32.@)
3145  *
3146  * Resumes all class objects registered with REGCLS_SUSPENDED.
3147  *
3148  * RETURNS
3149  *  Success: S_OK.
3150  *  Failure: HRESULT code.
3151  */
3152 HRESULT WINAPI CoResumeClassObjects(void)
3153 {
3154        FIXME("stub\n");
3155 	return S_OK;
3156 }
3157 
3158 /***********************************************************************
3159  *           CoCreateInstance [OLE32.@]
3160  *
3161  * Creates an instance of the specified class.
3162  *
3163  * PARAMS
3164  *  rclsid       [I] Class ID to create an instance of.
3165  *  pUnkOuter    [I] Optional outer unknown to allow aggregation with another object.
3166  *  dwClsContext [I] Flags to restrict the location of the created instance.
3167  *  iid          [I] The ID of the interface of the instance to return.
3168  *  ppv          [O] On returns, contains a pointer to the specified interface of the instance.
3169  *
3170  * RETURNS
3171  *  Success: S_OK
3172  *  Failure: HRESULT code.
3173  *
3174  * NOTES
3175  *  The dwClsContext parameter can be one or more of the following:
3176  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3177  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3178  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3179  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3180  *
3181  * Aggregation is the concept of deferring the IUnknown of an object to another
3182  * object. This allows a separate object to behave as though it was part of
3183  * the object and to allow this the pUnkOuter parameter can be set. Note that
3184  * not all objects support having an outer of unknown.
3185  *
3186  * SEE ALSO
3187  *  CoGetClassObject()
3188  */
3189 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3190     REFCLSID rclsid,
3191     LPUNKNOWN pUnkOuter,
3192     DWORD dwClsContext,
3193     REFIID iid,
3194     LPVOID *ppv)
3195 {
3196     MULTI_QI multi_qi = { iid };
3197     HRESULT hres;
3198 
3199     TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3200           pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3201 
3202     if (ppv==0)
3203         return E_POINTER;
3204 
3205     hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3206     *ppv = multi_qi.pItf;
3207     return hres;
3208 }
3209 
3210 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3211 {
3212   ULONG i;
3213 
3214   for (i = 0; i < count; i++)
3215   {
3216       mqi[i].pItf = NULL;
3217       mqi[i].hr = hr;
3218   }
3219 }
3220 
3221 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3222 {
3223   ULONG index = 0, fetched = 0;
3224 
3225   if (include_unk)
3226   {
3227     mqi[0].hr = S_OK;
3228     mqi[0].pItf = unk;
3229     index = fetched = 1;
3230   }
3231 
3232   for (; index < count; index++)
3233   {
3234     mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3235     if (mqi[index].hr == S_OK)
3236       fetched++;
3237   }
3238 
3239   if (!include_unk)
3240       IUnknown_Release(unk);
3241 
3242   if (fetched == 0)
3243     return E_NOINTERFACE;
3244 
3245   return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3246 }
3247 
3248 /***********************************************************************
3249  *           CoCreateInstanceEx [OLE32.@]
3250  */
3251 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3252   REFCLSID      rclsid,
3253   LPUNKNOWN     pUnkOuter,
3254   DWORD         dwClsContext,
3255   COSERVERINFO* pServerInfo,
3256   ULONG         cmq,
3257   MULTI_QI*     pResults)
3258 {
3259     IUnknown *unk = NULL;
3260     IClassFactory *cf;
3261     APARTMENT *apt;
3262     CLSID clsid;
3263     HRESULT hres;
3264 
3265     TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3266 
3267     if (!cmq || !pResults)
3268         return E_INVALIDARG;
3269 
3270     if (pServerInfo)
3271         FIXME("() non-NULL pServerInfo not supported!\n");
3272 
3273     init_multi_qi(cmq, pResults, E_NOINTERFACE);
3274 
3275     hres = CoGetTreatAsClass(rclsid, &clsid);
3276     if(FAILED(hres))
3277         clsid = *rclsid;
3278 
3279     if (!(apt = COM_CurrentApt()))
3280     {
3281         if (!(apt = apartment_find_multi_threaded()))
3282         {
3283             ERR("apartment not initialised\n");
3284             return CO_E_NOTINITIALIZED;
3285         }
3286         apartment_release(apt);
3287     }
3288 
3289     /*
3290      * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3291      */
3292     if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3293     {
3294         IGlobalInterfaceTable *git = get_std_git();
3295         TRACE("Retrieving GIT\n");
3296         return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3297     }
3298 
3299     if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3300         hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3301         if (FAILED(hres))
3302             return hres;
3303         return return_multi_qi(unk, cmq, pResults, TRUE);
3304     }
3305 
3306     /*
3307      * Get a class factory to construct the object we want.
3308      */
3309     hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3310     if (FAILED(hres))
3311         return hres;
3312 
3313     /*
3314      * Create the object and don't forget to release the factory
3315      */
3316     hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3317     IClassFactory_Release(cf);
3318     if (FAILED(hres))
3319     {
3320         if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3321             FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3322         else
3323             FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3324                   debugstr_guid(pResults[0].pIID),
3325                   debugstr_guid(&clsid),hres);
3326         return hres;
3327     }
3328 
3329     return return_multi_qi(unk, cmq, pResults, TRUE);
3330 }
3331 
3332 /***********************************************************************
3333  *           CoGetInstanceFromFile [OLE32.@]
3334  */
3335 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3336   COSERVERINFO *server_info,
3337   CLSID        *rclsid,
3338   IUnknown     *outer,
3339   DWORD         cls_context,
3340   DWORD         grfmode,
3341   OLECHAR      *filename,
3342   DWORD         count,
3343   MULTI_QI     *results
3344 )
3345 {
3346   IPersistFile *pf = NULL;
3347   IUnknown* unk = NULL;
3348   CLSID clsid;
3349   HRESULT hr;
3350 
3351   if (count == 0 || !results)
3352     return E_INVALIDARG;
3353 
3354   if (server_info)
3355     FIXME("() non-NULL server_info not supported\n");
3356 
3357   init_multi_qi(count, results, E_NOINTERFACE);
3358 
3359   /* optionally get CLSID from a file */
3360   if (!rclsid)
3361   {
3362     hr = GetClassFile(filename, &clsid);
3363     if (FAILED(hr))
3364     {
3365       ERR("failed to get CLSID from a file\n");
3366       return hr;
3367     }
3368 
3369     rclsid = &clsid;
3370   }
3371 
3372   hr = CoCreateInstance(rclsid,
3373 			outer,
3374 			cls_context,
3375 			&IID_IUnknown,
3376 			(void**)&unk);
3377 
3378   if (hr != S_OK)
3379   {
3380       init_multi_qi(count, results, hr);
3381       return hr;
3382   }
3383 
3384   /* init from file */
3385   hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3386   if (FAILED(hr))
3387   {
3388       init_multi_qi(count, results, hr);
3389       IUnknown_Release(unk);
3390       return hr;
3391   }
3392 
3393   hr = IPersistFile_Load(pf, filename, grfmode);
3394   IPersistFile_Release(pf);
3395   if (SUCCEEDED(hr))
3396       return return_multi_qi(unk, count, results, FALSE);
3397   else
3398   {
3399       init_multi_qi(count, results, hr);
3400       IUnknown_Release(unk);
3401       return hr;
3402   }
3403 }
3404 
3405 /***********************************************************************
3406  *           CoGetInstanceFromIStorage [OLE32.@]
3407  */
3408 HRESULT WINAPI CoGetInstanceFromIStorage(
3409   COSERVERINFO *server_info,
3410   CLSID        *rclsid,
3411   IUnknown     *outer,
3412   DWORD         cls_context,
3413   IStorage     *storage,
3414   DWORD         count,
3415   MULTI_QI     *results
3416 )
3417 {
3418   IPersistStorage *ps = NULL;
3419   IUnknown* unk = NULL;
3420   STATSTG stat;
3421   HRESULT hr;
3422 
3423   if (count == 0 || !results || !storage)
3424     return E_INVALIDARG;
3425 
3426   if (server_info)
3427     FIXME("() non-NULL server_info not supported\n");
3428 
3429   init_multi_qi(count, results, E_NOINTERFACE);
3430 
3431   /* optionally get CLSID from a file */
3432   if (!rclsid)
3433   {
3434     memset(&stat.clsid, 0, sizeof(stat.clsid));
3435     hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3436     if (FAILED(hr))
3437     {
3438       ERR("failed to get CLSID from a file\n");
3439       return hr;
3440     }
3441 
3442     rclsid = &stat.clsid;
3443   }
3444 
3445   hr = CoCreateInstance(rclsid,
3446 			outer,
3447 			cls_context,
3448 			&IID_IUnknown,
3449 			(void**)&unk);
3450 
3451   if (hr != S_OK)
3452     return hr;
3453 
3454   /* init from IStorage */
3455   hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3456   if (FAILED(hr))
3457       ERR("failed to get IPersistStorage\n");
3458 
3459   if (ps)
3460   {
3461       IPersistStorage_Load(ps, storage);
3462       IPersistStorage_Release(ps);
3463   }
3464 
3465   return return_multi_qi(unk, count, results, FALSE);
3466 }
3467 
3468 /***********************************************************************
3469  *           CoLoadLibrary (OLE32.@)
3470  *
3471  * Loads a library.
3472  *
3473  * PARAMS
3474  *  lpszLibName [I] Path to library.
3475  *  bAutoFree   [I] Whether the library should automatically be freed.
3476  *
3477  * RETURNS
3478  *  Success: Handle to loaded library.
3479  *  Failure: NULL.
3480  *
3481  * SEE ALSO
3482  *  CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3483  */
3484 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3485 {
3486     TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3487 
3488     return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3489 }
3490 
3491 /***********************************************************************
3492  *           CoFreeLibrary [OLE32.@]
3493  *
3494  * Unloads a library from memory.
3495  *
3496  * PARAMS
3497  *  hLibrary [I] Handle to library to unload.
3498  *
3499  * RETURNS
3500  *  Nothing
3501  *
3502  * SEE ALSO
3503  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3504  */
3505 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3506 {
3507     FreeLibrary(hLibrary);
3508 }
3509 
3510 
3511 /***********************************************************************
3512  *           CoFreeAllLibraries [OLE32.@]
3513  *
3514  * Function for backwards compatibility only. Does nothing.
3515  *
3516  * RETURNS
3517  *  Nothing.
3518  *
3519  * SEE ALSO
3520  *  CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3521  */
3522 void WINAPI CoFreeAllLibraries(void)
3523 {
3524     /* NOP */
3525 }
3526 
3527 /***********************************************************************
3528  *           CoFreeUnusedLibrariesEx [OLE32.@]
3529  *
3530  * Frees any previously unused libraries whose delay has expired and marks
3531  * currently unused libraries for unloading. Unused are identified as those that
3532  * return S_OK from their DllCanUnloadNow function.
3533  *
3534  * PARAMS
3535  *  dwUnloadDelay [I] Unload delay in milliseconds.
3536  *  dwReserved    [I] Reserved. Set to 0.
3537  *
3538  * RETURNS
3539  *  Nothing.
3540  *
3541  * SEE ALSO
3542  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3543  */
3544 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3545 {
3546     struct apartment *apt = COM_CurrentApt();
3547     if (!apt)
3548     {
3549         ERR("apartment not initialised\n");
3550         return;
3551     }
3552 
3553     apartment_freeunusedlibraries(apt, dwUnloadDelay);
3554 }
3555 
3556 /***********************************************************************
3557  *           CoFreeUnusedLibraries [OLE32.@]
3558  *
3559  * Frees any unused libraries. Unused are identified as those that return
3560  * S_OK from their DllCanUnloadNow function.
3561  *
3562  * RETURNS
3563  *  Nothing.
3564  *
3565  * SEE ALSO
3566  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3567  */
3568 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3569 {
3570     CoFreeUnusedLibrariesEx(INFINITE, 0);
3571 }
3572 
3573 /***********************************************************************
3574  *           CoFileTimeNow [OLE32.@]
3575  *
3576  * Retrieves the current time in FILETIME format.
3577  *
3578  * PARAMS
3579  *  lpFileTime [O] The current time.
3580  *
3581  * RETURNS
3582  *	S_OK.
3583  */
3584 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3585 {
3586     GetSystemTimeAsFileTime( lpFileTime );
3587     return S_OK;
3588 }
3589 
3590 /******************************************************************************
3591  *		CoLockObjectExternal	[OLE32.@]
3592  *
3593  * Increments or decrements the external reference count of a stub object.
3594  *
3595  * PARAMS
3596  *  pUnk                [I] Stub object.
3597  *  fLock               [I] If TRUE then increments the external ref-count,
3598  *                          otherwise decrements.
3599  *  fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3600  *                          calling CoDisconnectObject.
3601  *
3602  * RETURNS
3603  *  Success: S_OK.
3604  *  Failure: HRESULT code.
3605  *
3606  * NOTES
3607  *  If fLock is TRUE and an object is passed in that doesn't have a stub
3608  *  manager then a new stub manager is created for the object.
3609  */
3610 HRESULT WINAPI CoLockObjectExternal(
3611     LPUNKNOWN pUnk,
3612     BOOL fLock,
3613     BOOL fLastUnlockReleases)
3614 {
3615     struct stub_manager *stubmgr;
3616     struct apartment *apt;
3617 
3618     TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3619           pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3620 
3621     apt = COM_CurrentApt();
3622     if (!apt) return CO_E_NOTINITIALIZED;
3623 
3624     stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3625     if (!stubmgr)
3626     {
3627         WARN("stub object not found %p\n", pUnk);
3628         /* Note: native is pretty broken here because it just silently
3629          * fails, without returning an appropriate error code, making apps
3630          * think that the object was disconnected, when it actually wasn't */
3631         return S_OK;
3632     }
3633 
3634     if (fLock)
3635         stub_manager_ext_addref(stubmgr, 1, FALSE);
3636     else
3637         stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3638 
3639     stub_manager_int_release(stubmgr);
3640     return S_OK;
3641 }
3642 
3643 /***********************************************************************
3644  *           CoInitializeWOW (OLE32.@)
3645  *
3646  * WOW equivalent of CoInitialize?
3647  *
3648  * PARAMS
3649  *  x [I] Unknown.
3650  *  y [I] Unknown.
3651  *
3652  * RETURNS
3653  *  Unknown.
3654  */
3655 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3656 {
3657     FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3658     return 0;
3659 }
3660 
3661 /***********************************************************************
3662  *           CoGetState [OLE32.@]
3663  *
3664  * Retrieves the thread state object previously stored by CoSetState().
3665  *
3666  * PARAMS
3667  *  ppv [I] Address where pointer to object will be stored.
3668  *
3669  * RETURNS
3670  *  Success: S_OK.
3671  *  Failure: E_OUTOFMEMORY.
3672  *
3673  * NOTES
3674  *  Crashes on all invalid ppv addresses, including NULL.
3675  *  If the function returns a non-NULL object then the caller must release its
3676  *  reference on the object when the object is no longer required.
3677  *
3678  * SEE ALSO
3679  *  CoSetState().
3680  */
3681 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3682 {
3683     struct oletls *info = COM_CurrentInfo();
3684     if (!info) return E_OUTOFMEMORY;
3685 
3686     *ppv = NULL;
3687 
3688     if (info->state)
3689     {
3690         IUnknown_AddRef(info->state);
3691         *ppv = info->state;
3692         TRACE("apt->state=%p\n", info->state);
3693     }
3694 
3695     return S_OK;
3696 }
3697 
3698 /***********************************************************************
3699  *           CoSetState [OLE32.@]
3700  *
3701  * Sets the thread state object.
3702  *
3703  * PARAMS
3704  *  pv [I] Pointer to state object to be stored.
3705  *
3706  * NOTES
3707  *  The system keeps a reference on the object while the object stored.
3708  *
3709  * RETURNS
3710  *  Success: S_OK.
3711  *  Failure: E_OUTOFMEMORY.
3712  */
3713 HRESULT WINAPI CoSetState(IUnknown * pv)
3714 {
3715     struct oletls *info = COM_CurrentInfo();
3716     if (!info) return E_OUTOFMEMORY;
3717 
3718     if (pv) IUnknown_AddRef(pv);
3719 
3720     if (info->state)
3721     {
3722         TRACE("-- release %p now\n", info->state);
3723         IUnknown_Release(info->state);
3724     }
3725 
3726     info->state = pv;
3727 
3728     return S_OK;
3729 }
3730 
3731 
3732 /******************************************************************************
3733  *              CoTreatAsClass        [OLE32.@]
3734  *
3735  * Sets the TreatAs value of a class.
3736  *
3737  * PARAMS
3738  *  clsidOld [I] Class to set TreatAs value on.
3739  *  clsidNew [I] The class the clsidOld should be treated as.
3740  *
3741  * RETURNS
3742  *  Success: S_OK.
3743  *  Failure: HRESULT code.
3744  *
3745  * SEE ALSO
3746  *  CoGetTreatAsClass
3747  */
3748 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3749 {
3750     static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3751     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3752     HKEY hkey = NULL;
3753     WCHAR szClsidNew[CHARS_IN_GUID];
3754     HRESULT res = S_OK;
3755     WCHAR auto_treat_as[CHARS_IN_GUID];
3756     LONG auto_treat_as_size = sizeof(auto_treat_as);
3757     CLSID id;
3758 
3759     res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3760     if (FAILED(res))
3761         goto done;
3762 
3763     if (IsEqualGUID( clsidOld, clsidNew ))
3764     {
3765        if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3766            CLSIDFromString(auto_treat_as, &id) == S_OK)
3767        {
3768            if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3769            {
3770                res = REGDB_E_WRITEREGDB;
3771                goto done;
3772            }
3773        }
3774        else
3775        {
3776            if(RegDeleteKeyW(hkey, wszTreatAs))
3777                res = REGDB_E_WRITEREGDB;
3778            goto done;
3779        }
3780     }
3781     else
3782     {
3783         if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3784            RegDeleteKeyW(hkey, wszTreatAs);
3785         }else{
3786             if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3787                 WARN("StringFromGUID2 failed\n");
3788                 res = E_FAIL;
3789                 goto done;
3790             }
3791 
3792             if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3793                 WARN("RegSetValue failed\n");
3794                 res = REGDB_E_WRITEREGDB;
3795                 goto done;
3796             }
3797         }
3798     }
3799 
3800 done:
3801     if (hkey) RegCloseKey(hkey);
3802     return res;
3803 }
3804 
3805 /******************************************************************************
3806  *              CoGetTreatAsClass        [OLE32.@]
3807  *
3808  * Gets the TreatAs value of a class.
3809  *
3810  * PARAMS
3811  *  clsidOld [I] Class to get the TreatAs value of.
3812  *  clsidNew [I] The class the clsidOld should be treated as.
3813  *
3814  * RETURNS
3815  *  Success: S_OK.
3816  *  Failure: HRESULT code.
3817  *
3818  * SEE ALSO
3819  *  CoSetTreatAsClass
3820  */
3821 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3822 {
3823     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3824     HKEY hkey = NULL;
3825     WCHAR szClsidNew[CHARS_IN_GUID];
3826     HRESULT res = S_OK;
3827     LONG len = sizeof(szClsidNew);
3828 
3829     TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3830 
3831     if (!clsidOld || !clsidNew)
3832         return E_INVALIDARG;
3833 
3834     *clsidNew = *clsidOld; /* copy over old value */
3835 
3836     res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3837     if (FAILED(res))
3838     {
3839         res = S_FALSE;
3840         goto done;
3841     }
3842     if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3843     {
3844         res = S_FALSE;
3845 	goto done;
3846     }
3847     res = CLSIDFromString(szClsidNew,clsidNew);
3848     if (FAILED(res))
3849         ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3850 done:
3851     if (hkey) RegCloseKey(hkey);
3852     return res;
3853 }
3854 
3855 /******************************************************************************
3856  *		CoGetCurrentProcess	[OLE32.@]
3857  *
3858  * Gets the current process ID.
3859  *
3860  * RETURNS
3861  *  The current process ID.
3862  *
3863  * NOTES
3864  *   Is DWORD really the correct return type for this function?
3865  */
3866 DWORD WINAPI CoGetCurrentProcess(void)
3867 {
3868 	return GetCurrentProcessId();
3869 }
3870 
3871 /***********************************************************************
3872  *              CoGetCurrentLogicalThreadId        [OLE32.@]
3873  */
3874 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
3875 {
3876     TRACE("(%p)\n", id);
3877 
3878     if (!id)
3879         return E_INVALIDARG;
3880 
3881     *id = COM_CurrentCausalityId();
3882     return S_OK;
3883 }
3884 
3885 /******************************************************************************
3886  *		CoRegisterMessageFilter	[OLE32.@]
3887  *
3888  * Registers a message filter.
3889  *
3890  * PARAMS
3891  *  lpMessageFilter [I] Pointer to interface.
3892  *  lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3893  *
3894  * RETURNS
3895  *  Success: S_OK.
3896  *  Failure: HRESULT code.
3897  *
3898  * NOTES
3899  *  Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3900  *  lpMessageFilter removes the message filter.
3901  *
3902  *  If lplpMessageFilter is not NULL the previous message filter will be
3903  *  returned in the memory pointer to this parameter and the caller is
3904  *  responsible for releasing the object.
3905  *
3906  *  The current thread be in an apartment otherwise the function will crash.
3907  */
3908 HRESULT WINAPI CoRegisterMessageFilter(
3909     LPMESSAGEFILTER lpMessageFilter,
3910     LPMESSAGEFILTER *lplpMessageFilter)
3911 {
3912     struct apartment *apt;
3913     IMessageFilter *lpOldMessageFilter;
3914 
3915     TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3916 
3917     apt = COM_CurrentApt();
3918 
3919     /* can't set a message filter in a multi-threaded apartment */
3920     if (!apt || apt->multi_threaded)
3921     {
3922         WARN("can't set message filter in MTA or uninitialized apt\n");
3923         return CO_E_NOT_SUPPORTED;
3924     }
3925 
3926     if (lpMessageFilter)
3927         IMessageFilter_AddRef(lpMessageFilter);
3928 
3929     EnterCriticalSection(&apt->cs);
3930 
3931     lpOldMessageFilter = apt->filter;
3932     apt->filter = lpMessageFilter;
3933 
3934     LeaveCriticalSection(&apt->cs);
3935 
3936     if (lplpMessageFilter)
3937         *lplpMessageFilter = lpOldMessageFilter;
3938     else if (lpOldMessageFilter)
3939         IMessageFilter_Release(lpOldMessageFilter);
3940 
3941     return S_OK;
3942 }
3943 
3944 /***********************************************************************
3945  *           CoIsOle1Class [OLE32.@]
3946  *
3947  * Determines whether the specified class an OLE v1 class.
3948  *
3949  * PARAMS
3950  *  clsid [I] Class to test.
3951  *
3952  * RETURNS
3953  *  TRUE if the class is an OLE v1 class, or FALSE otherwise.
3954  */
3955 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3956 {
3957   FIXME("%s\n", debugstr_guid(clsid));
3958   return FALSE;
3959 }
3960 
3961 /***********************************************************************
3962  *           IsEqualGUID [OLE32.@]
3963  *
3964  * Compares two Unique Identifiers.
3965  *
3966  * PARAMS
3967  *  rguid1 [I] The first GUID to compare.
3968  *  rguid2 [I] The other GUID to compare.
3969  *
3970  * RETURNS
3971  *	TRUE if equal
3972  */
3973 #undef IsEqualGUID
3974 BOOL WINAPI IsEqualGUID(
3975      REFGUID rguid1,
3976      REFGUID rguid2)
3977 {
3978     return !memcmp(rguid1,rguid2,sizeof(GUID));
3979 }
3980 
3981 /***********************************************************************
3982  *           CoInitializeSecurity [OLE32.@]
3983  */
3984 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3985                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3986                                     void* pReserved1, DWORD dwAuthnLevel,
3987                                     DWORD dwImpLevel, void* pReserved2,
3988                                     DWORD dwCapabilities, void* pReserved3)
3989 {
3990   FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3991         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3992         dwCapabilities, pReserved3);
3993   return S_OK;
3994 }
3995 
3996 /***********************************************************************
3997  *           CoSuspendClassObjects [OLE32.@]
3998  *
3999  * Suspends all registered class objects to prevent further requests coming in
4000  * for those objects.
4001  *
4002  * RETURNS
4003  *  Success: S_OK.
4004  *  Failure: HRESULT code.
4005  */
4006 HRESULT WINAPI CoSuspendClassObjects(void)
4007 {
4008     FIXME("\n");
4009     return S_OK;
4010 }
4011 
4012 /***********************************************************************
4013  *           CoAddRefServerProcess [OLE32.@]
4014  *
4015  * Helper function for incrementing the reference count of a local-server
4016  * process.
4017  *
4018  * RETURNS
4019  *  New reference count.
4020  *
4021  * SEE ALSO
4022  *  CoReleaseServerProcess().
4023  */
4024 ULONG WINAPI CoAddRefServerProcess(void)
4025 {
4026     ULONG refs;
4027 
4028     TRACE("\n");
4029 
4030     EnterCriticalSection(&csRegisteredClassList);
4031     refs = ++s_COMServerProcessReferences;
4032     LeaveCriticalSection(&csRegisteredClassList);
4033 
4034     TRACE("refs before: %d\n", refs - 1);
4035 
4036     return refs;
4037 }
4038 
4039 /***********************************************************************
4040  *           CoReleaseServerProcess [OLE32.@]
4041  *
4042  * Helper function for decrementing the reference count of a local-server
4043  * process.
4044  *
4045  * RETURNS
4046  *  New reference count.
4047  *
4048  * NOTES
4049  *  When reference count reaches 0, this function suspends all registered
4050  *  classes so no new connections are accepted.
4051  *
4052  * SEE ALSO
4053  *  CoAddRefServerProcess(), CoSuspendClassObjects().
4054  */
4055 ULONG WINAPI CoReleaseServerProcess(void)
4056 {
4057     ULONG refs;
4058 
4059     TRACE("\n");
4060 
4061     EnterCriticalSection(&csRegisteredClassList);
4062 
4063     refs = --s_COMServerProcessReferences;
4064     /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4065 
4066     LeaveCriticalSection(&csRegisteredClassList);
4067 
4068     TRACE("refs after: %d\n", refs);
4069 
4070     return refs;
4071 }
4072 
4073 /***********************************************************************
4074  *           CoIsHandlerConnected [OLE32.@]
4075  *
4076  * Determines whether a proxy is connected to a remote stub.
4077  *
4078  * PARAMS
4079  *  pUnk [I] Pointer to object that may or may not be connected.
4080  *
4081  * RETURNS
4082  *  TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4083  *  FALSE otherwise.
4084  */
4085 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4086 {
4087     FIXME("%p\n", pUnk);
4088 
4089     return TRUE;
4090 }
4091 
4092 /***********************************************************************
4093  *           CoAllowSetForegroundWindow [OLE32.@]
4094  *
4095  */
4096 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4097 {
4098     FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4099     return S_OK;
4100 }
4101 
4102 /***********************************************************************
4103  *           CoQueryProxyBlanket [OLE32.@]
4104  *
4105  * Retrieves the security settings being used by a proxy.
4106  *
4107  * PARAMS
4108  *  pProxy        [I] Pointer to the proxy object.
4109  *  pAuthnSvc     [O] The type of authentication service.
4110  *  pAuthzSvc     [O] The type of authorization service.
4111  *  ppServerPrincName [O] Optional. The server prinicple name.
4112  *  pAuthnLevel   [O] The authentication level.
4113  *  pImpLevel     [O] The impersonation level.
4114  *  ppAuthInfo    [O] Information specific to the authorization/authentication service.
4115  *  pCapabilities [O] Flags affecting the security behaviour.
4116  *
4117  * RETURNS
4118  *  Success: S_OK.
4119  *  Failure: HRESULT code.
4120  *
4121  * SEE ALSO
4122  *  CoCopyProxy, CoSetProxyBlanket.
4123  */
4124 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4125     DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4126     DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4127 {
4128     IClientSecurity *pCliSec;
4129     HRESULT hr;
4130 
4131     TRACE("%p\n", pProxy);
4132 
4133     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4134     if (SUCCEEDED(hr))
4135     {
4136         hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4137                                           pAuthzSvc, ppServerPrincName,
4138                                           pAuthnLevel, pImpLevel, ppAuthInfo,
4139                                           pCapabilities);
4140         IClientSecurity_Release(pCliSec);
4141     }
4142 
4143     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4144     return hr;
4145 }
4146 
4147 /***********************************************************************
4148  *           CoSetProxyBlanket [OLE32.@]
4149  *
4150  * Sets the security settings for a proxy.
4151  *
4152  * PARAMS
4153  *  pProxy       [I] Pointer to the proxy object.
4154  *  AuthnSvc     [I] The type of authentication service.
4155  *  AuthzSvc     [I] The type of authorization service.
4156  *  pServerPrincName [I] The server prinicple name.
4157  *  AuthnLevel   [I] The authentication level.
4158  *  ImpLevel     [I] The impersonation level.
4159  *  pAuthInfo    [I] Information specific to the authorization/authentication service.
4160  *  Capabilities [I] Flags affecting the security behaviour.
4161  *
4162  * RETURNS
4163  *  Success: S_OK.
4164  *  Failure: HRESULT code.
4165  *
4166  * SEE ALSO
4167  *  CoQueryProxyBlanket, CoCopyProxy.
4168  */
4169 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4170     DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4171     DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4172 {
4173     IClientSecurity *pCliSec;
4174     HRESULT hr;
4175 
4176     TRACE("%p\n", pProxy);
4177 
4178     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4179     if (SUCCEEDED(hr))
4180     {
4181         hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4182                                         AuthzSvc, pServerPrincName,
4183                                         AuthnLevel, ImpLevel, pAuthInfo,
4184                                         Capabilities);
4185         IClientSecurity_Release(pCliSec);
4186     }
4187 
4188     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4189     return hr;
4190 }
4191 
4192 /***********************************************************************
4193  *           CoCopyProxy [OLE32.@]
4194  *
4195  * Copies a proxy.
4196  *
4197  * PARAMS
4198  *  pProxy [I] Pointer to the proxy object.
4199  *  ppCopy [O] Copy of the proxy.
4200  *
4201  * RETURNS
4202  *  Success: S_OK.
4203  *  Failure: HRESULT code.
4204  *
4205  * SEE ALSO
4206  *  CoQueryProxyBlanket, CoSetProxyBlanket.
4207  */
4208 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4209 {
4210     IClientSecurity *pCliSec;
4211     HRESULT hr;
4212 
4213     TRACE("%p\n", pProxy);
4214 
4215     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4216     if (SUCCEEDED(hr))
4217     {
4218         hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4219         IClientSecurity_Release(pCliSec);
4220     }
4221 
4222     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4223     return hr;
4224 }
4225 
4226 
4227 /***********************************************************************
4228  *           CoGetCallContext [OLE32.@]
4229  *
4230  * Gets the context of the currently executing server call in the current
4231  * thread.
4232  *
4233  * PARAMS
4234  *  riid [I] Context interface to return.
4235  *  ppv  [O] Pointer to memory that will receive the context on return.
4236  *
4237  * RETURNS
4238  *  Success: S_OK.
4239  *  Failure: HRESULT code.
4240  */
4241 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4242 {
4243     struct oletls *info = COM_CurrentInfo();
4244 
4245     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4246 
4247     if (!info)
4248         return E_OUTOFMEMORY;
4249 
4250     if (!info->call_state)
4251         return RPC_E_CALL_COMPLETE;
4252 
4253     return IUnknown_QueryInterface(info->call_state, riid, ppv);
4254 }
4255 
4256 /***********************************************************************
4257  *           CoSwitchCallContext [OLE32.@]
4258  *
4259  * Switches the context of the currently executing server call in the current
4260  * thread.
4261  *
4262  * PARAMS
4263  *  pObject     [I] Pointer to new context object
4264  *  ppOldObject [O] Pointer to memory that will receive old context object pointer
4265  *
4266  * RETURNS
4267  *  Success: S_OK.
4268  *  Failure: HRESULT code.
4269  */
4270 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4271 {
4272     struct oletls *info = COM_CurrentInfo();
4273 
4274     TRACE("(%p, %p)\n", pObject, ppOldObject);
4275 
4276     if (!info)
4277         return E_OUTOFMEMORY;
4278 
4279     *ppOldObject = info->call_state;
4280     info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4281 
4282     return S_OK;
4283 }
4284 
4285 /***********************************************************************
4286  *           CoQueryClientBlanket [OLE32.@]
4287  *
4288  * Retrieves the authentication information about the client of the currently
4289  * executing server call in the current thread.
4290  *
4291  * PARAMS
4292  *  pAuthnSvc     [O] Optional. The type of authentication service.
4293  *  pAuthzSvc     [O] Optional. The type of authorization service.
4294  *  pServerPrincName [O] Optional. The server prinicple name.
4295  *  pAuthnLevel   [O] Optional. The authentication level.
4296  *  pImpLevel     [O] Optional. The impersonation level.
4297  *  pPrivs        [O] Optional. Information about the privileges of the client.
4298  *  pCapabilities [IO] Optional. Flags affecting the security behaviour.
4299  *
4300  * RETURNS
4301  *  Success: S_OK.
4302  *  Failure: HRESULT code.
4303  *
4304  * SEE ALSO
4305  *  CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4306  */
4307 HRESULT WINAPI CoQueryClientBlanket(
4308     DWORD *pAuthnSvc,
4309     DWORD *pAuthzSvc,
4310     OLECHAR **pServerPrincName,
4311     DWORD *pAuthnLevel,
4312     DWORD *pImpLevel,
4313     RPC_AUTHZ_HANDLE *pPrivs,
4314     DWORD *pCapabilities)
4315 {
4316     IServerSecurity *pSrvSec;
4317     HRESULT hr;
4318 
4319     TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4320         pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4321         pPrivs, pCapabilities);
4322 
4323     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4324     if (SUCCEEDED(hr))
4325     {
4326         hr = IServerSecurity_QueryBlanket(
4327             pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4328             pImpLevel, pPrivs, pCapabilities);
4329         IServerSecurity_Release(pSrvSec);
4330     }
4331 
4332     return hr;
4333 }
4334 
4335 /***********************************************************************
4336  *           CoImpersonateClient [OLE32.@]
4337  *
4338  * Impersonates the client of the currently executing server call in the
4339  * current thread.
4340  *
4341  * PARAMS
4342  *  None.
4343  *
4344  * RETURNS
4345  *  Success: S_OK.
4346  *  Failure: HRESULT code.
4347  *
4348  * NOTES
4349  *  If this function fails then the current thread will not be impersonating
4350  *  the client and all actions will take place on behalf of the server.
4351  *  Therefore, it is important to check the return value from this function.
4352  *
4353  * SEE ALSO
4354  *  CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4355  */
4356 HRESULT WINAPI CoImpersonateClient(void)
4357 {
4358     IServerSecurity *pSrvSec;
4359     HRESULT hr;
4360 
4361     TRACE("\n");
4362 
4363     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4364     if (SUCCEEDED(hr))
4365     {
4366         hr = IServerSecurity_ImpersonateClient(pSrvSec);
4367         IServerSecurity_Release(pSrvSec);
4368     }
4369 
4370     return hr;
4371 }
4372 
4373 /***********************************************************************
4374  *           CoRevertToSelf [OLE32.@]
4375  *
4376  * Ends the impersonation of the client of the currently executing server
4377  * call in the current thread.
4378  *
4379  * PARAMS
4380  *  None.
4381  *
4382  * RETURNS
4383  *  Success: S_OK.
4384  *  Failure: HRESULT code.
4385  *
4386  * SEE ALSO
4387  *  CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4388  */
4389 HRESULT WINAPI CoRevertToSelf(void)
4390 {
4391     IServerSecurity *pSrvSec;
4392     HRESULT hr;
4393 
4394     TRACE("\n");
4395 
4396     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4397     if (SUCCEEDED(hr))
4398     {
4399         hr = IServerSecurity_RevertToSelf(pSrvSec);
4400         IServerSecurity_Release(pSrvSec);
4401     }
4402 
4403     return hr;
4404 }
4405 
4406 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4407 {
4408     /* first try to retrieve messages for incoming COM calls to the apartment window */
4409     return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4410            /* next retrieve other messages necessary for the app to remain responsive */
4411            PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4412            PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4413 }
4414 
4415 /***********************************************************************
4416  *           CoWaitForMultipleHandles [OLE32.@]
4417  *
4418  * Waits for one or more handles to become signaled.
4419  *
4420  * PARAMS
4421  *  dwFlags   [I] Flags. See notes.
4422  *  dwTimeout [I] Timeout in milliseconds.
4423  *  cHandles  [I] Number of handles pointed to by pHandles.
4424  *  pHandles  [I] Handles to wait for.
4425  *  lpdwindex [O] Index of handle that was signaled.
4426  *
4427  * RETURNS
4428  *  Success: S_OK.
4429  *  Failure: RPC_S_CALLPENDING on timeout.
4430  *
4431  * NOTES
4432  *
4433  * The dwFlags parameter can be zero or more of the following:
4434  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4435  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4436  *
4437  * SEE ALSO
4438  *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
4439  */
4440 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4441     ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4442 {
4443     HRESULT hr = S_OK;
4444     DWORD start_time = GetTickCount();
4445     APARTMENT *apt = COM_CurrentApt();
4446     BOOL message_loop = apt && !apt->multi_threaded;
4447     BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4448 
4449     TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4450         pHandles, lpdwindex);
4451 
4452     if (!lpdwindex)
4453         return E_INVALIDARG;
4454 
4455     *lpdwindex = 0;
4456 
4457     if (!pHandles)
4458         return E_INVALIDARG;
4459 
4460     if (!cHandles)
4461         return RPC_E_NO_SYNC;
4462 
4463     while (TRUE)
4464     {
4465         DWORD now = GetTickCount();
4466         DWORD res;
4467 
4468         if (now - start_time > dwTimeout)
4469         {
4470             hr = RPC_S_CALLPENDING;
4471             break;
4472         }
4473 
4474         if (message_loop)
4475         {
4476             DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4477                     ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4478 
4479             TRACE("waiting for rpc completion or window message\n");
4480 
4481             res = WAIT_TIMEOUT;
4482 
4483             if (check_apc)
4484             {
4485                 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4486                     (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4487                 check_apc = FALSE;
4488             }
4489 
4490             if (res == WAIT_TIMEOUT)
4491                 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4492                     (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4493                     QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4494 
4495             if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
4496             {
4497                 MSG msg;
4498                 int count = 0;
4499 
4500                 /* call message filter */
4501 
4502                 if (COM_CurrentApt()->filter)
4503                 {
4504                     PENDINGTYPE pendingtype =
4505                         COM_CurrentInfo()->pending_call_count_server ?
4506                             PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4507                     DWORD be_handled = IMessageFilter_MessagePending(
4508                         COM_CurrentApt()->filter, 0 /* FIXME */,
4509                         now - start_time, pendingtype);
4510                     TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4511                     switch (be_handled)
4512                     {
4513                     case PENDINGMSG_CANCELCALL:
4514                         WARN("call canceled\n");
4515                         hr = RPC_E_CALL_CANCELED;
4516                         break;
4517                     case PENDINGMSG_WAITNOPROCESS:
4518                     case PENDINGMSG_WAITDEFPROCESS:
4519                     default:
4520                         /* FIXME: MSDN is very vague about the difference
4521                          * between WAITNOPROCESS and WAITDEFPROCESS - there
4522                          * appears to be none, so it is possibly a left-over
4523                          * from the 16-bit world. */
4524                         break;
4525                     }
4526                 }
4527 
4528                 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4529                  * so after processing 100 messages we go back to checking the wait handles */
4530                 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4531                 {
4532                     TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4533                     TranslateMessage(&msg);
4534                     DispatchMessageW(&msg);
4535                     if (msg.message == WM_QUIT)
4536                     {
4537                         TRACE("resending WM_QUIT to outer message loop\n");
4538                         PostQuitMessage(msg.wParam);
4539                         /* no longer need to process messages */
4540                         message_loop = FALSE;
4541                         break;
4542                     }
4543                 }
4544                 continue;
4545             }
4546         }
4547         else
4548         {
4549             TRACE("waiting for rpc completion\n");
4550 
4551             res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4552                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4553                 (dwFlags & COWAIT_ALERTABLE) != 0);
4554         }
4555 
4556         switch (res)
4557         {
4558         case WAIT_TIMEOUT:
4559             hr = RPC_S_CALLPENDING;
4560             break;
4561         case WAIT_FAILED:
4562             hr = HRESULT_FROM_WIN32( GetLastError() );
4563             break;
4564         default:
4565             *lpdwindex = res;
4566             break;
4567         }
4568         break;
4569     }
4570     TRACE("-- 0x%08x\n", hr);
4571     return hr;
4572 }
4573 
4574 
4575 /***********************************************************************
4576  *           CoGetObject [OLE32.@]
4577  *
4578  * Gets the object named by converting the name to a moniker and binding to it.
4579  *
4580  * PARAMS
4581  *  pszName      [I] String representing the object.
4582  *  pBindOptions [I] Parameters affecting the binding to the named object.
4583  *  riid         [I] Interface to bind to on the objecct.
4584  *  ppv          [O] On output, the interface riid of the object represented
4585  *                   by pszName.
4586  *
4587  * RETURNS
4588  *  Success: S_OK.
4589  *  Failure: HRESULT code.
4590  *
4591  * SEE ALSO
4592  *  MkParseDisplayName.
4593  */
4594 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4595     REFIID riid, void **ppv)
4596 {
4597     IBindCtx *pbc;
4598     HRESULT hr;
4599 
4600     *ppv = NULL;
4601 
4602     hr = CreateBindCtx(0, &pbc);
4603     if (SUCCEEDED(hr))
4604     {
4605         if (pBindOptions)
4606             hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4607 
4608         if (SUCCEEDED(hr))
4609         {
4610             ULONG chEaten;
4611             IMoniker *pmk;
4612 
4613             hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4614             if (SUCCEEDED(hr))
4615             {
4616                 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4617                 IMoniker_Release(pmk);
4618             }
4619         }
4620 
4621         IBindCtx_Release(pbc);
4622     }
4623     return hr;
4624 }
4625 
4626 /***********************************************************************
4627  *           CoRegisterChannelHook [OLE32.@]
4628  *
4629  * Registers a process-wide hook that is called during ORPC calls.
4630  *
4631  * PARAMS
4632  *  guidExtension [I] GUID of the channel hook to register.
4633  *  pChannelHook  [I] Channel hook object to register.
4634  *
4635  * RETURNS
4636  *  Success: S_OK.
4637  *  Failure: HRESULT code.
4638  */
4639 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4640 {
4641     TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4642 
4643     return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4644 }
4645 
4646 typedef struct Context
4647 {
4648     IComThreadingInfo IComThreadingInfo_iface;
4649     IContextCallback IContextCallback_iface;
4650     IObjContext IObjContext_iface;
4651     LONG refs;
4652 } Context;
4653 
4654 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4655 {
4656         return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4657 }
4658 
4659 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4660 {
4661         return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4662 }
4663 
4664 static inline Context *impl_from_IObjContext( IObjContext *iface )
4665 {
4666         return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4667 }
4668 
4669 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4670 {
4671     *ppv = NULL;
4672 
4673     if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4674         IsEqualIID(riid, &IID_IUnknown))
4675     {
4676         *ppv = &iface->IComThreadingInfo_iface;
4677     }
4678     else if (IsEqualIID(riid, &IID_IContextCallback))
4679     {
4680         *ppv = &iface->IContextCallback_iface;
4681     }
4682     else if (IsEqualIID(riid, &IID_IObjContext))
4683     {
4684         *ppv = &iface->IObjContext_iface;
4685     }
4686 
4687     if (*ppv)
4688     {
4689         IUnknown_AddRef((IUnknown*)*ppv);
4690         return S_OK;
4691     }
4692 
4693     FIXME("interface not implemented %s\n", debugstr_guid(riid));
4694     return E_NOINTERFACE;
4695 }
4696 
4697 static ULONG Context_AddRef(Context *This)
4698 {
4699     return InterlockedIncrement(&This->refs);
4700 }
4701 
4702 static ULONG Context_Release(Context *This)
4703 {
4704     /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4705        releasing context while refcount is at 0 destroys it. */
4706     if (!This->refs)
4707     {
4708         HeapFree(GetProcessHeap(), 0, This);
4709         return 0;
4710     }
4711 
4712     return InterlockedDecrement(&This->refs);
4713 }
4714 
4715 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4716 {
4717     Context *This = impl_from_IComThreadingInfo(iface);
4718     return Context_QueryInterface(This, riid, ppv);
4719 }
4720 
4721 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4722 {
4723     Context *This = impl_from_IComThreadingInfo(iface);
4724     return Context_AddRef(This);
4725 }
4726 
4727 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4728 {
4729     Context *This = impl_from_IComThreadingInfo(iface);
4730     return Context_Release(This);
4731 }
4732 
4733 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4734 {
4735     APTTYPEQUALIFIER qualifier;
4736 
4737     TRACE("(%p)\n", apttype);
4738 
4739     return CoGetApartmentType(apttype, &qualifier);
4740 }
4741 
4742 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4743 {
4744     APTTYPEQUALIFIER qualifier;
4745     APTTYPE apttype;
4746     HRESULT hr;
4747 
4748     hr = CoGetApartmentType(&apttype, &qualifier);
4749     if (FAILED(hr))
4750         return hr;
4751 
4752     TRACE("(%p)\n", thdtype);
4753 
4754     switch (apttype)
4755     {
4756     case APTTYPE_STA:
4757     case APTTYPE_MAINSTA:
4758         *thdtype = THDTYPE_PROCESSMESSAGES;
4759         break;
4760     default:
4761         *thdtype = THDTYPE_BLOCKMESSAGES;
4762         break;
4763     }
4764     return S_OK;
4765 }
4766 
4767 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4768 {
4769     TRACE("(%p)\n", logical_thread_id);
4770     return CoGetCurrentLogicalThreadId(logical_thread_id);
4771 }
4772 
4773 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4774 {
4775     FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4776     return E_NOTIMPL;
4777 }
4778 
4779 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4780 {
4781     Context_CTI_QueryInterface,
4782     Context_CTI_AddRef,
4783     Context_CTI_Release,
4784     Context_CTI_GetCurrentApartmentType,
4785     Context_CTI_GetCurrentThreadType,
4786     Context_CTI_GetCurrentLogicalThreadId,
4787     Context_CTI_SetCurrentLogicalThreadId
4788 };
4789 
4790 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4791 {
4792     Context *This = impl_from_IContextCallback(iface);
4793     return Context_QueryInterface(This, riid, ppv);
4794 }
4795 
4796 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4797 {
4798     Context *This = impl_from_IContextCallback(iface);
4799     return Context_AddRef(This);
4800 }
4801 
4802 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4803 {
4804     Context *This = impl_from_IContextCallback(iface);
4805     return Context_Release(This);
4806 }
4807 
4808 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4809                             ComCallData *param, REFIID riid, int method, IUnknown *punk)
4810 {
4811     Context *This = impl_from_IContextCallback(iface);
4812 
4813     FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4814     return E_NOTIMPL;
4815 }
4816 
4817 static const IContextCallbackVtbl Context_Callback_Vtbl =
4818 {
4819     Context_CC_QueryInterface,
4820     Context_CC_AddRef,
4821     Context_CC_Release,
4822     Context_CC_ContextCallback
4823 };
4824 
4825 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4826 {
4827     Context *This = impl_from_IObjContext(iface);
4828     return Context_QueryInterface(This, riid, ppv);
4829 }
4830 
4831 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4832 {
4833     Context *This = impl_from_IObjContext(iface);
4834     return Context_AddRef(This);
4835 }
4836 
4837 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4838 {
4839     Context *This = impl_from_IObjContext(iface);
4840     return Context_Release(This);
4841 }
4842 
4843 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4844 {
4845     Context *This = impl_from_IObjContext(iface);
4846 
4847     FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4848     return E_NOTIMPL;
4849 }
4850 
4851 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4852 {
4853     Context *This = impl_from_IObjContext(iface);
4854 
4855     FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4856     return E_NOTIMPL;
4857 }
4858 
4859 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4860 {
4861     Context *This = impl_from_IObjContext(iface);
4862 
4863     FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4864     return E_NOTIMPL;
4865 }
4866 
4867 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4868 {
4869     Context *This = impl_from_IObjContext(iface);
4870 
4871     FIXME("(%p/%p)->(%p)\n", This, iface, props);
4872     return E_NOTIMPL;
4873 }
4874 
4875 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4876 {
4877     Context *This = impl_from_IObjContext(iface);
4878     FIXME("(%p/%p)\n", This, iface);
4879 }
4880 
4881 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4882 {
4883     Context *This = impl_from_IObjContext(iface);
4884     FIXME("(%p/%p)\n", This, iface);
4885 }
4886 
4887 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4888 {
4889     Context *This = impl_from_IObjContext(iface);
4890     FIXME("(%p/%p)\n", This, iface);
4891 }
4892 
4893 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4894 {
4895     Context *This = impl_from_IObjContext(iface);
4896     FIXME("(%p/%p)\n", This, iface);
4897 }
4898 
4899 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4900 {
4901     Context *This = impl_from_IObjContext(iface);
4902     FIXME("(%p/%p)\n", This, iface);
4903 }
4904 
4905 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4906 {
4907     Context *This = impl_from_IObjContext(iface);
4908     FIXME("(%p/%p)\n", This, iface);
4909 }
4910 
4911 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4912 {
4913     Context *This = impl_from_IObjContext(iface);
4914     FIXME("(%p/%p)\n", This, iface);
4915 }
4916 
4917 static const IObjContextVtbl Context_Object_Vtbl =
4918 {
4919     Context_OC_QueryInterface,
4920     Context_OC_AddRef,
4921     Context_OC_Release,
4922     Context_OC_SetProperty,
4923     Context_OC_RemoveProperty,
4924     Context_OC_GetProperty,
4925     Context_OC_EnumContextProps,
4926     Context_OC_Reserved1,
4927     Context_OC_Reserved2,
4928     Context_OC_Reserved3,
4929     Context_OC_Reserved4,
4930     Context_OC_Reserved5,
4931     Context_OC_Reserved6,
4932     Context_OC_Reserved7
4933 };
4934 
4935 /***********************************************************************
4936  *           CoGetObjectContext [OLE32.@]
4937  *
4938  * Retrieves an object associated with the current context (i.e. apartment).
4939  *
4940  * PARAMS
4941  *  riid [I] ID of the interface of the object to retrieve.
4942  *  ppv  [O] Address where object will be stored on return.
4943  *
4944  * RETURNS
4945  *  Success: S_OK.
4946  *  Failure: HRESULT code.
4947  */
4948 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4949 {
4950     IObjContext *context;
4951     HRESULT hr;
4952 
4953     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4954 
4955     *ppv = NULL;
4956     hr = CoGetContextToken((ULONG_PTR*)&context);
4957     if (FAILED(hr))
4958         return hr;
4959 
4960     return IObjContext_QueryInterface(context, riid, ppv);
4961 }
4962 
4963 /***********************************************************************
4964  *           CoGetContextToken [OLE32.@]
4965  */
4966 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4967 {
4968     struct oletls *info = COM_CurrentInfo();
4969 
4970     TRACE("(%p)\n", token);
4971 
4972     if (!info)
4973         return E_OUTOFMEMORY;
4974 
4975     if (!info->apt)
4976     {
4977         APARTMENT *apt;
4978         if (!(apt = apartment_find_multi_threaded()))
4979         {
4980             ERR("apartment not initialised\n");
4981             return CO_E_NOTINITIALIZED;
4982         }
4983         apartment_release(apt);
4984     }
4985 
4986     if (!token)
4987         return E_POINTER;
4988 
4989     if (!info->context_token)
4990     {
4991         Context *context;
4992 
4993         context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4994         if (!context)
4995             return E_OUTOFMEMORY;
4996 
4997         context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4998         context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4999         context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
5000         /* Context token does not take a reference, it's always zero until the
5001            interface is explicitly requested with CoGetObjectContext(). */
5002         context->refs = 0;
5003 
5004         info->context_token = &context->IObjContext_iface;
5005     }
5006 
5007     *token = (ULONG_PTR)info->context_token;
5008     TRACE("context_token=%p\n", info->context_token);
5009 
5010     return S_OK;
5011 }
5012 
5013 /***********************************************************************
5014  *           CoGetDefaultContext [OLE32.@]
5015  */
5016 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5017 {
5018     FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5019     return E_NOINTERFACE;
5020 }
5021 
5022 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5023 {
5024     static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5025     HKEY hkey;
5026     HRESULT hres;
5027 
5028     hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5029     if (SUCCEEDED(hres))
5030     {
5031         struct class_reg_data regdata;
5032         WCHAR dllpath[MAX_PATH+1];
5033 
5034         regdata.u.hkey = hkey;
5035         regdata.hkey = TRUE;
5036 
5037         if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
5038         {
5039             static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5040             if (!strcmpiW(dllpath, wszOle32))
5041             {
5042                 RegCloseKey(hkey);
5043                 return HandlerCF_Create(rclsid, riid, ppv);
5044             }
5045         }
5046         else
5047             WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5048         RegCloseKey(hkey);
5049     }
5050 
5051     return CLASS_E_CLASSNOTAVAILABLE;
5052 }
5053 
5054 /***********************************************************************
5055  *           CoGetApartmentType [OLE32.@]
5056  */
5057 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5058 {
5059     struct oletls *info = COM_CurrentInfo();
5060 
5061     FIXME("(%p, %p): semi-stub\n", type, qualifier);
5062 
5063     if (!type || !qualifier)
5064         return E_INVALIDARG;
5065 
5066     if (!info)
5067         return E_OUTOFMEMORY;
5068 
5069     if (!info->apt)
5070         *type = APTTYPE_CURRENT;
5071     else if (info->apt->multi_threaded)
5072         *type = APTTYPE_MTA;
5073     else if (info->apt->main)
5074         *type = APTTYPE_MAINSTA;
5075     else
5076         *type = APTTYPE_STA;
5077 
5078     *qualifier = APTTYPEQUALIFIER_NONE;
5079 
5080     return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5081 }
5082 
5083 /***********************************************************************
5084  *           CoRegisterSurrogate [OLE32.@]
5085  */
5086 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5087 {
5088     FIXME("(%p): stub\n", surrogate);
5089 
5090     return E_NOTIMPL;
5091 }
5092 
5093 /***********************************************************************
5094  *           CoRegisterSurrogateEx [OLE32.@]
5095  */
5096 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5097 {
5098     FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5099 
5100     return E_NOTIMPL;
5101 }
5102 
5103 typedef struct {
5104     IGlobalOptions IGlobalOptions_iface;
5105     LONG ref;
5106 } GlobalOptions;
5107 
5108 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5109 {
5110     return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5111 }
5112 
5113 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5114 {
5115     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5116 
5117     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5118 
5119     if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5120     {
5121         *ppv = iface;
5122     }
5123     else
5124     {
5125         *ppv = NULL;
5126         return E_NOINTERFACE;
5127     }
5128 
5129     IUnknown_AddRef((IUnknown*)*ppv);
5130     return S_OK;
5131 }
5132 
5133 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5134 {
5135     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5136     LONG ref = InterlockedIncrement(&This->ref);
5137 
5138     TRACE("(%p) ref=%d\n", This, ref);
5139 
5140     return ref;
5141 }
5142 
5143 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5144 {
5145     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5146     LONG ref = InterlockedDecrement(&This->ref);
5147 
5148     TRACE("(%p) ref=%d\n", This, ref);
5149 
5150     if (!ref)
5151         heap_free(This);
5152 
5153     return ref;
5154 }
5155 
5156 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5157 {
5158     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5159     FIXME("(%p)->(%u %lx)\n", This, property, value);
5160     return S_OK;
5161 }
5162 
5163 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5164 {
5165     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5166     FIXME("(%p)->(%u %p)\n", This, property, value);
5167     return E_NOTIMPL;
5168 }
5169 
5170 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5171     GlobalOptions_QueryInterface,
5172     GlobalOptions_AddRef,
5173     GlobalOptions_Release,
5174     GlobalOptions_Set,
5175     GlobalOptions_Query
5176 };
5177 
5178 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5179 {
5180     GlobalOptions *global_options;
5181     HRESULT hres;
5182 
5183     TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5184 
5185     if (outer)
5186         return E_INVALIDARG;
5187 
5188     global_options = heap_alloc(sizeof(*global_options));
5189     if (!global_options)
5190         return E_OUTOFMEMORY;
5191     global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5192     global_options->ref = 1;
5193 
5194     hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5195     IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5196     return hres;
5197 }
5198 
5199 /***********************************************************************
5200  *		DllMain (OLE32.@)
5201  */
5202 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5203 {
5204     TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5205 
5206     switch(fdwReason) {
5207     case DLL_PROCESS_ATTACH:
5208         hProxyDll = hinstDLL;
5209 	break;
5210 
5211     case DLL_PROCESS_DETACH:
5212         if (reserved) break;
5213         release_std_git();
5214         UnregisterClassW( wszAptWinClass, hProxyDll );
5215         RPC_UnregisterAllChannelHooks();
5216         COMPOBJ_DllList_Free();
5217         DeleteCriticalSection(&csRegisteredClassList);
5218         DeleteCriticalSection(&csApartment);
5219 	break;
5220 
5221     case DLL_THREAD_DETACH:
5222         COM_TlsDestroy();
5223         break;
5224     }
5225     return TRUE;
5226 }
5227 
5228 /***********************************************************************
5229  *		DllRegisterServer (OLE32.@)
5230  */
5231 HRESULT WINAPI DllRegisterServer(void)
5232 {
5233     return OLE32_DllRegisterServer();
5234 }
5235 
5236 /***********************************************************************
5237  *		DllUnregisterServer (OLE32.@)
5238  */
5239 HRESULT WINAPI DllUnregisterServer(void)
5240 {
5241     return OLE32_DllUnregisterServer();
5242 }
5243