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