xref: /reactos/dll/win32/ole32/compobj.c (revision c2c66aff)
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 void apartment_joinmta(void)
1706 {
1707     apartment_addref(MTA);
1708     COM_CurrentInfo()->apt = MTA;
1709 }
1710 
1711 static void COM_TlsDestroy(void)
1712 {
1713     struct oletls *info = NtCurrentTeb()->ReservedForOle;
1714     if (info)
1715     {
1716         if (info->apt) apartment_release(info->apt);
1717         if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1718         if (info->state) IUnknown_Release(info->state);
1719         if (info->spy) IInitializeSpy_Release(info->spy);
1720         if (info->context_token) IObjContext_Release(info->context_token);
1721         HeapFree(GetProcessHeap(), 0, info);
1722         NtCurrentTeb()->ReservedForOle = NULL;
1723     }
1724 }
1725 
1726 /******************************************************************************
1727  *           CoBuildVersion [OLE32.@]
1728  *
1729  * Gets the build version of the DLL.
1730  *
1731  * PARAMS
1732  *
1733  * RETURNS
1734  *	Current build version, hiword is majornumber, loword is minornumber
1735  */
1736 DWORD WINAPI CoBuildVersion(void)
1737 {
1738     TRACE("Returning version %d, build %d.\n", rmm, rup);
1739     return (rmm<<16)+rup;
1740 }
1741 
1742 /******************************************************************************
1743  *              CoRegisterInitializeSpy [OLE32.@]
1744  *
1745  * Add a Spy that watches CoInitializeEx calls
1746  *
1747  * PARAMS
1748  *  spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1749  *  cookie [II] cookie receiver
1750  *
1751  * RETURNS
1752  *  Success: S_OK if not already initialized, S_FALSE otherwise.
1753  *  Failure: HRESULT code.
1754  *
1755  * SEE ALSO
1756  *   CoInitializeEx
1757  */
1758 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1759 {
1760     struct oletls *info = COM_CurrentInfo();
1761     HRESULT hr;
1762 
1763     TRACE("(%p, %p)\n", spy, cookie);
1764 
1765     if (!spy || !cookie || !info)
1766     {
1767         if (!info)
1768             WARN("Could not allocate tls\n");
1769         return E_INVALIDARG;
1770     }
1771 
1772     if (info->spy)
1773     {
1774         FIXME("Already registered?\n");
1775         return E_UNEXPECTED;
1776     }
1777 
1778     hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1779     if (SUCCEEDED(hr))
1780     {
1781         cookie->QuadPart = (DWORD_PTR)spy;
1782         return S_OK;
1783     }
1784     return hr;
1785 }
1786 
1787 /******************************************************************************
1788  *              CoRevokeInitializeSpy [OLE32.@]
1789  *
1790  * Remove a spy that previously watched CoInitializeEx calls
1791  *
1792  * PARAMS
1793  *  cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1794  *
1795  * RETURNS
1796  *  Success: S_OK if a spy is removed
1797  *  Failure: E_INVALIDARG
1798  *
1799  * SEE ALSO
1800  *   CoInitializeEx
1801  */
1802 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1803 {
1804     struct oletls *info = COM_CurrentInfo();
1805     TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1806 
1807     if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1808         return E_INVALIDARG;
1809 
1810     IInitializeSpy_Release(info->spy);
1811     info->spy = NULL;
1812     return S_OK;
1813 }
1814 
1815 
1816 /******************************************************************************
1817  *		CoInitialize	[OLE32.@]
1818  *
1819  * Initializes the COM libraries by calling CoInitializeEx with
1820  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1821  *
1822  * PARAMS
1823  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1824  *
1825  * RETURNS
1826  *  Success: S_OK if not already initialized, S_FALSE otherwise.
1827  *  Failure: HRESULT code.
1828  *
1829  * SEE ALSO
1830  *   CoInitializeEx
1831  */
1832 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1833 {
1834   /*
1835    * Just delegate to the newer method.
1836    */
1837   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1838 }
1839 
1840 /******************************************************************************
1841  *		CoInitializeEx	[OLE32.@]
1842  *
1843  * Initializes the COM libraries.
1844  *
1845  * PARAMS
1846  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1847  *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
1848  *
1849  * RETURNS
1850  *  S_OK               if successful,
1851  *  S_FALSE            if this function was called already.
1852  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1853  *                     threading model.
1854  *
1855  * NOTES
1856  *
1857  * The behavior used to set the IMalloc used for memory management is
1858  * obsolete.
1859  * The dwCoInit parameter must specify one of the following apartment
1860  * threading models:
1861  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1862  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1863  * The parameter may also specify zero or more of the following flags:
1864  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1865  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1866  *
1867  * SEE ALSO
1868  *   CoUninitialize
1869  */
1870 HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1871 {
1872   struct oletls *info = COM_CurrentInfo();
1873   HRESULT hr = S_OK;
1874   APARTMENT *apt;
1875 
1876   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1877 
1878   if (lpReserved!=NULL)
1879   {
1880     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1881   }
1882 
1883   /*
1884    * Check the lock count. If this is the first time going through the initialize
1885    * process, we have to initialize the libraries.
1886    *
1887    * And crank-up that lock count.
1888    */
1889   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1890   {
1891     /*
1892      * Initialize the various COM libraries and data structures.
1893      */
1894     TRACE("() - Initializing the COM libraries\n");
1895 
1896     /* we may need to defer this until after apartment initialisation */
1897     RunningObjectTableImpl_Initialize();
1898   }
1899 
1900   if (info->spy)
1901       IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1902 
1903   if (!(apt = info->apt))
1904   {
1905     apt = apartment_get_or_create(dwCoInit);
1906     if (!apt) return E_OUTOFMEMORY;
1907   }
1908   else if (!apartment_is_model(apt, dwCoInit))
1909   {
1910     /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1911        code then we are probably using the wrong threading model to implement that API. */
1912     ERR("Attempt to change threading model of this apartment from %s to %s\n",
1913         apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1914         dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1915     return RPC_E_CHANGED_MODE;
1916   }
1917   else
1918     hr = S_FALSE;
1919 
1920   info->inits++;
1921 
1922   if (info->spy)
1923       IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1924 
1925   return hr;
1926 }
1927 
1928 /***********************************************************************
1929  *           CoUninitialize   [OLE32.@]
1930  *
1931  * This method will decrement the refcount on the current apartment, freeing
1932  * the resources associated with it if it is the last thread in the apartment.
1933  * If the last apartment is freed, the function will additionally release
1934  * any COM resources associated with the process.
1935  *
1936  * PARAMS
1937  *
1938  * RETURNS
1939  *  Nothing.
1940  *
1941  * SEE ALSO
1942  *   CoInitializeEx
1943  */
1944 void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
1945 {
1946   struct oletls * info = COM_CurrentInfo();
1947   LONG lCOMRefCnt;
1948 
1949   TRACE("()\n");
1950 
1951   /* will only happen on OOM */
1952   if (!info) return;
1953 
1954   if (info->spy)
1955       IInitializeSpy_PreUninitialize(info->spy, info->inits);
1956 
1957   /* sanity check */
1958   if (!info->inits)
1959   {
1960     ERR("Mismatched CoUninitialize\n");
1961 
1962     if (info->spy)
1963         IInitializeSpy_PostUninitialize(info->spy, info->inits);
1964     return;
1965   }
1966 
1967   if (!--info->inits)
1968   {
1969     if (info->ole_inits)
1970       WARN("uninitializing apartment while Ole is still initialized\n");
1971     apartment_release(info->apt);
1972     info->apt = NULL;
1973   }
1974 
1975   /*
1976    * Decrease the reference count.
1977    * If we are back to 0 locks on the COM library, make sure we free
1978    * all the associated data structures.
1979    */
1980   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1981   if (lCOMRefCnt==1)
1982   {
1983     TRACE("() - Releasing the COM libraries\n");
1984 
1985     revoke_registered_psclsids();
1986     RunningObjectTableImpl_UnInitialize();
1987   }
1988   else if (lCOMRefCnt<1) {
1989     ERR( "CoUninitialize() - not CoInitialized.\n" );
1990     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1991   }
1992   if (info->spy)
1993       IInitializeSpy_PostUninitialize(info->spy, info->inits);
1994 }
1995 
1996 /******************************************************************************
1997  *		CoDisconnectObject	[OLE32.@]
1998  *
1999  * Disconnects all connections to this object from remote processes. Dispatches
2000  * pending RPCs while blocking new RPCs from occurring, and then calls
2001  * IMarshal::DisconnectObject on the given object.
2002  *
2003  * Typically called when the object server is forced to shut down, for instance by
2004  * the user.
2005  *
2006  * PARAMS
2007  *  lpUnk    [I] The object whose stub should be disconnected.
2008  *  reserved [I] Reserved. Should be set to 0.
2009  *
2010  * RETURNS
2011  *  Success: S_OK.
2012  *  Failure: HRESULT code.
2013  *
2014  * SEE ALSO
2015  *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
2016  */
2017 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
2018 {
2019     struct stub_manager *manager;
2020     HRESULT hr;
2021     IMarshal *marshal;
2022     APARTMENT *apt;
2023 
2024     TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
2025 
2026     if (!lpUnk) return E_INVALIDARG;
2027 
2028     hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
2029     if (hr == S_OK)
2030     {
2031         hr = IMarshal_DisconnectObject(marshal, reserved);
2032         IMarshal_Release(marshal);
2033         return hr;
2034     }
2035 
2036     apt = COM_CurrentApt();
2037     if (!apt)
2038         return CO_E_NOTINITIALIZED;
2039 
2040     manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
2041     if (manager) {
2042         stub_manager_disconnect(manager);
2043         /* Release stub manager twice, to remove the apartment reference. */
2044         stub_manager_int_release(manager);
2045         stub_manager_int_release(manager);
2046     }
2047 
2048     /* Note: native is pretty broken here because it just silently
2049      * fails, without returning an appropriate error code if the object was
2050      * not found, making apps think that the object was disconnected, when
2051      * it actually wasn't */
2052 
2053     return S_OK;
2054 }
2055 
2056 /******************************************************************************
2057  *		CoCreateGuid [OLE32.@]
2058  *
2059  * Simply forwards to UuidCreate in RPCRT4.
2060  *
2061  * PARAMS
2062  *  pguid [O] Points to the GUID to initialize.
2063  *
2064  * RETURNS
2065  *  Success: S_OK.
2066  *  Failure: HRESULT code.
2067  *
2068  * SEE ALSO
2069  *   UuidCreate
2070  */
2071 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2072 {
2073     DWORD status;
2074 
2075     if(!pguid) return E_INVALIDARG;
2076 
2077     status = UuidCreate(pguid);
2078     if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2079     return HRESULT_FROM_WIN32( status );
2080 }
2081 
2082 static inline BOOL is_valid_hex(WCHAR c)
2083 {
2084     if (!(((c >= '0') && (c <= '9'))  ||
2085           ((c >= 'a') && (c <= 'f'))  ||
2086           ((c >= 'A') && (c <= 'F'))))
2087         return FALSE;
2088     return TRUE;
2089 }
2090 
2091 static const BYTE guid_conv_table[256] =
2092 {
2093   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
2094   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
2095   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
2096   0,   1,   2,   3,   4,   5,   6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 */
2097   0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
2098   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
2099   0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf                             /* 0x60 */
2100 };
2101 
2102 /* conversion helper for CLSIDFromString/IIDFromString */
2103 static BOOL guid_from_string(LPCWSTR s, GUID *id)
2104 {
2105   int	i;
2106 
2107   if (!s || s[0]!='{') {
2108     memset( id, 0, sizeof (CLSID) );
2109     if(!s) return TRUE;
2110     return FALSE;
2111   }
2112 
2113   TRACE("%s -> %p\n", debugstr_w(s), id);
2114 
2115   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
2116 
2117   id->Data1 = 0;
2118   for (i = 1; i < 9; i++) {
2119     if (!is_valid_hex(s[i])) return FALSE;
2120     id->Data1 = (id->Data1 << 4) | guid_conv_table[s[i]];
2121   }
2122   if (s[9]!='-') return FALSE;
2123 
2124   id->Data2 = 0;
2125   for (i = 10; i < 14; i++) {
2126     if (!is_valid_hex(s[i])) return FALSE;
2127     id->Data2 = (id->Data2 << 4) | guid_conv_table[s[i]];
2128   }
2129   if (s[14]!='-') return FALSE;
2130 
2131   id->Data3 = 0;
2132   for (i = 15; i < 19; i++) {
2133     if (!is_valid_hex(s[i])) return FALSE;
2134     id->Data3 = (id->Data3 << 4) | guid_conv_table[s[i]];
2135   }
2136   if (s[19]!='-') return FALSE;
2137 
2138   for (i = 20; i < 37; i+=2) {
2139     if (i == 24) {
2140       if (s[i]!='-') return FALSE;
2141       i++;
2142     }
2143     if (!is_valid_hex(s[i]) || !is_valid_hex(s[i+1])) return FALSE;
2144     id->Data4[(i-20)/2] = guid_conv_table[s[i]] << 4 | guid_conv_table[s[i+1]];
2145   }
2146 
2147   if (s[37] == '}' && s[38] == '\0')
2148     return TRUE;
2149 
2150   return FALSE;
2151 }
2152 
2153 /*****************************************************************************/
2154 
2155 static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid)
2156 {
2157     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
2158     WCHAR buf2[CHARS_IN_GUID];
2159     LONG buf2len = sizeof(buf2);
2160     HKEY xhkey;
2161     WCHAR *buf;
2162 
2163     memset(clsid, 0, sizeof(*clsid));
2164     buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
2165     if (!buf) return E_OUTOFMEMORY;
2166     strcpyW( buf, progid );
2167     strcatW( buf, clsidW );
2168     if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey))
2169     {
2170         HeapFree(GetProcessHeap(),0,buf);
2171         WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
2172         return CO_E_CLASSSTRING;
2173     }
2174     HeapFree(GetProcessHeap(),0,buf);
2175 
2176     if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
2177     {
2178         RegCloseKey(xhkey);
2179         WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
2180         return CO_E_CLASSSTRING;
2181     }
2182     RegCloseKey(xhkey);
2183     return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING;
2184 }
2185 
2186 /******************************************************************************
2187  *		CLSIDFromString	[OLE32.@]
2188  *
2189  * Converts a unique identifier from its string representation into
2190  * the GUID struct.
2191  *
2192  * PARAMS
2193  *  idstr [I] The string representation of the GUID.
2194  *  id    [O] GUID converted from the string.
2195  *
2196  * RETURNS
2197  *   S_OK on success
2198  *   CO_E_CLASSSTRING if idstr is not a valid CLSID
2199  *
2200  * SEE ALSO
2201  *  StringFromCLSID
2202  */
2203 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
2204 {
2205     HRESULT ret = CO_E_CLASSSTRING;
2206     CLSID tmp_id;
2207 
2208     if (!id)
2209         return E_INVALIDARG;
2210 
2211     if (guid_from_string(idstr, id))
2212         return S_OK;
2213 
2214     /* It appears a ProgID is also valid */
2215     ret = clsid_from_string_reg(idstr, &tmp_id);
2216     if(SUCCEEDED(ret))
2217         *id = tmp_id;
2218 
2219     return ret;
2220 }
2221 
2222 /******************************************************************************
2223  *		IIDFromString   [OLE32.@]
2224  *
2225  * Converts an interface identifier from its string representation to
2226  * the IID struct.
2227  *
2228  * PARAMS
2229  *  idstr [I] The string representation of the GUID.
2230  *  id    [O] IID converted from the string.
2231  *
2232  * RETURNS
2233  *   S_OK on success
2234  *   CO_E_IIDSTRING if idstr is not a valid IID
2235  *
2236  * SEE ALSO
2237  *  StringFromIID
2238  */
2239 HRESULT WINAPI IIDFromString(LPCOLESTR s, IID *iid)
2240 {
2241   TRACE("%s -> %p\n", debugstr_w(s), iid);
2242 
2243   if (!s)
2244   {
2245       memset(iid, 0, sizeof(*iid));
2246       return S_OK;
2247   }
2248 
2249   /* length mismatch is a special case */
2250   if (strlenW(s) + 1 != CHARS_IN_GUID)
2251       return E_INVALIDARG;
2252 
2253   if (s[0] != '{')
2254       return CO_E_IIDSTRING;
2255 
2256   return guid_from_string(s, iid) ? S_OK : CO_E_IIDSTRING;
2257 }
2258 
2259 /******************************************************************************
2260  *		StringFromCLSID	[OLE32.@]
2261  *		StringFromIID   [OLE32.@]
2262  *
2263  * Converts a GUID into the respective string representation.
2264  * The target string is allocated using the OLE IMalloc.
2265  *
2266  * PARAMS
2267  *  id    [I] the GUID to be converted.
2268  *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
2269  *
2270  * RETURNS
2271  *   S_OK
2272  *   E_FAIL
2273  *
2274  * SEE ALSO
2275  *  StringFromGUID2, CLSIDFromString
2276  */
2277 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
2278 {
2279     if (!(*idstr = CoTaskMemAlloc(CHARS_IN_GUID * sizeof(WCHAR)))) return E_OUTOFMEMORY;
2280     StringFromGUID2( id, *idstr, CHARS_IN_GUID );
2281     return S_OK;
2282 }
2283 
2284 /******************************************************************************
2285  *		StringFromGUID2	[OLE32.@]
2286  *
2287  * Modified version of StringFromCLSID that allows you to specify max
2288  * buffer size.
2289  *
2290  * PARAMS
2291  *  id   [I] GUID to convert to string.
2292  *  str  [O] Buffer where the result will be stored.
2293  *  cmax [I] Size of the buffer in characters.
2294  *
2295  * RETURNS
2296  *	Success: The length of the resulting string in characters.
2297  *  Failure: 0.
2298  */
2299 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
2300 {
2301     static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
2302                                      '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
2303                                      '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2304                                      '%','0','2','X','%','0','2','X','}',0 };
2305     if (!id || cmax < CHARS_IN_GUID) return 0;
2306     sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
2307               id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
2308               id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
2309     return CHARS_IN_GUID;
2310 }
2311 
2312 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
2313 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
2314 {
2315     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
2316     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
2317     LONG res;
2318     HKEY key;
2319 
2320     strcpyW(path, wszCLSIDSlash);
2321     StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
2322     res = open_classes_key(HKEY_CLASSES_ROOT, path, keyname ? KEY_READ : access, &key);
2323     if (res == ERROR_FILE_NOT_FOUND)
2324         return REGDB_E_CLASSNOTREG;
2325     else if (res != ERROR_SUCCESS)
2326         return REGDB_E_READREGDB;
2327 
2328     if (!keyname)
2329     {
2330         *subkey = key;
2331         return S_OK;
2332     }
2333 
2334     res = open_classes_key(key, keyname, access, subkey);
2335     RegCloseKey(key);
2336     if (res == ERROR_FILE_NOT_FOUND)
2337         return REGDB_E_KEYMISSING;
2338     else if (res != ERROR_SUCCESS)
2339         return REGDB_E_READREGDB;
2340 
2341     return S_OK;
2342 }
2343 
2344 /* open HKCR\\AppId\\{string form of appid clsid} key */
2345 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
2346 {
2347     static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
2348     static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
2349     DWORD res;
2350     WCHAR buf[CHARS_IN_GUID];
2351     WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
2352     DWORD size;
2353     HKEY hkey;
2354     DWORD type;
2355     HRESULT hr;
2356 
2357     /* read the AppID value under the class's key */
2358     hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
2359     if (FAILED(hr))
2360         return hr;
2361 
2362     size = sizeof(buf);
2363     res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
2364     RegCloseKey(hkey);
2365     if (res == ERROR_FILE_NOT_FOUND)
2366         return REGDB_E_KEYMISSING;
2367     else if (res != ERROR_SUCCESS || type!=REG_SZ)
2368         return REGDB_E_READREGDB;
2369 
2370     strcpyW(keyname, szAppIdKey);
2371     strcatW(keyname, buf);
2372     res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
2373     if (res == ERROR_FILE_NOT_FOUND)
2374         return REGDB_E_KEYMISSING;
2375     else if (res != ERROR_SUCCESS)
2376         return REGDB_E_READREGDB;
2377 
2378     return S_OK;
2379 }
2380 
2381 /******************************************************************************
2382  *               ProgIDFromCLSID [OLE32.@]
2383  *
2384  * Converts a class id into the respective program ID.
2385  *
2386  * PARAMS
2387  *  clsid        [I] Class ID, as found in registry.
2388  *  ppszProgID [O] Associated ProgID.
2389  *
2390  * RETURNS
2391  *   S_OK
2392  *   E_OUTOFMEMORY
2393  *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
2394  */
2395 HRESULT WINAPI DECLSPEC_HOTPATCH ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
2396 {
2397     static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
2398     ACTCTX_SECTION_KEYED_DATA data;
2399     HKEY     hkey;
2400     HRESULT  ret;
2401     LONG progidlen = 0;
2402 
2403     if (!ppszProgID)
2404         return E_INVALIDARG;
2405 
2406     *ppszProgID = NULL;
2407 
2408     data.cbSize = sizeof(data);
2409     if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
2410                               clsid, &data))
2411     {
2412         struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
2413         if (comclass->progid_len)
2414         {
2415             WCHAR *ptrW;
2416 
2417             *ppszProgID = CoTaskMemAlloc(comclass->progid_len + sizeof(WCHAR));
2418             if (!*ppszProgID) return E_OUTOFMEMORY;
2419 
2420             ptrW = (WCHAR*)((BYTE*)comclass + comclass->progid_offset);
2421             memcpy(*ppszProgID, ptrW, comclass->progid_len + sizeof(WCHAR));
2422             return S_OK;
2423         }
2424         else
2425             return REGDB_E_CLASSNOTREG;
2426     }
2427 
2428     ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
2429     if (FAILED(ret))
2430         return ret;
2431 
2432     if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
2433       ret = REGDB_E_CLASSNOTREG;
2434 
2435     if (ret == S_OK)
2436     {
2437       *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
2438       if (*ppszProgID)
2439       {
2440         if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen)) {
2441           ret = REGDB_E_CLASSNOTREG;
2442           CoTaskMemFree(*ppszProgID);
2443           *ppszProgID = NULL;
2444         }
2445       }
2446       else
2447         ret = E_OUTOFMEMORY;
2448     }
2449 
2450     RegCloseKey(hkey);
2451     return ret;
2452 }
2453 
2454 /******************************************************************************
2455  *		CLSIDFromProgID	[OLE32.@]
2456  *
2457  * Converts a program id into the respective GUID.
2458  *
2459  * PARAMS
2460  *  progid [I] Unicode program ID, as found in registry.
2461  *  clsid  [O] Associated CLSID.
2462  *
2463  * RETURNS
2464  *	Success: S_OK
2465  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
2466  */
2467 HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
2468 {
2469     ACTCTX_SECTION_KEYED_DATA data;
2470 
2471     if (!progid || !clsid)
2472         return E_INVALIDARG;
2473 
2474     data.cbSize = sizeof(data);
2475     if (FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION,
2476                                  progid, &data))
2477     {
2478         struct progidredirect_data *progiddata = (struct progidredirect_data*)data.lpData;
2479         CLSID *alias = (CLSID*)((BYTE*)data.lpSectionBase + progiddata->clsid_offset);
2480         *clsid = *alias;
2481         return S_OK;
2482     }
2483 
2484     return clsid_from_string_reg(progid, clsid);
2485 }
2486 
2487 /******************************************************************************
2488  *              CLSIDFromProgIDEx [OLE32.@]
2489  */
2490 HRESULT WINAPI CLSIDFromProgIDEx(LPCOLESTR progid, LPCLSID clsid)
2491 {
2492     FIXME("%s,%p: semi-stub\n", debugstr_w(progid), clsid);
2493 
2494     return CLSIDFromProgID(progid, clsid);
2495 }
2496 
2497 static HRESULT get_ps_clsid_from_registry(const WCHAR* path, REGSAM access, CLSID *pclsid)
2498 {
2499     HKEY hkey;
2500     WCHAR value[CHARS_IN_GUID];
2501     DWORD len;
2502 
2503     access |= KEY_READ;
2504 
2505     if (open_classes_key(HKEY_CLASSES_ROOT, path, access, &hkey))
2506         return REGDB_E_IIDNOTREG;
2507 
2508     len = sizeof(value);
2509     if (ERROR_SUCCESS != RegQueryValueExW(hkey, NULL, NULL, NULL, (BYTE *)value, &len))
2510         return REGDB_E_IIDNOTREG;
2511     RegCloseKey(hkey);
2512 
2513     if (CLSIDFromString(value, pclsid) != NOERROR)
2514         return REGDB_E_IIDNOTREG;
2515 
2516     return S_OK;
2517 }
2518 
2519 /*****************************************************************************
2520  *             CoGetPSClsid [OLE32.@]
2521  *
2522  * Retrieves the CLSID of the proxy/stub factory that implements
2523  * IPSFactoryBuffer for the specified interface.
2524  *
2525  * PARAMS
2526  *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
2527  *  pclsid [O] Where to store returned proxy/stub CLSID.
2528  *
2529  * RETURNS
2530  *   S_OK
2531  *   E_OUTOFMEMORY
2532  *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
2533  *
2534  * NOTES
2535  *
2536  * The standard marshaller activates the object with the CLSID
2537  * returned and uses the CreateProxy and CreateStub methods on its
2538  * IPSFactoryBuffer interface to construct the proxies and stubs for a
2539  * given object.
2540  *
2541  * CoGetPSClsid determines this CLSID by searching the
2542  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
2543  * in the registry and any interface id registered by
2544  * CoRegisterPSClsid within the current process.
2545  *
2546  * BUGS
2547  *
2548  * Native returns S_OK for interfaces with a key in HKCR\Interface, but
2549  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
2550  * considered a bug in native unless an application depends on this (unlikely).
2551  *
2552  * SEE ALSO
2553  *  CoRegisterPSClsid.
2554  */
2555 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
2556 {
2557     static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
2558     static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
2559     WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
2560     APARTMENT *apt = COM_CurrentApt();
2561     struct registered_psclsid *registered_psclsid;
2562     ACTCTX_SECTION_KEYED_DATA data;
2563     HRESULT hr;
2564     REGSAM opposite = (sizeof(void*) > sizeof(int)) ? KEY_WOW64_32KEY : KEY_WOW64_64KEY;
2565     BOOL is_wow64;
2566 
2567     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
2568 
2569     if (!apt)
2570     {
2571         ERR("apartment not initialised\n");
2572         return CO_E_NOTINITIALIZED;
2573     }
2574 
2575     if (!pclsid)
2576         return E_INVALIDARG;
2577 
2578     EnterCriticalSection(&cs_registered_psclsid_list);
2579 
2580     LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2581         if (IsEqualIID(&registered_psclsid->iid, riid))
2582         {
2583             *pclsid = registered_psclsid->clsid;
2584             LeaveCriticalSection(&cs_registered_psclsid_list);
2585             return S_OK;
2586         }
2587 
2588     LeaveCriticalSection(&cs_registered_psclsid_list);
2589 
2590     data.cbSize = sizeof(data);
2591     if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
2592                               riid, &data))
2593     {
2594         struct ifacepsredirect_data *ifaceps = (struct ifacepsredirect_data*)data.lpData;
2595         *pclsid = ifaceps->iid;
2596         return S_OK;
2597     }
2598 
2599     /* Interface\\{string form of riid}\\ProxyStubClsid32 */
2600     strcpyW(path, wszInterface);
2601     StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
2602     strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
2603 
2604     hr = get_ps_clsid_from_registry(path, 0, pclsid);
2605     if (FAILED(hr) && (opposite == KEY_WOW64_32KEY ||
2606                        (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)))
2607         hr = get_ps_clsid_from_registry(path, opposite, pclsid);
2608 
2609     if (hr == S_OK)
2610         TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
2611     else
2612         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
2613 
2614     return hr;
2615 }
2616 
2617 /*****************************************************************************
2618  *             CoRegisterPSClsid [OLE32.@]
2619  *
2620  * Register a proxy/stub CLSID for the given interface in the current process
2621  * only.
2622  *
2623  * PARAMS
2624  *  riid   [I] Interface whose proxy/stub CLSID is to be registered.
2625  *  rclsid [I] CLSID of the proxy/stub.
2626  *
2627  * RETURNS
2628  *   Success: S_OK
2629  *   Failure: E_OUTOFMEMORY
2630  *
2631  * NOTES
2632  *
2633  * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
2634  * will be returned from other apartments in the same process.
2635  *
2636  * This function does not add anything to the registry and the effects are
2637  * limited to the lifetime of the current process.
2638  *
2639  * SEE ALSO
2640  *  CoGetPSClsid.
2641  */
2642 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
2643 {
2644     APARTMENT *apt = COM_CurrentApt();
2645     struct registered_psclsid *registered_psclsid;
2646 
2647     TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
2648 
2649     if (!apt)
2650     {
2651         ERR("apartment not initialised\n");
2652         return CO_E_NOTINITIALIZED;
2653     }
2654 
2655     EnterCriticalSection(&cs_registered_psclsid_list);
2656 
2657     LIST_FOR_EACH_ENTRY(registered_psclsid, &registered_psclsid_list, struct registered_psclsid, entry)
2658         if (IsEqualIID(&registered_psclsid->iid, riid))
2659         {
2660             registered_psclsid->clsid = *rclsid;
2661             LeaveCriticalSection(&cs_registered_psclsid_list);
2662             return S_OK;
2663         }
2664 
2665     registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
2666     if (!registered_psclsid)
2667     {
2668         LeaveCriticalSection(&cs_registered_psclsid_list);
2669         return E_OUTOFMEMORY;
2670     }
2671 
2672     registered_psclsid->iid = *riid;
2673     registered_psclsid->clsid = *rclsid;
2674     list_add_head(&registered_psclsid_list, &registered_psclsid->entry);
2675 
2676     LeaveCriticalSection(&cs_registered_psclsid_list);
2677 
2678     return S_OK;
2679 }
2680 
2681 
2682 /***
2683  * COM_GetRegisteredClassObject
2684  *
2685  * This internal method is used to scan the registered class list to
2686  * find a class object.
2687  *
2688  * Params:
2689  *   rclsid        Class ID of the class to find.
2690  *   dwClsContext  Class context to match.
2691  *   ppv           [out] returns a pointer to the class object. Complying
2692  *                 to normal COM usage, this method will increase the
2693  *                 reference count on this object.
2694  */
2695 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
2696                                             DWORD dwClsContext, LPUNKNOWN* ppUnk)
2697 {
2698   HRESULT hr = S_FALSE;
2699   RegisteredClass *curClass;
2700 
2701   EnterCriticalSection( &csRegisteredClassList );
2702 
2703   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2704   {
2705     /*
2706      * Check if we have a match on the class ID and context.
2707      */
2708     if ((apt->oxid == curClass->apartment_id) &&
2709         (dwClsContext & curClass->runContext) &&
2710         IsEqualGUID(&(curClass->classIdentifier), rclsid))
2711     {
2712       /*
2713        * We have a match, return the pointer to the class object.
2714        */
2715       *ppUnk = curClass->classObject;
2716 
2717       IUnknown_AddRef(curClass->classObject);
2718 
2719       hr = S_OK;
2720       break;
2721     }
2722   }
2723 
2724   LeaveCriticalSection( &csRegisteredClassList );
2725 
2726   return hr;
2727 }
2728 
2729 /******************************************************************************
2730  *		CoRegisterClassObject	[OLE32.@]
2731  *
2732  * Registers the class object for a given class ID. Servers housed in EXE
2733  * files use this method instead of exporting DllGetClassObject to allow
2734  * other code to connect to their objects.
2735  *
2736  * PARAMS
2737  *  rclsid       [I] CLSID of the object to register.
2738  *  pUnk         [I] IUnknown of the object.
2739  *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2740  *  flags        [I] REGCLS flags indicating how connections are made.
2741  *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2742  *
2743  * RETURNS
2744  *   S_OK on success,
2745  *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
2746  *   CO_E_OBJISREG if the object is already registered. We should not return this.
2747  *
2748  * SEE ALSO
2749  *   CoRevokeClassObject, CoGetClassObject
2750  *
2751  * NOTES
2752  *  In-process objects are only registered for the current apartment.
2753  *  CoGetClassObject() and CoCreateInstance() will not return objects registered
2754  *  in other apartments.
2755  *
2756  * BUGS
2757  *  MSDN claims that multiple interface registrations are legal, but we
2758  *  can't do that with our current implementation.
2759  */
2760 HRESULT WINAPI CoRegisterClassObject(
2761     REFCLSID rclsid,
2762     LPUNKNOWN pUnk,
2763     DWORD dwClsContext,
2764     DWORD flags,
2765     LPDWORD lpdwRegister)
2766 {
2767   static LONG next_cookie;
2768   RegisteredClass* newClass;
2769   LPUNKNOWN        foundObject;
2770   HRESULT          hr;
2771   APARTMENT *apt;
2772 
2773   TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2774 	debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2775 
2776   if ( (lpdwRegister==0) || (pUnk==0) )
2777     return E_INVALIDARG;
2778 
2779   apt = COM_CurrentApt();
2780   if (!apt)
2781   {
2782       ERR("COM was not initialized\n");
2783       return CO_E_NOTINITIALIZED;
2784   }
2785 
2786   *lpdwRegister = 0;
2787 
2788   /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2789    * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2790   if (flags & REGCLS_MULTIPLEUSE)
2791     dwClsContext |= CLSCTX_INPROC_SERVER;
2792 
2793   /*
2794    * First, check if the class is already registered.
2795    * If it is, this should cause an error.
2796    */
2797   hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2798   if (hr == S_OK) {
2799     if (flags & REGCLS_MULTIPLEUSE) {
2800       if (dwClsContext & CLSCTX_LOCAL_SERVER)
2801         hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2802       IUnknown_Release(foundObject);
2803       return hr;
2804     }
2805     IUnknown_Release(foundObject);
2806     ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2807     return CO_E_OBJISREG;
2808   }
2809 
2810   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2811   if ( newClass == NULL )
2812     return E_OUTOFMEMORY;
2813 
2814   newClass->classIdentifier = *rclsid;
2815   newClass->apartment_id    = apt->oxid;
2816   newClass->runContext      = dwClsContext;
2817   newClass->connectFlags    = flags;
2818   newClass->RpcRegistration = NULL;
2819 
2820   if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2821       newClass->dwCookie = InterlockedIncrement( &next_cookie );
2822 
2823   /*
2824    * Since we're making a copy of the object pointer, we have to increase its
2825    * reference count.
2826    */
2827   newClass->classObject     = pUnk;
2828   IUnknown_AddRef(newClass->classObject);
2829 
2830   EnterCriticalSection( &csRegisteredClassList );
2831   list_add_tail(&RegisteredClassList, &newClass->entry);
2832   LeaveCriticalSection( &csRegisteredClassList );
2833 
2834   *lpdwRegister = newClass->dwCookie;
2835 
2836   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2837       IStream *marshal_stream;
2838 
2839       hr = get_local_server_stream(apt, &marshal_stream);
2840       if(FAILED(hr))
2841           return hr;
2842 
2843       hr = RPC_StartLocalServer(&newClass->classIdentifier,
2844                                 marshal_stream,
2845                                 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2846                                 &newClass->RpcRegistration);
2847       IStream_Release(marshal_stream);
2848   }
2849   return S_OK;
2850 }
2851 
2852 static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data)
2853 {
2854     if (data->hkey)
2855     {
2856         static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2857         static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2858         static const WCHAR wszFree[] = {'F','r','e','e',0};
2859         static const WCHAR wszBoth[] = {'B','o','t','h',0};
2860         WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2861         DWORD dwLength = sizeof(threading_model);
2862         DWORD keytype;
2863         DWORD ret;
2864 
2865         ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength);
2866         if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2867             threading_model[0] = '\0';
2868 
2869         if (!strcmpiW(threading_model, wszApartment)) return ThreadingModel_Apartment;
2870         if (!strcmpiW(threading_model, wszFree)) return ThreadingModel_Free;
2871         if (!strcmpiW(threading_model, wszBoth)) return ThreadingModel_Both;
2872 
2873         /* there's not specific handling for this case */
2874         if (threading_model[0]) return ThreadingModel_Neutral;
2875         return ThreadingModel_No;
2876     }
2877     else
2878         return data->u.actctx.data->model;
2879 }
2880 
2881 static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata,
2882                                        REFCLSID rclsid, REFIID riid,
2883                                        BOOL hostifnecessary, void **ppv)
2884 {
2885     WCHAR dllpath[MAX_PATH+1];
2886     BOOL apartment_threaded;
2887 
2888     if (hostifnecessary)
2889     {
2890         enum comclass_threadingmodel model = get_threading_model(regdata);
2891 
2892         if (model == ThreadingModel_Apartment)
2893         {
2894             apartment_threaded = TRUE;
2895             if (apt->multi_threaded)
2896                 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv);
2897         }
2898         else if (model == ThreadingModel_Free)
2899         {
2900             apartment_threaded = FALSE;
2901             if (!apt->multi_threaded)
2902                 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv);
2903         }
2904         /* everything except "Apartment", "Free" and "Both" */
2905         else if (model != ThreadingModel_Both)
2906         {
2907             apartment_threaded = TRUE;
2908             /* everything else is main-threaded */
2909             if (model != ThreadingModel_No)
2910                 FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid));
2911 
2912             if (apt->multi_threaded || !apt->main)
2913                 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv);
2914         }
2915         else
2916             apartment_threaded = FALSE;
2917     }
2918     else
2919         apartment_threaded = !apt->multi_threaded;
2920 
2921     if (COM_RegReadPath(regdata, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2922     {
2923         /* failure: CLSID is not found in registry */
2924         WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2925         return REGDB_E_CLASSNOTREG;
2926     }
2927 
2928     return apartment_getclassobject(apt, dllpath, apartment_threaded,
2929                                     rclsid, riid, ppv);
2930 }
2931 
2932 /***********************************************************************
2933  *           CoGetClassObject [OLE32.@]
2934  *
2935  * Creates an object of the specified class.
2936  *
2937  * PARAMS
2938  *  rclsid       [I] Class ID to create an instance of.
2939  *  dwClsContext [I] Flags to restrict the location of the created instance.
2940  *  pServerInfo  [I] Optional. Details for connecting to a remote server.
2941  *  iid          [I] The ID of the interface of the instance to return.
2942  *  ppv          [O] On returns, contains a pointer to the specified interface of the object.
2943  *
2944  * RETURNS
2945  *  Success: S_OK
2946  *  Failure: HRESULT code.
2947  *
2948  * NOTES
2949  *  The dwClsContext parameter can be one or more of the following:
2950  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2951  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2952  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2953  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2954  *
2955  * SEE ALSO
2956  *  CoCreateInstance()
2957  */
2958 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
2959     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2960     REFIID iid, LPVOID *ppv)
2961 {
2962     struct class_reg_data clsreg;
2963     IUnknown *regClassObject;
2964     HRESULT	hres = E_UNEXPECTED;
2965     APARTMENT  *apt;
2966     BOOL release_apt = FALSE;
2967 
2968     TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2969 
2970     if (!ppv)
2971         return E_INVALIDARG;
2972 
2973     *ppv = NULL;
2974 
2975     if (!(apt = COM_CurrentApt()))
2976     {
2977         if (!(apt = apartment_find_multi_threaded()))
2978         {
2979             ERR("apartment not initialised\n");
2980             return CO_E_NOTINITIALIZED;
2981         }
2982         release_apt = TRUE;
2983     }
2984 
2985     if (pServerInfo) {
2986 	FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
2987               debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2988     }
2989 
2990     if (CLSCTX_INPROC_SERVER & dwClsContext)
2991     {
2992         if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2993         {
2994             if (release_apt) apartment_release(apt);
2995             return FTMarshalCF_Create(iid, ppv);
2996         }
2997         if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions))
2998             return IClassFactory_QueryInterface(&GlobalOptionsCF, iid, ppv);
2999     }
3000 
3001     if (CLSCTX_INPROC & dwClsContext)
3002     {
3003         ACTCTX_SECTION_KEYED_DATA data;
3004 
3005         data.cbSize = sizeof(data);
3006         /* search activation context first */
3007         if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
3008                                   ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
3009                                   rclsid, &data))
3010         {
3011             struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
3012 
3013             clsreg.u.actctx.hactctx = data.hActCtx;
3014             clsreg.u.actctx.data = data.lpData;
3015             clsreg.u.actctx.section = data.lpSectionBase;
3016             clsreg.hkey = FALSE;
3017 
3018             hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3019             ReleaseActCtx(data.hActCtx);
3020             if (release_apt) apartment_release(apt);
3021             return hres;
3022         }
3023     }
3024 
3025     /*
3026      * First, try and see if we can't match the class ID with one of the
3027      * registered classes.
3028      */
3029     if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
3030                                              &regClassObject))
3031     {
3032       /* Get the required interface from the retrieved pointer. */
3033       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
3034 
3035       /*
3036        * Since QI got another reference on the pointer, we want to release the
3037        * one we already have. If QI was unsuccessful, this will release the object. This
3038        * is good since we are not returning it in the "out" parameter.
3039        */
3040       IUnknown_Release(regClassObject);
3041       if (release_apt) apartment_release(apt);
3042       return hres;
3043     }
3044 
3045     /* First try in-process server */
3046     if (CLSCTX_INPROC_SERVER & dwClsContext)
3047     {
3048         static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
3049         HKEY hkey;
3050 
3051         hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
3052         if (FAILED(hres))
3053         {
3054             if (hres == REGDB_E_CLASSNOTREG)
3055                 ERR("class %s not registered\n", debugstr_guid(rclsid));
3056             else if (hres == REGDB_E_KEYMISSING)
3057             {
3058                 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
3059                 hres = REGDB_E_CLASSNOTREG;
3060             }
3061         }
3062 
3063         if (SUCCEEDED(hres))
3064         {
3065             clsreg.u.hkey = hkey;
3066             clsreg.hkey = TRUE;
3067 
3068             hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3069             RegCloseKey(hkey);
3070         }
3071 
3072         /* return if we got a class, otherwise fall through to one of the
3073          * other types */
3074         if (SUCCEEDED(hres))
3075         {
3076             if (release_apt) apartment_release(apt);
3077             return hres;
3078         }
3079     }
3080 
3081     /* Next try in-process handler */
3082     if (CLSCTX_INPROC_HANDLER & dwClsContext)
3083     {
3084         static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
3085         HKEY hkey;
3086 
3087         hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
3088         if (FAILED(hres))
3089         {
3090             if (hres == REGDB_E_CLASSNOTREG)
3091                 ERR("class %s not registered\n", debugstr_guid(rclsid));
3092             else if (hres == REGDB_E_KEYMISSING)
3093             {
3094                 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
3095                 hres = REGDB_E_CLASSNOTREG;
3096             }
3097         }
3098 
3099         if (SUCCEEDED(hres))
3100         {
3101             clsreg.u.hkey = hkey;
3102             clsreg.hkey = TRUE;
3103 
3104             hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
3105             RegCloseKey(hkey);
3106         }
3107 
3108         /* return if we got a class, otherwise fall through to one of the
3109          * other types */
3110         if (SUCCEEDED(hres))
3111         {
3112             if (release_apt) apartment_release(apt);
3113             return hres;
3114         }
3115     }
3116     if (release_apt) apartment_release(apt);
3117 
3118     /* Next try out of process */
3119     if (CLSCTX_LOCAL_SERVER & dwClsContext)
3120     {
3121         hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
3122         if (SUCCEEDED(hres))
3123             return hres;
3124     }
3125 
3126     /* Finally try remote: this requires networked DCOM (a lot of work) */
3127     if (CLSCTX_REMOTE_SERVER & dwClsContext)
3128     {
3129         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
3130         hres = REGDB_E_CLASSNOTREG;
3131     }
3132 
3133     if (FAILED(hres))
3134         ERR("no class object %s could be created for context 0x%x\n",
3135             debugstr_guid(rclsid), dwClsContext);
3136     return hres;
3137 }
3138 
3139 /***********************************************************************
3140  *        CoResumeClassObjects (OLE32.@)
3141  *
3142  * Resumes all class objects registered with REGCLS_SUSPENDED.
3143  *
3144  * RETURNS
3145  *  Success: S_OK.
3146  *  Failure: HRESULT code.
3147  */
3148 HRESULT WINAPI CoResumeClassObjects(void)
3149 {
3150        FIXME("stub\n");
3151 	return S_OK;
3152 }
3153 
3154 /***********************************************************************
3155  *           CoCreateInstance [OLE32.@]
3156  *
3157  * Creates an instance of the specified class.
3158  *
3159  * PARAMS
3160  *  rclsid       [I] Class ID to create an instance of.
3161  *  pUnkOuter    [I] Optional outer unknown to allow aggregation with another object.
3162  *  dwClsContext [I] Flags to restrict the location of the created instance.
3163  *  iid          [I] The ID of the interface of the instance to return.
3164  *  ppv          [O] On returns, contains a pointer to the specified interface of the instance.
3165  *
3166  * RETURNS
3167  *  Success: S_OK
3168  *  Failure: HRESULT code.
3169  *
3170  * NOTES
3171  *  The dwClsContext parameter can be one or more of the following:
3172  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
3173  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
3174  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
3175  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
3176  *
3177  * Aggregation is the concept of deferring the IUnknown of an object to another
3178  * object. This allows a separate object to behave as though it was part of
3179  * the object and to allow this the pUnkOuter parameter can be set. Note that
3180  * not all objects support having an outer of unknown.
3181  *
3182  * SEE ALSO
3183  *  CoGetClassObject()
3184  */
3185 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(
3186     REFCLSID rclsid,
3187     LPUNKNOWN pUnkOuter,
3188     DWORD dwClsContext,
3189     REFIID iid,
3190     LPVOID *ppv)
3191 {
3192     MULTI_QI multi_qi = { iid };
3193     HRESULT hres;
3194 
3195     TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
3196           pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
3197 
3198     if (ppv==0)
3199         return E_POINTER;
3200 
3201     hres = CoCreateInstanceEx(rclsid, pUnkOuter, dwClsContext, NULL, 1, &multi_qi);
3202     *ppv = multi_qi.pItf;
3203     return hres;
3204 }
3205 
3206 static void init_multi_qi(DWORD count, MULTI_QI *mqi, HRESULT hr)
3207 {
3208   ULONG i;
3209 
3210   for (i = 0; i < count; i++)
3211   {
3212       mqi[i].pItf = NULL;
3213       mqi[i].hr = hr;
3214   }
3215 }
3216 
3217 static HRESULT return_multi_qi(IUnknown *unk, DWORD count, MULTI_QI *mqi, BOOL include_unk)
3218 {
3219   ULONG index = 0, fetched = 0;
3220 
3221   if (include_unk)
3222   {
3223     mqi[0].hr = S_OK;
3224     mqi[0].pItf = unk;
3225     index = fetched = 1;
3226   }
3227 
3228   for (; index < count; index++)
3229   {
3230     mqi[index].hr = IUnknown_QueryInterface(unk, mqi[index].pIID, (void**)&mqi[index].pItf);
3231     if (mqi[index].hr == S_OK)
3232       fetched++;
3233   }
3234 
3235   if (!include_unk)
3236       IUnknown_Release(unk);
3237 
3238   if (fetched == 0)
3239     return E_NOINTERFACE;
3240 
3241   return fetched == count ? S_OK : CO_S_NOTALLINTERFACES;
3242 }
3243 
3244 /***********************************************************************
3245  *           CoCreateInstanceEx [OLE32.@]
3246  */
3247 HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(
3248   REFCLSID      rclsid,
3249   LPUNKNOWN     pUnkOuter,
3250   DWORD         dwClsContext,
3251   COSERVERINFO* pServerInfo,
3252   ULONG         cmq,
3253   MULTI_QI*     pResults)
3254 {
3255     IUnknown *unk = NULL;
3256     IClassFactory *cf;
3257     APARTMENT *apt;
3258     CLSID clsid;
3259     HRESULT hres;
3260 
3261     TRACE("(%s %p %x %p %u %p)\n", debugstr_guid(rclsid), pUnkOuter, dwClsContext, pServerInfo, cmq, pResults);
3262 
3263     if (!cmq || !pResults)
3264         return E_INVALIDARG;
3265 
3266     if (pServerInfo)
3267         FIXME("() non-NULL pServerInfo not supported!\n");
3268 
3269     init_multi_qi(cmq, pResults, E_NOINTERFACE);
3270 
3271     hres = CoGetTreatAsClass(rclsid, &clsid);
3272     if(FAILED(hres))
3273         clsid = *rclsid;
3274 
3275     if (!(apt = COM_CurrentApt()))
3276     {
3277         if (!(apt = apartment_find_multi_threaded()))
3278         {
3279             ERR("apartment not initialised\n");
3280             return CO_E_NOTINITIALIZED;
3281         }
3282         apartment_release(apt);
3283     }
3284 
3285     /*
3286      * The Standard Global Interface Table (GIT) object is a process-wide singleton.
3287      */
3288     if (IsEqualIID(&clsid, &CLSID_StdGlobalInterfaceTable))
3289     {
3290         IGlobalInterfaceTable *git = get_std_git();
3291         TRACE("Retrieving GIT\n");
3292         return return_multi_qi((IUnknown*)git, cmq, pResults, FALSE);
3293     }
3294 
3295     if (IsEqualCLSID(&clsid, &CLSID_ManualResetEvent)) {
3296         hres = ManualResetEvent_Construct(pUnkOuter, pResults[0].pIID, (void**)&unk);
3297         if (FAILED(hres))
3298             return hres;
3299         return return_multi_qi(unk, cmq, pResults, TRUE);
3300     }
3301 
3302     /*
3303      * Get a class factory to construct the object we want.
3304      */
3305     hres = CoGetClassObject(&clsid, dwClsContext, NULL, &IID_IClassFactory, (void**)&cf);
3306     if (FAILED(hres))
3307         return hres;
3308 
3309     /*
3310      * Create the object and don't forget to release the factory
3311      */
3312     hres = IClassFactory_CreateInstance(cf, pUnkOuter, pResults[0].pIID, (void**)&unk);
3313     IClassFactory_Release(cf);
3314     if (FAILED(hres))
3315     {
3316         if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
3317             FIXME("Class %s does not support aggregation\n", debugstr_guid(&clsid));
3318         else
3319             FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n",
3320                   debugstr_guid(pResults[0].pIID),
3321                   debugstr_guid(&clsid),hres);
3322         return hres;
3323     }
3324 
3325     return return_multi_qi(unk, cmq, pResults, TRUE);
3326 }
3327 
3328 /***********************************************************************
3329  *           CoGetInstanceFromFile [OLE32.@]
3330  */
3331 HRESULT WINAPI DECLSPEC_HOTPATCH CoGetInstanceFromFile(
3332   COSERVERINFO *server_info,
3333   CLSID        *rclsid,
3334   IUnknown     *outer,
3335   DWORD         cls_context,
3336   DWORD         grfmode,
3337   OLECHAR      *filename,
3338   DWORD         count,
3339   MULTI_QI     *results
3340 )
3341 {
3342   IPersistFile *pf = NULL;
3343   IUnknown* unk = NULL;
3344   CLSID clsid;
3345   HRESULT hr;
3346 
3347   if (count == 0 || !results)
3348     return E_INVALIDARG;
3349 
3350   if (server_info)
3351     FIXME("() non-NULL server_info not supported\n");
3352 
3353   init_multi_qi(count, results, E_NOINTERFACE);
3354 
3355   /* optionally get CLSID from a file */
3356   if (!rclsid)
3357   {
3358     hr = GetClassFile(filename, &clsid);
3359     if (FAILED(hr))
3360     {
3361       ERR("failed to get CLSID from a file\n");
3362       return hr;
3363     }
3364 
3365     rclsid = &clsid;
3366   }
3367 
3368   hr = CoCreateInstance(rclsid,
3369 			outer,
3370 			cls_context,
3371 			&IID_IUnknown,
3372 			(void**)&unk);
3373 
3374   if (hr != S_OK)
3375   {
3376       init_multi_qi(count, results, hr);
3377       return hr;
3378   }
3379 
3380   /* init from file */
3381   hr = IUnknown_QueryInterface(unk, &IID_IPersistFile, (void**)&pf);
3382   if (FAILED(hr))
3383   {
3384       init_multi_qi(count, results, hr);
3385       IUnknown_Release(unk);
3386       return hr;
3387   }
3388 
3389   hr = IPersistFile_Load(pf, filename, grfmode);
3390   IPersistFile_Release(pf);
3391   if (SUCCEEDED(hr))
3392       return return_multi_qi(unk, count, results, FALSE);
3393   else
3394   {
3395       init_multi_qi(count, results, hr);
3396       IUnknown_Release(unk);
3397       return hr;
3398   }
3399 }
3400 
3401 /***********************************************************************
3402  *           CoGetInstanceFromIStorage [OLE32.@]
3403  */
3404 HRESULT WINAPI CoGetInstanceFromIStorage(
3405   COSERVERINFO *server_info,
3406   CLSID        *rclsid,
3407   IUnknown     *outer,
3408   DWORD         cls_context,
3409   IStorage     *storage,
3410   DWORD         count,
3411   MULTI_QI     *results
3412 )
3413 {
3414   IPersistStorage *ps = NULL;
3415   IUnknown* unk = NULL;
3416   STATSTG stat;
3417   HRESULT hr;
3418 
3419   if (count == 0 || !results || !storage)
3420     return E_INVALIDARG;
3421 
3422   if (server_info)
3423     FIXME("() non-NULL server_info not supported\n");
3424 
3425   init_multi_qi(count, results, E_NOINTERFACE);
3426 
3427   /* optionally get CLSID from a file */
3428   if (!rclsid)
3429   {
3430     memset(&stat.clsid, 0, sizeof(stat.clsid));
3431     hr = IStorage_Stat(storage, &stat, STATFLAG_NONAME);
3432     if (FAILED(hr))
3433     {
3434       ERR("failed to get CLSID from a file\n");
3435       return hr;
3436     }
3437 
3438     rclsid = &stat.clsid;
3439   }
3440 
3441   hr = CoCreateInstance(rclsid,
3442 			outer,
3443 			cls_context,
3444 			&IID_IUnknown,
3445 			(void**)&unk);
3446 
3447   if (hr != S_OK)
3448     return hr;
3449 
3450   /* init from IStorage */
3451   hr = IUnknown_QueryInterface(unk, &IID_IPersistStorage, (void**)&ps);
3452   if (FAILED(hr))
3453       ERR("failed to get IPersistStorage\n");
3454 
3455   if (ps)
3456   {
3457       IPersistStorage_Load(ps, storage);
3458       IPersistStorage_Release(ps);
3459   }
3460 
3461   return return_multi_qi(unk, count, results, FALSE);
3462 }
3463 
3464 /***********************************************************************
3465  *           CoLoadLibrary (OLE32.@)
3466  *
3467  * Loads a library.
3468  *
3469  * PARAMS
3470  *  lpszLibName [I] Path to library.
3471  *  bAutoFree   [I] Whether the library should automatically be freed.
3472  *
3473  * RETURNS
3474  *  Success: Handle to loaded library.
3475  *  Failure: NULL.
3476  *
3477  * SEE ALSO
3478  *  CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3479  */
3480 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
3481 {
3482     TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
3483 
3484     return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
3485 }
3486 
3487 /***********************************************************************
3488  *           CoFreeLibrary [OLE32.@]
3489  *
3490  * Unloads a library from memory.
3491  *
3492  * PARAMS
3493  *  hLibrary [I] Handle to library to unload.
3494  *
3495  * RETURNS
3496  *  Nothing
3497  *
3498  * SEE ALSO
3499  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
3500  */
3501 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
3502 {
3503     FreeLibrary(hLibrary);
3504 }
3505 
3506 
3507 /***********************************************************************
3508  *           CoFreeAllLibraries [OLE32.@]
3509  *
3510  * Function for backwards compatibility only. Does nothing.
3511  *
3512  * RETURNS
3513  *  Nothing.
3514  *
3515  * SEE ALSO
3516  *  CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
3517  */
3518 void WINAPI CoFreeAllLibraries(void)
3519 {
3520     /* NOP */
3521 }
3522 
3523 /***********************************************************************
3524  *           CoFreeUnusedLibrariesEx [OLE32.@]
3525  *
3526  * Frees any previously unused libraries whose delay has expired and marks
3527  * currently unused libraries for unloading. Unused are identified as those that
3528  * return S_OK from their DllCanUnloadNow function.
3529  *
3530  * PARAMS
3531  *  dwUnloadDelay [I] Unload delay in milliseconds.
3532  *  dwReserved    [I] Reserved. Set to 0.
3533  *
3534  * RETURNS
3535  *  Nothing.
3536  *
3537  * SEE ALSO
3538  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3539  */
3540 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
3541 {
3542     struct apartment *apt = COM_CurrentApt();
3543     if (!apt)
3544     {
3545         ERR("apartment not initialised\n");
3546         return;
3547     }
3548 
3549     apartment_freeunusedlibraries(apt, dwUnloadDelay);
3550 }
3551 
3552 /***********************************************************************
3553  *           CoFreeUnusedLibraries [OLE32.@]
3554  *
3555  * Frees any unused libraries. Unused are identified as those that return
3556  * S_OK from their DllCanUnloadNow function.
3557  *
3558  * RETURNS
3559  *  Nothing.
3560  *
3561  * SEE ALSO
3562  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
3563  */
3564 void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibraries(void)
3565 {
3566     CoFreeUnusedLibrariesEx(INFINITE, 0);
3567 }
3568 
3569 /***********************************************************************
3570  *           CoFileTimeNow [OLE32.@]
3571  *
3572  * Retrieves the current time in FILETIME format.
3573  *
3574  * PARAMS
3575  *  lpFileTime [O] The current time.
3576  *
3577  * RETURNS
3578  *	S_OK.
3579  */
3580 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
3581 {
3582     GetSystemTimeAsFileTime( lpFileTime );
3583     return S_OK;
3584 }
3585 
3586 /******************************************************************************
3587  *		CoLockObjectExternal	[OLE32.@]
3588  *
3589  * Increments or decrements the external reference count of a stub object.
3590  *
3591  * PARAMS
3592  *  pUnk                [I] Stub object.
3593  *  fLock               [I] If TRUE then increments the external ref-count,
3594  *                          otherwise decrements.
3595  *  fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
3596  *                          calling CoDisconnectObject.
3597  *
3598  * RETURNS
3599  *  Success: S_OK.
3600  *  Failure: HRESULT code.
3601  *
3602  * NOTES
3603  *  If fLock is TRUE and an object is passed in that doesn't have a stub
3604  *  manager then a new stub manager is created for the object.
3605  */
3606 HRESULT WINAPI CoLockObjectExternal(
3607     LPUNKNOWN pUnk,
3608     BOOL fLock,
3609     BOOL fLastUnlockReleases)
3610 {
3611     struct stub_manager *stubmgr;
3612     struct apartment *apt;
3613 
3614     TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
3615           pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
3616 
3617     apt = COM_CurrentApt();
3618     if (!apt) return CO_E_NOTINITIALIZED;
3619 
3620     stubmgr = get_stub_manager_from_object(apt, pUnk, fLock);
3621     if (!stubmgr)
3622     {
3623         WARN("stub object not found %p\n", pUnk);
3624         /* Note: native is pretty broken here because it just silently
3625          * fails, without returning an appropriate error code, making apps
3626          * think that the object was disconnected, when it actually wasn't */
3627         return S_OK;
3628     }
3629 
3630     if (fLock)
3631         stub_manager_ext_addref(stubmgr, 1, FALSE);
3632     else
3633         stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
3634 
3635     stub_manager_int_release(stubmgr);
3636     return S_OK;
3637 }
3638 
3639 /***********************************************************************
3640  *           CoInitializeWOW (OLE32.@)
3641  *
3642  * WOW equivalent of CoInitialize?
3643  *
3644  * PARAMS
3645  *  x [I] Unknown.
3646  *  y [I] Unknown.
3647  *
3648  * RETURNS
3649  *  Unknown.
3650  */
3651 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
3652 {
3653     FIXME("(0x%08x,0x%08x),stub!\n",x,y);
3654     return 0;
3655 }
3656 
3657 /***********************************************************************
3658  *           CoGetState [OLE32.@]
3659  *
3660  * Retrieves the thread state object previously stored by CoSetState().
3661  *
3662  * PARAMS
3663  *  ppv [I] Address where pointer to object will be stored.
3664  *
3665  * RETURNS
3666  *  Success: S_OK.
3667  *  Failure: E_OUTOFMEMORY.
3668  *
3669  * NOTES
3670  *  Crashes on all invalid ppv addresses, including NULL.
3671  *  If the function returns a non-NULL object then the caller must release its
3672  *  reference on the object when the object is no longer required.
3673  *
3674  * SEE ALSO
3675  *  CoSetState().
3676  */
3677 HRESULT WINAPI CoGetState(IUnknown ** ppv)
3678 {
3679     struct oletls *info = COM_CurrentInfo();
3680     if (!info) return E_OUTOFMEMORY;
3681 
3682     *ppv = NULL;
3683 
3684     if (info->state)
3685     {
3686         IUnknown_AddRef(info->state);
3687         *ppv = info->state;
3688         TRACE("apt->state=%p\n", info->state);
3689     }
3690 
3691     return S_OK;
3692 }
3693 
3694 /***********************************************************************
3695  *           CoSetState [OLE32.@]
3696  *
3697  * Sets the thread state object.
3698  *
3699  * PARAMS
3700  *  pv [I] Pointer to state object to be stored.
3701  *
3702  * NOTES
3703  *  The system keeps a reference on the object while the object stored.
3704  *
3705  * RETURNS
3706  *  Success: S_OK.
3707  *  Failure: E_OUTOFMEMORY.
3708  */
3709 HRESULT WINAPI CoSetState(IUnknown * pv)
3710 {
3711     struct oletls *info = COM_CurrentInfo();
3712     if (!info) return E_OUTOFMEMORY;
3713 
3714     if (pv) IUnknown_AddRef(pv);
3715 
3716     if (info->state)
3717     {
3718         TRACE("-- release %p now\n", info->state);
3719         IUnknown_Release(info->state);
3720     }
3721 
3722     info->state = pv;
3723 
3724     return S_OK;
3725 }
3726 
3727 
3728 /******************************************************************************
3729  *              CoTreatAsClass        [OLE32.@]
3730  *
3731  * Sets the TreatAs value of a class.
3732  *
3733  * PARAMS
3734  *  clsidOld [I] Class to set TreatAs value on.
3735  *  clsidNew [I] The class the clsidOld should be treated as.
3736  *
3737  * RETURNS
3738  *  Success: S_OK.
3739  *  Failure: HRESULT code.
3740  *
3741  * SEE ALSO
3742  *  CoGetTreatAsClass
3743  */
3744 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
3745 {
3746     static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
3747     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3748     HKEY hkey = NULL;
3749     WCHAR szClsidNew[CHARS_IN_GUID];
3750     HRESULT res = S_OK;
3751     WCHAR auto_treat_as[CHARS_IN_GUID];
3752     LONG auto_treat_as_size = sizeof(auto_treat_as);
3753     CLSID id;
3754 
3755     res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
3756     if (FAILED(res))
3757         goto done;
3758 
3759     if (IsEqualGUID( clsidOld, clsidNew ))
3760     {
3761        if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
3762            CLSIDFromString(auto_treat_as, &id) == S_OK)
3763        {
3764            if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
3765            {
3766                res = REGDB_E_WRITEREGDB;
3767                goto done;
3768            }
3769        }
3770        else
3771        {
3772            if(RegDeleteKeyW(hkey, wszTreatAs))
3773                res = REGDB_E_WRITEREGDB;
3774            goto done;
3775        }
3776     }
3777     else
3778     {
3779         if(IsEqualGUID(clsidNew, &CLSID_NULL)){
3780            RegDeleteKeyW(hkey, wszTreatAs);
3781         }else{
3782             if(!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew))){
3783                 WARN("StringFromGUID2 failed\n");
3784                 res = E_FAIL;
3785                 goto done;
3786             }
3787 
3788             if(RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)) != ERROR_SUCCESS){
3789                 WARN("RegSetValue failed\n");
3790                 res = REGDB_E_WRITEREGDB;
3791                 goto done;
3792             }
3793         }
3794     }
3795 
3796 done:
3797     if (hkey) RegCloseKey(hkey);
3798     return res;
3799 }
3800 
3801 /******************************************************************************
3802  *              CoGetTreatAsClass        [OLE32.@]
3803  *
3804  * Gets the TreatAs value of a class.
3805  *
3806  * PARAMS
3807  *  clsidOld [I] Class to get the TreatAs value of.
3808  *  clsidNew [I] The class the clsidOld should be treated as.
3809  *
3810  * RETURNS
3811  *  Success: S_OK.
3812  *  Failure: HRESULT code.
3813  *
3814  * SEE ALSO
3815  *  CoSetTreatAsClass
3816  */
3817 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
3818 {
3819     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
3820     HKEY hkey = NULL;
3821     WCHAR szClsidNew[CHARS_IN_GUID];
3822     HRESULT res = S_OK;
3823     LONG len = sizeof(szClsidNew);
3824 
3825     TRACE("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
3826 
3827     if (!clsidOld || !clsidNew)
3828         return E_INVALIDARG;
3829 
3830     *clsidNew = *clsidOld; /* copy over old value */
3831 
3832     res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
3833     if (FAILED(res))
3834     {
3835         res = S_FALSE;
3836         goto done;
3837     }
3838     if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
3839     {
3840         res = S_FALSE;
3841 	goto done;
3842     }
3843     res = CLSIDFromString(szClsidNew,clsidNew);
3844     if (FAILED(res))
3845         ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
3846 done:
3847     if (hkey) RegCloseKey(hkey);
3848     return res;
3849 }
3850 
3851 /******************************************************************************
3852  *		CoGetCurrentProcess	[OLE32.@]
3853  *
3854  * Gets the current process ID.
3855  *
3856  * RETURNS
3857  *  The current process ID.
3858  *
3859  * NOTES
3860  *   Is DWORD really the correct return type for this function?
3861  */
3862 DWORD WINAPI CoGetCurrentProcess(void)
3863 {
3864 	return GetCurrentProcessId();
3865 }
3866 
3867 /***********************************************************************
3868  *              CoGetCurrentLogicalThreadId        [OLE32.@]
3869  */
3870 HRESULT WINAPI CoGetCurrentLogicalThreadId(GUID *id)
3871 {
3872     TRACE("(%p)\n", id);
3873 
3874     if (!id)
3875         return E_INVALIDARG;
3876 
3877     *id = COM_CurrentCausalityId();
3878     return S_OK;
3879 }
3880 
3881 /******************************************************************************
3882  *		CoRegisterMessageFilter	[OLE32.@]
3883  *
3884  * Registers a message filter.
3885  *
3886  * PARAMS
3887  *  lpMessageFilter [I] Pointer to interface.
3888  *  lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
3889  *
3890  * RETURNS
3891  *  Success: S_OK.
3892  *  Failure: HRESULT code.
3893  *
3894  * NOTES
3895  *  Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
3896  *  lpMessageFilter removes the message filter.
3897  *
3898  *  If lplpMessageFilter is not NULL the previous message filter will be
3899  *  returned in the memory pointer to this parameter and the caller is
3900  *  responsible for releasing the object.
3901  *
3902  *  The current thread be in an apartment otherwise the function will crash.
3903  */
3904 HRESULT WINAPI CoRegisterMessageFilter(
3905     LPMESSAGEFILTER lpMessageFilter,
3906     LPMESSAGEFILTER *lplpMessageFilter)
3907 {
3908     struct apartment *apt;
3909     IMessageFilter *lpOldMessageFilter;
3910 
3911     TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3912 
3913     apt = COM_CurrentApt();
3914 
3915     /* can't set a message filter in a multi-threaded apartment */
3916     if (!apt || apt->multi_threaded)
3917     {
3918         WARN("can't set message filter in MTA or uninitialized apt\n");
3919         return CO_E_NOT_SUPPORTED;
3920     }
3921 
3922     if (lpMessageFilter)
3923         IMessageFilter_AddRef(lpMessageFilter);
3924 
3925     EnterCriticalSection(&apt->cs);
3926 
3927     lpOldMessageFilter = apt->filter;
3928     apt->filter = lpMessageFilter;
3929 
3930     LeaveCriticalSection(&apt->cs);
3931 
3932     if (lplpMessageFilter)
3933         *lplpMessageFilter = lpOldMessageFilter;
3934     else if (lpOldMessageFilter)
3935         IMessageFilter_Release(lpOldMessageFilter);
3936 
3937     return S_OK;
3938 }
3939 
3940 /***********************************************************************
3941  *           CoIsOle1Class [OLE32.@]
3942  *
3943  * Determines whether the specified class an OLE v1 class.
3944  *
3945  * PARAMS
3946  *  clsid [I] Class to test.
3947  *
3948  * RETURNS
3949  *  TRUE if the class is an OLE v1 class, or FALSE otherwise.
3950  */
3951 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3952 {
3953   FIXME("%s\n", debugstr_guid(clsid));
3954   return FALSE;
3955 }
3956 
3957 /***********************************************************************
3958  *           IsEqualGUID [OLE32.@]
3959  *
3960  * Compares two Unique Identifiers.
3961  *
3962  * PARAMS
3963  *  rguid1 [I] The first GUID to compare.
3964  *  rguid2 [I] The other GUID to compare.
3965  *
3966  * RETURNS
3967  *	TRUE if equal
3968  */
3969 #undef IsEqualGUID
3970 BOOL WINAPI IsEqualGUID(
3971      REFGUID rguid1,
3972      REFGUID rguid2)
3973 {
3974     return !memcmp(rguid1,rguid2,sizeof(GUID));
3975 }
3976 
3977 /***********************************************************************
3978  *           CoInitializeSecurity [OLE32.@]
3979  */
3980 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3981                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3982                                     void* pReserved1, DWORD dwAuthnLevel,
3983                                     DWORD dwImpLevel, void* pReserved2,
3984                                     DWORD dwCapabilities, void* pReserved3)
3985 {
3986   FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3987         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3988         dwCapabilities, pReserved3);
3989   return S_OK;
3990 }
3991 
3992 /***********************************************************************
3993  *           CoSuspendClassObjects [OLE32.@]
3994  *
3995  * Suspends all registered class objects to prevent further requests coming in
3996  * for those objects.
3997  *
3998  * RETURNS
3999  *  Success: S_OK.
4000  *  Failure: HRESULT code.
4001  */
4002 HRESULT WINAPI CoSuspendClassObjects(void)
4003 {
4004     FIXME("\n");
4005     return S_OK;
4006 }
4007 
4008 /***********************************************************************
4009  *           CoAddRefServerProcess [OLE32.@]
4010  *
4011  * Helper function for incrementing the reference count of a local-server
4012  * process.
4013  *
4014  * RETURNS
4015  *  New reference count.
4016  *
4017  * SEE ALSO
4018  *  CoReleaseServerProcess().
4019  */
4020 ULONG WINAPI CoAddRefServerProcess(void)
4021 {
4022     ULONG refs;
4023 
4024     TRACE("\n");
4025 
4026     EnterCriticalSection(&csRegisteredClassList);
4027     refs = ++s_COMServerProcessReferences;
4028     LeaveCriticalSection(&csRegisteredClassList);
4029 
4030     TRACE("refs before: %d\n", refs - 1);
4031 
4032     return refs;
4033 }
4034 
4035 /***********************************************************************
4036  *           CoReleaseServerProcess [OLE32.@]
4037  *
4038  * Helper function for decrementing the reference count of a local-server
4039  * process.
4040  *
4041  * RETURNS
4042  *  New reference count.
4043  *
4044  * NOTES
4045  *  When reference count reaches 0, this function suspends all registered
4046  *  classes so no new connections are accepted.
4047  *
4048  * SEE ALSO
4049  *  CoAddRefServerProcess(), CoSuspendClassObjects().
4050  */
4051 ULONG WINAPI CoReleaseServerProcess(void)
4052 {
4053     ULONG refs;
4054 
4055     TRACE("\n");
4056 
4057     EnterCriticalSection(&csRegisteredClassList);
4058 
4059     refs = --s_COMServerProcessReferences;
4060     /* FIXME: if (!refs) COM_SuspendClassObjects(); */
4061 
4062     LeaveCriticalSection(&csRegisteredClassList);
4063 
4064     TRACE("refs after: %d\n", refs);
4065 
4066     return refs;
4067 }
4068 
4069 /***********************************************************************
4070  *           CoIsHandlerConnected [OLE32.@]
4071  *
4072  * Determines whether a proxy is connected to a remote stub.
4073  *
4074  * PARAMS
4075  *  pUnk [I] Pointer to object that may or may not be connected.
4076  *
4077  * RETURNS
4078  *  TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
4079  *  FALSE otherwise.
4080  */
4081 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
4082 {
4083     FIXME("%p\n", pUnk);
4084 
4085     return TRUE;
4086 }
4087 
4088 /***********************************************************************
4089  *           CoAllowSetForegroundWindow [OLE32.@]
4090  *
4091  */
4092 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
4093 {
4094     FIXME("(%p, %p): stub\n", pUnk, pvReserved);
4095     return S_OK;
4096 }
4097 
4098 /***********************************************************************
4099  *           CoQueryProxyBlanket [OLE32.@]
4100  *
4101  * Retrieves the security settings being used by a proxy.
4102  *
4103  * PARAMS
4104  *  pProxy        [I] Pointer to the proxy object.
4105  *  pAuthnSvc     [O] The type of authentication service.
4106  *  pAuthzSvc     [O] The type of authorization service.
4107  *  ppServerPrincName [O] Optional. The server prinicple name.
4108  *  pAuthnLevel   [O] The authentication level.
4109  *  pImpLevel     [O] The impersonation level.
4110  *  ppAuthInfo    [O] Information specific to the authorization/authentication service.
4111  *  pCapabilities [O] Flags affecting the security behaviour.
4112  *
4113  * RETURNS
4114  *  Success: S_OK.
4115  *  Failure: HRESULT code.
4116  *
4117  * SEE ALSO
4118  *  CoCopyProxy, CoSetProxyBlanket.
4119  */
4120 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
4121     DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
4122     DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
4123 {
4124     IClientSecurity *pCliSec;
4125     HRESULT hr;
4126 
4127     TRACE("%p\n", pProxy);
4128 
4129     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4130     if (SUCCEEDED(hr))
4131     {
4132         hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
4133                                           pAuthzSvc, ppServerPrincName,
4134                                           pAuthnLevel, pImpLevel, ppAuthInfo,
4135                                           pCapabilities);
4136         IClientSecurity_Release(pCliSec);
4137     }
4138 
4139     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4140     return hr;
4141 }
4142 
4143 /***********************************************************************
4144  *           CoSetProxyBlanket [OLE32.@]
4145  *
4146  * Sets the security settings for a proxy.
4147  *
4148  * PARAMS
4149  *  pProxy       [I] Pointer to the proxy object.
4150  *  AuthnSvc     [I] The type of authentication service.
4151  *  AuthzSvc     [I] The type of authorization service.
4152  *  pServerPrincName [I] The server prinicple name.
4153  *  AuthnLevel   [I] The authentication level.
4154  *  ImpLevel     [I] The impersonation level.
4155  *  pAuthInfo    [I] Information specific to the authorization/authentication service.
4156  *  Capabilities [I] Flags affecting the security behaviour.
4157  *
4158  * RETURNS
4159  *  Success: S_OK.
4160  *  Failure: HRESULT code.
4161  *
4162  * SEE ALSO
4163  *  CoQueryProxyBlanket, CoCopyProxy.
4164  */
4165 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
4166     DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
4167     DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
4168 {
4169     IClientSecurity *pCliSec;
4170     HRESULT hr;
4171 
4172     TRACE("%p\n", pProxy);
4173 
4174     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4175     if (SUCCEEDED(hr))
4176     {
4177         hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
4178                                         AuthzSvc, pServerPrincName,
4179                                         AuthnLevel, ImpLevel, pAuthInfo,
4180                                         Capabilities);
4181         IClientSecurity_Release(pCliSec);
4182     }
4183 
4184     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4185     return hr;
4186 }
4187 
4188 /***********************************************************************
4189  *           CoCopyProxy [OLE32.@]
4190  *
4191  * Copies a proxy.
4192  *
4193  * PARAMS
4194  *  pProxy [I] Pointer to the proxy object.
4195  *  ppCopy [O] Copy of the proxy.
4196  *
4197  * RETURNS
4198  *  Success: S_OK.
4199  *  Failure: HRESULT code.
4200  *
4201  * SEE ALSO
4202  *  CoQueryProxyBlanket, CoSetProxyBlanket.
4203  */
4204 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
4205 {
4206     IClientSecurity *pCliSec;
4207     HRESULT hr;
4208 
4209     TRACE("%p\n", pProxy);
4210 
4211     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
4212     if (SUCCEEDED(hr))
4213     {
4214         hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
4215         IClientSecurity_Release(pCliSec);
4216     }
4217 
4218     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
4219     return hr;
4220 }
4221 
4222 
4223 /***********************************************************************
4224  *           CoGetCallContext [OLE32.@]
4225  *
4226  * Gets the context of the currently executing server call in the current
4227  * thread.
4228  *
4229  * PARAMS
4230  *  riid [I] Context interface to return.
4231  *  ppv  [O] Pointer to memory that will receive the context on return.
4232  *
4233  * RETURNS
4234  *  Success: S_OK.
4235  *  Failure: HRESULT code.
4236  */
4237 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
4238 {
4239     struct oletls *info = COM_CurrentInfo();
4240 
4241     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4242 
4243     if (!info)
4244         return E_OUTOFMEMORY;
4245 
4246     if (!info->call_state)
4247         return RPC_E_CALL_COMPLETE;
4248 
4249     return IUnknown_QueryInterface(info->call_state, riid, ppv);
4250 }
4251 
4252 /***********************************************************************
4253  *           CoSwitchCallContext [OLE32.@]
4254  *
4255  * Switches the context of the currently executing server call in the current
4256  * thread.
4257  *
4258  * PARAMS
4259  *  pObject     [I] Pointer to new context object
4260  *  ppOldObject [O] Pointer to memory that will receive old context object pointer
4261  *
4262  * RETURNS
4263  *  Success: S_OK.
4264  *  Failure: HRESULT code.
4265  */
4266 HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
4267 {
4268     struct oletls *info = COM_CurrentInfo();
4269 
4270     TRACE("(%p, %p)\n", pObject, ppOldObject);
4271 
4272     if (!info)
4273         return E_OUTOFMEMORY;
4274 
4275     *ppOldObject = info->call_state;
4276     info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */
4277 
4278     return S_OK;
4279 }
4280 
4281 /***********************************************************************
4282  *           CoQueryClientBlanket [OLE32.@]
4283  *
4284  * Retrieves the authentication information about the client of the currently
4285  * executing server call in the current thread.
4286  *
4287  * PARAMS
4288  *  pAuthnSvc     [O] Optional. The type of authentication service.
4289  *  pAuthzSvc     [O] Optional. The type of authorization service.
4290  *  pServerPrincName [O] Optional. The server prinicple name.
4291  *  pAuthnLevel   [O] Optional. The authentication level.
4292  *  pImpLevel     [O] Optional. The impersonation level.
4293  *  pPrivs        [O] Optional. Information about the privileges of the client.
4294  *  pCapabilities [IO] Optional. Flags affecting the security behaviour.
4295  *
4296  * RETURNS
4297  *  Success: S_OK.
4298  *  Failure: HRESULT code.
4299  *
4300  * SEE ALSO
4301  *  CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
4302  */
4303 HRESULT WINAPI CoQueryClientBlanket(
4304     DWORD *pAuthnSvc,
4305     DWORD *pAuthzSvc,
4306     OLECHAR **pServerPrincName,
4307     DWORD *pAuthnLevel,
4308     DWORD *pImpLevel,
4309     RPC_AUTHZ_HANDLE *pPrivs,
4310     DWORD *pCapabilities)
4311 {
4312     IServerSecurity *pSrvSec;
4313     HRESULT hr;
4314 
4315     TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
4316         pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
4317         pPrivs, pCapabilities);
4318 
4319     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4320     if (SUCCEEDED(hr))
4321     {
4322         hr = IServerSecurity_QueryBlanket(
4323             pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
4324             pImpLevel, pPrivs, pCapabilities);
4325         IServerSecurity_Release(pSrvSec);
4326     }
4327 
4328     return hr;
4329 }
4330 
4331 /***********************************************************************
4332  *           CoImpersonateClient [OLE32.@]
4333  *
4334  * Impersonates the client of the currently executing server call in the
4335  * current thread.
4336  *
4337  * PARAMS
4338  *  None.
4339  *
4340  * RETURNS
4341  *  Success: S_OK.
4342  *  Failure: HRESULT code.
4343  *
4344  * NOTES
4345  *  If this function fails then the current thread will not be impersonating
4346  *  the client and all actions will take place on behalf of the server.
4347  *  Therefore, it is important to check the return value from this function.
4348  *
4349  * SEE ALSO
4350  *  CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
4351  */
4352 HRESULT WINAPI CoImpersonateClient(void)
4353 {
4354     IServerSecurity *pSrvSec;
4355     HRESULT hr;
4356 
4357     TRACE("\n");
4358 
4359     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4360     if (SUCCEEDED(hr))
4361     {
4362         hr = IServerSecurity_ImpersonateClient(pSrvSec);
4363         IServerSecurity_Release(pSrvSec);
4364     }
4365 
4366     return hr;
4367 }
4368 
4369 /***********************************************************************
4370  *           CoRevertToSelf [OLE32.@]
4371  *
4372  * Ends the impersonation of the client of the currently executing server
4373  * call in the current thread.
4374  *
4375  * PARAMS
4376  *  None.
4377  *
4378  * RETURNS
4379  *  Success: S_OK.
4380  *  Failure: HRESULT code.
4381  *
4382  * SEE ALSO
4383  *  CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
4384  */
4385 HRESULT WINAPI CoRevertToSelf(void)
4386 {
4387     IServerSecurity *pSrvSec;
4388     HRESULT hr;
4389 
4390     TRACE("\n");
4391 
4392     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
4393     if (SUCCEEDED(hr))
4394     {
4395         hr = IServerSecurity_RevertToSelf(pSrvSec);
4396         IServerSecurity_Release(pSrvSec);
4397     }
4398 
4399     return hr;
4400 }
4401 
4402 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
4403 {
4404     /* first try to retrieve messages for incoming COM calls to the apartment window */
4405     return (apt->win && PeekMessageW(msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) ||
4406            /* next retrieve other messages necessary for the app to remain responsive */
4407            PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
4408            PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
4409 }
4410 
4411 /***********************************************************************
4412  *           CoWaitForMultipleHandles [OLE32.@]
4413  *
4414  * Waits for one or more handles to become signaled.
4415  *
4416  * PARAMS
4417  *  dwFlags   [I] Flags. See notes.
4418  *  dwTimeout [I] Timeout in milliseconds.
4419  *  cHandles  [I] Number of handles pointed to by pHandles.
4420  *  pHandles  [I] Handles to wait for.
4421  *  lpdwindex [O] Index of handle that was signaled.
4422  *
4423  * RETURNS
4424  *  Success: S_OK.
4425  *  Failure: RPC_S_CALLPENDING on timeout.
4426  *
4427  * NOTES
4428  *
4429  * The dwFlags parameter can be zero or more of the following:
4430  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
4431  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
4432  *
4433  * SEE ALSO
4434  *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
4435  */
4436 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
4437     ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
4438 {
4439     HRESULT hr = S_OK;
4440     DWORD start_time = GetTickCount();
4441     APARTMENT *apt = COM_CurrentApt();
4442     BOOL message_loop = apt && !apt->multi_threaded;
4443     BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0;
4444 
4445     TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
4446         pHandles, lpdwindex);
4447 
4448     if (!lpdwindex)
4449         return E_INVALIDARG;
4450 
4451     *lpdwindex = 0;
4452 
4453     if (!pHandles)
4454         return E_INVALIDARG;
4455 
4456     if (!cHandles)
4457         return RPC_E_NO_SYNC;
4458 
4459     while (TRUE)
4460     {
4461         DWORD now = GetTickCount();
4462         DWORD res;
4463 
4464         if (now - start_time > dwTimeout)
4465         {
4466             hr = RPC_S_CALLPENDING;
4467             break;
4468         }
4469 
4470         if (message_loop)
4471         {
4472             DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
4473                     ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
4474 
4475             TRACE("waiting for rpc completion or window message\n");
4476 
4477             res = WAIT_TIMEOUT;
4478 
4479             if (check_apc)
4480             {
4481                 res = WaitForMultipleObjectsEx(cHandles, pHandles,
4482                     (dwFlags & COWAIT_WAITALL) != 0, 0, TRUE);
4483                 check_apc = FALSE;
4484             }
4485 
4486             if (res == WAIT_TIMEOUT)
4487                 res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
4488                     (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4489                     QS_SENDMESSAGE | QS_ALLPOSTMESSAGE | QS_PAINT, wait_flags);
4490 
4491             if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
4492             {
4493                 MSG msg;
4494                 int count = 0;
4495 
4496                 /* call message filter */
4497 
4498                 if (COM_CurrentApt()->filter)
4499                 {
4500                     PENDINGTYPE pendingtype =
4501                         COM_CurrentInfo()->pending_call_count_server ?
4502                             PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
4503                     DWORD be_handled = IMessageFilter_MessagePending(
4504                         COM_CurrentApt()->filter, 0 /* FIXME */,
4505                         now - start_time, pendingtype);
4506                     TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
4507                     switch (be_handled)
4508                     {
4509                     case PENDINGMSG_CANCELCALL:
4510                         WARN("call canceled\n");
4511                         hr = RPC_E_CALL_CANCELED;
4512                         break;
4513                     case PENDINGMSG_WAITNOPROCESS:
4514                     case PENDINGMSG_WAITDEFPROCESS:
4515                     default:
4516                         /* FIXME: MSDN is very vague about the difference
4517                          * between WAITNOPROCESS and WAITDEFPROCESS - there
4518                          * appears to be none, so it is possibly a left-over
4519                          * from the 16-bit world. */
4520                         break;
4521                     }
4522                 }
4523 
4524                 /* some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever,
4525                  * so after processing 100 messages we go back to checking the wait handles */
4526                 while (count++ < 100 && COM_PeekMessage(apt, &msg))
4527                 {
4528                     TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
4529                     TranslateMessage(&msg);
4530                     DispatchMessageW(&msg);
4531                     if (msg.message == WM_QUIT)
4532                     {
4533                         TRACE("resending WM_QUIT to outer message loop\n");
4534                         PostQuitMessage(msg.wParam);
4535                         /* no longer need to process messages */
4536                         message_loop = FALSE;
4537                         break;
4538                     }
4539                 }
4540                 continue;
4541             }
4542         }
4543         else
4544         {
4545             TRACE("waiting for rpc completion\n");
4546 
4547             res = WaitForMultipleObjectsEx(cHandles, pHandles, (dwFlags & COWAIT_WAITALL) != 0,
4548                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
4549                 (dwFlags & COWAIT_ALERTABLE) != 0);
4550         }
4551 
4552         switch (res)
4553         {
4554         case WAIT_TIMEOUT:
4555             hr = RPC_S_CALLPENDING;
4556             break;
4557         case WAIT_FAILED:
4558             hr = HRESULT_FROM_WIN32( GetLastError() );
4559             break;
4560         default:
4561             *lpdwindex = res;
4562             break;
4563         }
4564         break;
4565     }
4566     TRACE("-- 0x%08x\n", hr);
4567     return hr;
4568 }
4569 
4570 
4571 /***********************************************************************
4572  *           CoGetObject [OLE32.@]
4573  *
4574  * Gets the object named by converting the name to a moniker and binding to it.
4575  *
4576  * PARAMS
4577  *  pszName      [I] String representing the object.
4578  *  pBindOptions [I] Parameters affecting the binding to the named object.
4579  *  riid         [I] Interface to bind to on the objecct.
4580  *  ppv          [O] On output, the interface riid of the object represented
4581  *                   by pszName.
4582  *
4583  * RETURNS
4584  *  Success: S_OK.
4585  *  Failure: HRESULT code.
4586  *
4587  * SEE ALSO
4588  *  MkParseDisplayName.
4589  */
4590 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
4591     REFIID riid, void **ppv)
4592 {
4593     IBindCtx *pbc;
4594     HRESULT hr;
4595 
4596     *ppv = NULL;
4597 
4598     hr = CreateBindCtx(0, &pbc);
4599     if (SUCCEEDED(hr))
4600     {
4601         if (pBindOptions)
4602             hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
4603 
4604         if (SUCCEEDED(hr))
4605         {
4606             ULONG chEaten;
4607             IMoniker *pmk;
4608 
4609             hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
4610             if (SUCCEEDED(hr))
4611             {
4612                 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
4613                 IMoniker_Release(pmk);
4614             }
4615         }
4616 
4617         IBindCtx_Release(pbc);
4618     }
4619     return hr;
4620 }
4621 
4622 /***********************************************************************
4623  *           CoRegisterChannelHook [OLE32.@]
4624  *
4625  * Registers a process-wide hook that is called during ORPC calls.
4626  *
4627  * PARAMS
4628  *  guidExtension [I] GUID of the channel hook to register.
4629  *  pChannelHook  [I] Channel hook object to register.
4630  *
4631  * RETURNS
4632  *  Success: S_OK.
4633  *  Failure: HRESULT code.
4634  */
4635 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
4636 {
4637     TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
4638 
4639     return RPC_RegisterChannelHook(guidExtension, pChannelHook);
4640 }
4641 
4642 typedef struct Context
4643 {
4644     IComThreadingInfo IComThreadingInfo_iface;
4645     IContextCallback IContextCallback_iface;
4646     IObjContext IObjContext_iface;
4647     LONG refs;
4648 } Context;
4649 
4650 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
4651 {
4652         return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
4653 }
4654 
4655 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
4656 {
4657         return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
4658 }
4659 
4660 static inline Context *impl_from_IObjContext( IObjContext *iface )
4661 {
4662         return CONTAINING_RECORD(iface, Context, IObjContext_iface);
4663 }
4664 
4665 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
4666 {
4667     *ppv = NULL;
4668 
4669     if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
4670         IsEqualIID(riid, &IID_IUnknown))
4671     {
4672         *ppv = &iface->IComThreadingInfo_iface;
4673     }
4674     else if (IsEqualIID(riid, &IID_IContextCallback))
4675     {
4676         *ppv = &iface->IContextCallback_iface;
4677     }
4678     else if (IsEqualIID(riid, &IID_IObjContext))
4679     {
4680         *ppv = &iface->IObjContext_iface;
4681     }
4682 
4683     if (*ppv)
4684     {
4685         IUnknown_AddRef((IUnknown*)*ppv);
4686         return S_OK;
4687     }
4688 
4689     FIXME("interface not implemented %s\n", debugstr_guid(riid));
4690     return E_NOINTERFACE;
4691 }
4692 
4693 static ULONG Context_AddRef(Context *This)
4694 {
4695     return InterlockedIncrement(&This->refs);
4696 }
4697 
4698 static ULONG Context_Release(Context *This)
4699 {
4700     /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
4701        releasing context while refcount is at 0 destroys it. */
4702     if (!This->refs)
4703     {
4704         HeapFree(GetProcessHeap(), 0, This);
4705         return 0;
4706     }
4707 
4708     return InterlockedDecrement(&This->refs);
4709 }
4710 
4711 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
4712 {
4713     Context *This = impl_from_IComThreadingInfo(iface);
4714     return Context_QueryInterface(This, riid, ppv);
4715 }
4716 
4717 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
4718 {
4719     Context *This = impl_from_IComThreadingInfo(iface);
4720     return Context_AddRef(This);
4721 }
4722 
4723 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
4724 {
4725     Context *This = impl_from_IComThreadingInfo(iface);
4726     return Context_Release(This);
4727 }
4728 
4729 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
4730 {
4731     APTTYPEQUALIFIER qualifier;
4732 
4733     TRACE("(%p)\n", apttype);
4734 
4735     return CoGetApartmentType(apttype, &qualifier);
4736 }
4737 
4738 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
4739 {
4740     APTTYPEQUALIFIER qualifier;
4741     APTTYPE apttype;
4742     HRESULT hr;
4743 
4744     hr = CoGetApartmentType(&apttype, &qualifier);
4745     if (FAILED(hr))
4746         return hr;
4747 
4748     TRACE("(%p)\n", thdtype);
4749 
4750     switch (apttype)
4751     {
4752     case APTTYPE_STA:
4753     case APTTYPE_MAINSTA:
4754         *thdtype = THDTYPE_PROCESSMESSAGES;
4755         break;
4756     default:
4757         *thdtype = THDTYPE_BLOCKMESSAGES;
4758         break;
4759     }
4760     return S_OK;
4761 }
4762 
4763 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
4764 {
4765     TRACE("(%p)\n", logical_thread_id);
4766     return CoGetCurrentLogicalThreadId(logical_thread_id);
4767 }
4768 
4769 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
4770 {
4771     FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
4772     return E_NOTIMPL;
4773 }
4774 
4775 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
4776 {
4777     Context_CTI_QueryInterface,
4778     Context_CTI_AddRef,
4779     Context_CTI_Release,
4780     Context_CTI_GetCurrentApartmentType,
4781     Context_CTI_GetCurrentThreadType,
4782     Context_CTI_GetCurrentLogicalThreadId,
4783     Context_CTI_SetCurrentLogicalThreadId
4784 };
4785 
4786 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
4787 {
4788     Context *This = impl_from_IContextCallback(iface);
4789     return Context_QueryInterface(This, riid, ppv);
4790 }
4791 
4792 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
4793 {
4794     Context *This = impl_from_IContextCallback(iface);
4795     return Context_AddRef(This);
4796 }
4797 
4798 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
4799 {
4800     Context *This = impl_from_IContextCallback(iface);
4801     return Context_Release(This);
4802 }
4803 
4804 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
4805                             ComCallData *param, REFIID riid, int method, IUnknown *punk)
4806 {
4807     Context *This = impl_from_IContextCallback(iface);
4808 
4809     FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
4810     return E_NOTIMPL;
4811 }
4812 
4813 static const IContextCallbackVtbl Context_Callback_Vtbl =
4814 {
4815     Context_CC_QueryInterface,
4816     Context_CC_AddRef,
4817     Context_CC_Release,
4818     Context_CC_ContextCallback
4819 };
4820 
4821 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
4822 {
4823     Context *This = impl_from_IObjContext(iface);
4824     return Context_QueryInterface(This, riid, ppv);
4825 }
4826 
4827 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
4828 {
4829     Context *This = impl_from_IObjContext(iface);
4830     return Context_AddRef(This);
4831 }
4832 
4833 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
4834 {
4835     Context *This = impl_from_IObjContext(iface);
4836     return Context_Release(This);
4837 }
4838 
4839 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
4840 {
4841     Context *This = impl_from_IObjContext(iface);
4842 
4843     FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4844     return E_NOTIMPL;
4845 }
4846 
4847 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
4848 {
4849     Context *This = impl_from_IObjContext(iface);
4850 
4851     FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
4852     return E_NOTIMPL;
4853 }
4854 
4855 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
4856 {
4857     Context *This = impl_from_IObjContext(iface);
4858 
4859     FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
4860     return E_NOTIMPL;
4861 }
4862 
4863 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
4864 {
4865     Context *This = impl_from_IObjContext(iface);
4866 
4867     FIXME("(%p/%p)->(%p)\n", This, iface, props);
4868     return E_NOTIMPL;
4869 }
4870 
4871 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
4872 {
4873     Context *This = impl_from_IObjContext(iface);
4874     FIXME("(%p/%p)\n", This, iface);
4875 }
4876 
4877 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
4878 {
4879     Context *This = impl_from_IObjContext(iface);
4880     FIXME("(%p/%p)\n", This, iface);
4881 }
4882 
4883 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
4884 {
4885     Context *This = impl_from_IObjContext(iface);
4886     FIXME("(%p/%p)\n", This, iface);
4887 }
4888 
4889 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
4890 {
4891     Context *This = impl_from_IObjContext(iface);
4892     FIXME("(%p/%p)\n", This, iface);
4893 }
4894 
4895 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
4896 {
4897     Context *This = impl_from_IObjContext(iface);
4898     FIXME("(%p/%p)\n", This, iface);
4899 }
4900 
4901 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
4902 {
4903     Context *This = impl_from_IObjContext(iface);
4904     FIXME("(%p/%p)\n", This, iface);
4905 }
4906 
4907 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
4908 {
4909     Context *This = impl_from_IObjContext(iface);
4910     FIXME("(%p/%p)\n", This, iface);
4911 }
4912 
4913 static const IObjContextVtbl Context_Object_Vtbl =
4914 {
4915     Context_OC_QueryInterface,
4916     Context_OC_AddRef,
4917     Context_OC_Release,
4918     Context_OC_SetProperty,
4919     Context_OC_RemoveProperty,
4920     Context_OC_GetProperty,
4921     Context_OC_EnumContextProps,
4922     Context_OC_Reserved1,
4923     Context_OC_Reserved2,
4924     Context_OC_Reserved3,
4925     Context_OC_Reserved4,
4926     Context_OC_Reserved5,
4927     Context_OC_Reserved6,
4928     Context_OC_Reserved7
4929 };
4930 
4931 /***********************************************************************
4932  *           CoGetObjectContext [OLE32.@]
4933  *
4934  * Retrieves an object associated with the current context (i.e. apartment).
4935  *
4936  * PARAMS
4937  *  riid [I] ID of the interface of the object to retrieve.
4938  *  ppv  [O] Address where object will be stored on return.
4939  *
4940  * RETURNS
4941  *  Success: S_OK.
4942  *  Failure: HRESULT code.
4943  */
4944 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4945 {
4946     IObjContext *context;
4947     HRESULT hr;
4948 
4949     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4950 
4951     *ppv = NULL;
4952     hr = CoGetContextToken((ULONG_PTR*)&context);
4953     if (FAILED(hr))
4954         return hr;
4955 
4956     return IObjContext_QueryInterface(context, riid, ppv);
4957 }
4958 
4959 /***********************************************************************
4960  *           CoGetContextToken [OLE32.@]
4961  */
4962 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4963 {
4964     struct oletls *info = COM_CurrentInfo();
4965 
4966     TRACE("(%p)\n", token);
4967 
4968     if (!info)
4969         return E_OUTOFMEMORY;
4970 
4971     if (!info->apt)
4972     {
4973         APARTMENT *apt;
4974         if (!(apt = apartment_find_multi_threaded()))
4975         {
4976             ERR("apartment not initialised\n");
4977             return CO_E_NOTINITIALIZED;
4978         }
4979         apartment_release(apt);
4980     }
4981 
4982     if (!token)
4983         return E_POINTER;
4984 
4985     if (!info->context_token)
4986     {
4987         Context *context;
4988 
4989         context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4990         if (!context)
4991             return E_OUTOFMEMORY;
4992 
4993         context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4994         context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4995         context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4996         /* Context token does not take a reference, it's always zero until the
4997            interface is explicitly requested with CoGetObjectContext(). */
4998         context->refs = 0;
4999 
5000         info->context_token = &context->IObjContext_iface;
5001     }
5002 
5003     *token = (ULONG_PTR)info->context_token;
5004     TRACE("context_token=%p\n", info->context_token);
5005 
5006     return S_OK;
5007 }
5008 
5009 /***********************************************************************
5010  *           CoGetDefaultContext [OLE32.@]
5011  */
5012 HRESULT WINAPI CoGetDefaultContext(APTTYPE type, REFIID riid, LPVOID *ppv)
5013 {
5014     FIXME("%d %s %p stub\n", type, debugstr_guid(riid), ppv);
5015     return E_NOINTERFACE;
5016 }
5017 
5018 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
5019 {
5020     static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
5021     HKEY hkey;
5022     HRESULT hres;
5023 
5024     hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
5025     if (SUCCEEDED(hres))
5026     {
5027         struct class_reg_data regdata;
5028         WCHAR dllpath[MAX_PATH+1];
5029 
5030         regdata.u.hkey = hkey;
5031         regdata.hkey = TRUE;
5032 
5033         if (COM_RegReadPath(&regdata, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
5034         {
5035             static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
5036             if (!strcmpiW(dllpath, wszOle32))
5037             {
5038                 RegCloseKey(hkey);
5039                 return HandlerCF_Create(rclsid, riid, ppv);
5040             }
5041         }
5042         else
5043             WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
5044         RegCloseKey(hkey);
5045     }
5046 
5047     return CLASS_E_CLASSNOTAVAILABLE;
5048 }
5049 
5050 /***********************************************************************
5051  *           CoGetApartmentType [OLE32.@]
5052  */
5053 HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
5054 {
5055     struct oletls *info = COM_CurrentInfo();
5056 
5057     FIXME("(%p, %p): semi-stub\n", type, qualifier);
5058 
5059     if (!type || !qualifier)
5060         return E_INVALIDARG;
5061 
5062     if (!info)
5063         return E_OUTOFMEMORY;
5064 
5065     if (!info->apt)
5066         *type = APTTYPE_CURRENT;
5067     else if (info->apt->multi_threaded)
5068         *type = APTTYPE_MTA;
5069     else if (info->apt->main)
5070         *type = APTTYPE_MAINSTA;
5071     else
5072         *type = APTTYPE_STA;
5073 
5074     *qualifier = APTTYPEQUALIFIER_NONE;
5075 
5076     return info->apt ? S_OK : CO_E_NOTINITIALIZED;
5077 }
5078 
5079 /***********************************************************************
5080  *           CoRegisterSurrogate [OLE32.@]
5081  */
5082 HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate)
5083 {
5084     FIXME("(%p): stub\n", surrogate);
5085 
5086     return E_NOTIMPL;
5087 }
5088 
5089 /***********************************************************************
5090  *           CoRegisterSurrogateEx [OLE32.@]
5091  */
5092 HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved)
5093 {
5094     FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved);
5095 
5096     return E_NOTIMPL;
5097 }
5098 
5099 typedef struct {
5100     IGlobalOptions IGlobalOptions_iface;
5101     LONG ref;
5102 } GlobalOptions;
5103 
5104 static inline GlobalOptions *impl_from_IGlobalOptions(IGlobalOptions *iface)
5105 {
5106     return CONTAINING_RECORD(iface, GlobalOptions, IGlobalOptions_iface);
5107 }
5108 
5109 static HRESULT WINAPI GlobalOptions_QueryInterface(IGlobalOptions *iface, REFIID riid, void **ppv)
5110 {
5111     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5112 
5113     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5114 
5115     if (IsEqualGUID(&IID_IGlobalOptions, riid) || IsEqualGUID(&IID_IUnknown, riid))
5116     {
5117         *ppv = iface;
5118     }
5119     else
5120     {
5121         *ppv = NULL;
5122         return E_NOINTERFACE;
5123     }
5124 
5125     IUnknown_AddRef((IUnknown*)*ppv);
5126     return S_OK;
5127 }
5128 
5129 static ULONG WINAPI GlobalOptions_AddRef(IGlobalOptions *iface)
5130 {
5131     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5132     LONG ref = InterlockedIncrement(&This->ref);
5133 
5134     TRACE("(%p) ref=%d\n", This, ref);
5135 
5136     return ref;
5137 }
5138 
5139 static ULONG WINAPI GlobalOptions_Release(IGlobalOptions *iface)
5140 {
5141     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5142     LONG ref = InterlockedDecrement(&This->ref);
5143 
5144     TRACE("(%p) ref=%d\n", This, ref);
5145 
5146     if (!ref)
5147         heap_free(This);
5148 
5149     return ref;
5150 }
5151 
5152 static HRESULT WINAPI GlobalOptions_Set(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR value)
5153 {
5154     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5155     FIXME("(%p)->(%u %lx)\n", This, property, value);
5156     return S_OK;
5157 }
5158 
5159 static HRESULT WINAPI GlobalOptions_Query(IGlobalOptions *iface, GLOBALOPT_PROPERTIES property, ULONG_PTR *value)
5160 {
5161     GlobalOptions *This = impl_from_IGlobalOptions(iface);
5162     FIXME("(%p)->(%u %p)\n", This, property, value);
5163     return E_NOTIMPL;
5164 }
5165 
5166 static const IGlobalOptionsVtbl GlobalOptionsVtbl = {
5167     GlobalOptions_QueryInterface,
5168     GlobalOptions_AddRef,
5169     GlobalOptions_Release,
5170     GlobalOptions_Set,
5171     GlobalOptions_Query
5172 };
5173 
5174 HRESULT WINAPI GlobalOptions_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
5175 {
5176     GlobalOptions *global_options;
5177     HRESULT hres;
5178 
5179     TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
5180 
5181     if (outer)
5182         return E_INVALIDARG;
5183 
5184     global_options = heap_alloc(sizeof(*global_options));
5185     if (!global_options)
5186         return E_OUTOFMEMORY;
5187     global_options->IGlobalOptions_iface.lpVtbl = &GlobalOptionsVtbl;
5188     global_options->ref = 1;
5189 
5190     hres = IGlobalOptions_QueryInterface(&global_options->IGlobalOptions_iface, riid, ppv);
5191     IGlobalOptions_Release(&global_options->IGlobalOptions_iface);
5192     return hres;
5193 }
5194 
5195 /***********************************************************************
5196  *		DllMain (OLE32.@)
5197  */
5198 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved)
5199 {
5200     TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, reserved);
5201 
5202     switch(fdwReason) {
5203     case DLL_PROCESS_ATTACH:
5204         hProxyDll = hinstDLL;
5205 	break;
5206 
5207     case DLL_PROCESS_DETACH:
5208         if (reserved) break;
5209         release_std_git();
5210         UnregisterClassW( wszAptWinClass, hProxyDll );
5211         RPC_UnregisterAllChannelHooks();
5212         COMPOBJ_DllList_Free();
5213         DeleteCriticalSection(&csRegisteredClassList);
5214         DeleteCriticalSection(&csApartment);
5215 	break;
5216 
5217     case DLL_THREAD_DETACH:
5218         COM_TlsDestroy();
5219         break;
5220     }
5221     return TRUE;
5222 }
5223 
5224 /***********************************************************************
5225  *		DllRegisterServer (OLE32.@)
5226  */
5227 HRESULT WINAPI DllRegisterServer(void)
5228 {
5229     return OLE32_DllRegisterServer();
5230 }
5231 
5232 /***********************************************************************
5233  *		DllUnregisterServer (OLE32.@)
5234  */
5235 HRESULT WINAPI DllUnregisterServer(void)
5236 {
5237     return OLE32_DllUnregisterServer();
5238 }
5239