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