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