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