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