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