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