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