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