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