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