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