d3d9: Finish the COM cleanup of the IDirect3DDevice9Ex iface.
[wine] / dlls / ole32 / compobj.c
1 /*
2  *      COMPOBJ library
3  *
4  *      Copyright 1995  Martin von Loewis
5  *      Copyright 1998  Justin Bradford
6  *      Copyright 1999  Francis Beaudet
7  *      Copyright 1999  Sylvain St-Germain
8  *      Copyright 2002  Marcus Meissner
9  *      Copyright 2004  Mike Hearn
10  *      Copyright 2005-2006 Robert Shearman (for CodeWeavers)
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  *
26  * Note
27  * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
28  *    Therefore do not test against COINIT_MULTITHREADED
29  *
30  * TODO list:           (items bunched together depend on each other)
31  *
32  *   - Implement the service control manager (in rpcss) to keep track
33  *     of registered class objects: ISCM::ServerRegisterClsid et al
34  *   - Implement the OXID resolver so we don't need magic endpoint names for
35  *     clients and servers to meet up
36  *
37  */
38
39 #include "config.h"
40
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <assert.h>
45
46 #define COBJMACROS
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
49
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "winuser.h"
55 #define USE_COM_CONTEXT_DEF
56 #include "objbase.h"
57 #include "ole2.h"
58 #include "ole2ver.h"
59 #include "ctxtcall.h"
60 #include "dde.h"
61
62 #include "initguid.h"
63 #include "compobj_private.h"
64 #include "moniker.h"
65
66 #include "wine/unicode.h"
67 #include "wine/debug.h"
68
69 WINE_DEFAULT_DEBUG_CHANNEL(ole);
70
71 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
72
73 /****************************************************************************
74  * This section defines variables internal to the COM module.
75  */
76
77 static APARTMENT *MTA; /* protected by csApartment */
78 static APARTMENT *MainApartment; /* the first STA apartment */
79 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
80
81 static CRITICAL_SECTION csApartment;
82 static CRITICAL_SECTION_DEBUG critsect_debug =
83 {
84     0, 0, &csApartment,
85     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
86       0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
87 };
88 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
89
90 struct registered_psclsid
91 {
92     struct list entry;
93     IID iid;
94     CLSID clsid;
95 };
96
97 /*
98  * This lock count counts the number of times CoInitialize is called. It is
99  * decreased every time CoUninitialize is called. When it hits 0, the COM
100  * libraries are freed
101  */
102 static LONG s_COMLockCount = 0;
103 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
104 static LONG s_COMServerProcessReferences = 0;
105
106 /*
107  * This linked list contains the list of registered class objects. These
108  * are mostly used to register the factories for out-of-proc servers of OLE
109  * objects.
110  *
111  * TODO: Make this data structure aware of inter-process communication. This
112  *       means that parts of this will be exported to rpcss.
113  */
114 typedef struct tagRegisteredClass
115 {
116   struct list entry;
117   CLSID     classIdentifier;
118   OXID      apartment_id;
119   LPUNKNOWN classObject;
120   DWORD     runContext;
121   DWORD     connectFlags;
122   DWORD     dwCookie;
123   LPSTREAM  pMarshaledData; /* FIXME: only really need to store OXID and IPID */
124   void     *RpcRegistration;
125 } RegisteredClass;
126
127 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
128
129 static CRITICAL_SECTION csRegisteredClassList;
130 static CRITICAL_SECTION_DEBUG class_cs_debug =
131 {
132     0, 0, &csRegisteredClassList,
133     { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
134       0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
135 };
136 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
137
138 /*****************************************************************************
139  * This section contains OpenDllList definitions
140  *
141  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
142  * other functions that do LoadLibrary _without_ giving back a HMODULE.
143  * Without this list these handles would never be freed.
144  *
145  * FIXME: a DLL that says OK when asked for unloading is unloaded in the
146  * next unload-call but not before 600 sec.
147  */
148
149 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
150 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
151
152 typedef struct tagOpenDll
153 {
154   LONG refs;
155   LPWSTR library_name;
156   HANDLE library;
157   DllGetClassObjectFunc DllGetClassObject;
158   DllCanUnloadNowFunc DllCanUnloadNow;
159   struct list entry;
160 } OpenDll;
161
162 static struct list openDllList = LIST_INIT(openDllList);
163
164 static CRITICAL_SECTION csOpenDllList;
165 static CRITICAL_SECTION_DEBUG dll_cs_debug =
166 {
167     0, 0, &csOpenDllList,
168     { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
169       0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
170 };
171 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
172
173 struct apartment_loaded_dll
174 {
175     struct list entry;
176     OpenDll *dll;
177     DWORD unload_time;
178     BOOL multi_threaded;
179 };
180
181 static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
182                                        '0','x','#','#','#','#','#','#','#','#',' ',0};
183
184 /*****************************************************************************
185  * This section contains OpenDllList implementation
186  */
187
188 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
189 {
190     OpenDll *ptr;
191     OpenDll *ret = NULL;
192     EnterCriticalSection(&csOpenDllList);
193     LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
194     {
195         if (!strcmpiW(library_name, ptr->library_name) &&
196             (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
197         {
198             ret = ptr;
199             break;
200         }
201     }
202     LeaveCriticalSection(&csOpenDllList);
203     return ret;
204 }
205
206 /* caller must ensure that library_name is not already in the open dll list */
207 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
208 {
209     OpenDll *entry;
210     int len;
211     HRESULT hr = S_OK;
212     HANDLE hLibrary;
213     DllCanUnloadNowFunc DllCanUnloadNow;
214     DllGetClassObjectFunc DllGetClassObject;
215
216     TRACE("\n");
217
218     *ret = COMPOBJ_DllList_Get(library_name);
219     if (*ret) return S_OK;
220
221     /* do this outside the csOpenDllList to avoid creating a lock dependency on
222      * the loader lock */
223     hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
224     if (!hLibrary)
225     {
226         ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
227         /* failure: DLL could not be loaded */
228         return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
229     }
230
231     DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
232     /* Note: failing to find DllCanUnloadNow is not a failure */
233     DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
234     if (!DllGetClassObject)
235     {
236         /* failure: the dll did not export DllGetClassObject */
237         ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
238         FreeLibrary(hLibrary);
239         return CO_E_DLLNOTFOUND;
240     }
241
242     EnterCriticalSection( &csOpenDllList );
243
244     *ret = COMPOBJ_DllList_Get(library_name);
245     if (*ret)
246     {
247         /* another caller to this function already added the dll while we
248          * weren't in the critical section */
249         FreeLibrary(hLibrary);
250     }
251     else
252     {
253         len = strlenW(library_name);
254         entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
255         if (entry)
256             entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
257         if (entry && entry->library_name)
258         {
259             memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
260             entry->library = hLibrary;
261             entry->refs = 1;
262             entry->DllCanUnloadNow = DllCanUnloadNow;
263             entry->DllGetClassObject = DllGetClassObject;
264             list_add_tail(&openDllList, &entry->entry);
265         }
266         else
267         {
268             HeapFree(GetProcessHeap(), 0, entry);
269             hr = E_OUTOFMEMORY;
270             FreeLibrary(hLibrary);
271         }
272         *ret = entry;
273     }
274
275     LeaveCriticalSection( &csOpenDllList );
276
277     return hr;
278 }
279
280 /* pass FALSE for free_entry to release a reference without destroying the
281  * entry if it reaches zero or TRUE otherwise */
282 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
283 {
284     if (!InterlockedDecrement(&entry->refs) && free_entry)
285     {
286         EnterCriticalSection(&csOpenDllList);
287         list_remove(&entry->entry);
288         LeaveCriticalSection(&csOpenDllList);
289
290         TRACE("freeing %p\n", entry->library);
291         FreeLibrary(entry->library);
292
293         HeapFree(GetProcessHeap(), 0, entry->library_name);
294         HeapFree(GetProcessHeap(), 0, entry);
295     }
296 }
297
298 /* frees memory associated with active dll list */
299 static void COMPOBJ_DllList_Free(void)
300 {
301     OpenDll *entry, *cursor2;
302     EnterCriticalSection(&csOpenDllList);
303     LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
304     {
305         list_remove(&entry->entry);
306
307         HeapFree(GetProcessHeap(), 0, entry->library_name);
308         HeapFree(GetProcessHeap(), 0, entry);
309     }
310     LeaveCriticalSection(&csOpenDllList);
311 }
312
313 /******************************************************************************
314  * Manage apartments.
315  */
316
317 static DWORD apartment_addref(struct apartment *apt)
318 {
319     DWORD refs = InterlockedIncrement(&apt->refs);
320     TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
321     return refs;
322 }
323
324 /* allocates memory and fills in the necessary fields for a new apartment
325  * object. must be called inside apartment cs */
326 static APARTMENT *apartment_construct(DWORD model)
327 {
328     APARTMENT *apt;
329
330     TRACE("creating new apartment, model=%d\n", model);
331
332     apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
333     apt->tid = GetCurrentThreadId();
334
335     list_init(&apt->proxies);
336     list_init(&apt->stubmgrs);
337     list_init(&apt->psclsids);
338     list_init(&apt->loaded_dlls);
339     apt->ipidc = 0;
340     apt->refs = 1;
341     apt->remunk_exported = FALSE;
342     apt->oidc = 1;
343     InitializeCriticalSection(&apt->cs);
344     DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
345
346     apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
347
348     if (apt->multi_threaded)
349     {
350         /* FIXME: should be randomly generated by in an RPC call to rpcss */
351         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
352     }
353     else
354     {
355         /* FIXME: should be randomly generated by in an RPC call to rpcss */
356         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
357     }
358
359     TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
360
361     list_add_head(&apts, &apt->entry);
362
363     return apt;
364 }
365
366 /* gets and existing apartment if one exists or otherwise creates an apartment
367  * structure which stores OLE apartment-local information and stores a pointer
368  * to it in the thread-local storage */
369 static APARTMENT *apartment_get_or_create(DWORD model)
370 {
371     APARTMENT *apt = COM_CurrentApt();
372
373     if (!apt)
374     {
375         if (model & COINIT_APARTMENTTHREADED)
376         {
377             EnterCriticalSection(&csApartment);
378
379             apt = apartment_construct(model);
380             if (!MainApartment)
381             {
382                 MainApartment = apt;
383                 apt->main = TRUE;
384                 TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
385             }
386
387             LeaveCriticalSection(&csApartment);
388
389             if (apt->main)
390                 apartment_createwindowifneeded(apt);
391         }
392         else
393         {
394             EnterCriticalSection(&csApartment);
395
396             /* The multi-threaded apartment (MTA) contains zero or more threads interacting
397              * with free threaded (ie thread safe) COM objects. There is only ever one MTA
398              * in a process */
399             if (MTA)
400             {
401                 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
402                 apartment_addref(MTA);
403             }
404             else
405                 MTA = apartment_construct(model);
406
407             apt = MTA;
408
409             LeaveCriticalSection(&csApartment);
410         }
411         COM_CurrentInfo()->apt = apt;
412     }
413
414     return apt;
415 }
416
417 static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
418 {
419     return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
420 }
421
422 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
423 {
424     list_remove(&curClass->entry);
425
426     if (curClass->runContext & CLSCTX_LOCAL_SERVER)
427         RPC_StopLocalServer(curClass->RpcRegistration);
428
429     /*
430      * Release the reference to the class object.
431      */
432     IUnknown_Release(curClass->classObject);
433
434     if (curClass->pMarshaledData)
435     {
436         LARGE_INTEGER zero;
437         memset(&zero, 0, sizeof(zero));
438         IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
439         CoReleaseMarshalData(curClass->pMarshaledData);
440         IStream_Release(curClass->pMarshaledData);
441     }
442
443     HeapFree(GetProcessHeap(), 0, curClass);
444 }
445
446 static void COM_RevokeAllClasses(const struct apartment *apt)
447 {
448   RegisteredClass *curClass, *cursor;
449
450   EnterCriticalSection( &csRegisteredClassList );
451
452   LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
453   {
454     if (curClass->apartment_id == apt->oxid)
455       COM_RevokeRegisteredClassObject(curClass);
456   }
457
458   LeaveCriticalSection( &csRegisteredClassList );
459 }
460
461 /***********************************************************************
462  *           CoRevokeClassObject [OLE32.@]
463  *
464  * Removes a class object from the class registry.
465  *
466  * PARAMS
467  *  dwRegister [I] Cookie returned from CoRegisterClassObject().
468  *
469  * RETURNS
470  *  Success: S_OK.
471  *  Failure: HRESULT code.
472  *
473  * NOTES
474  *  Must be called from the same apartment that called CoRegisterClassObject(),
475  *  otherwise it will fail with RPC_E_WRONG_THREAD.
476  *
477  * SEE ALSO
478  *  CoRegisterClassObject
479  */
480 HRESULT WINAPI CoRevokeClassObject(
481         DWORD dwRegister)
482 {
483   HRESULT hr = E_INVALIDARG;
484   RegisteredClass *curClass;
485   APARTMENT *apt;
486
487   TRACE("(%08x)\n",dwRegister);
488
489   apt = COM_CurrentApt();
490   if (!apt)
491   {
492     ERR("COM was not initialized\n");
493     return CO_E_NOTINITIALIZED;
494   }
495
496   EnterCriticalSection( &csRegisteredClassList );
497
498   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
499   {
500     /*
501      * Check if we have a match on the cookie.
502      */
503     if (curClass->dwCookie == dwRegister)
504     {
505       if (curClass->apartment_id == apt->oxid)
506       {
507           COM_RevokeRegisteredClassObject(curClass);
508           hr = S_OK;
509       }
510       else
511       {
512           ERR("called from wrong apartment, should be called from %s\n",
513               wine_dbgstr_longlong(curClass->apartment_id));
514           hr = RPC_E_WRONG_THREAD;
515       }
516       break;
517     }
518   }
519
520   LeaveCriticalSection( &csRegisteredClassList );
521
522   return hr;
523 }
524
525 /* frees unused libraries loaded by apartment_getclassobject by calling the
526  * DLL's DllCanUnloadNow entry point */
527 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
528 {
529     struct apartment_loaded_dll *entry, *next;
530     EnterCriticalSection(&apt->cs);
531     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
532     {
533         if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
534         {
535             DWORD real_delay = delay;
536
537             if (real_delay == INFINITE)
538             {
539                 /* DLLs that return multi-threaded objects aren't unloaded
540                  * straight away to cope for programs that have races between
541                  * last object destruction and threads in the DLLs that haven't
542                  * finished, despite DllCanUnloadNow returning S_OK */
543                 if (entry->multi_threaded)
544                     real_delay = 10 * 60 * 1000; /* 10 minutes */
545                 else
546                     real_delay = 0;
547             }
548
549             if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
550             {
551                 list_remove(&entry->entry);
552                 COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
553                 HeapFree(GetProcessHeap(), 0, entry);
554             }
555             else
556                 entry->unload_time = GetTickCount() + real_delay;
557         }
558         else if (entry->unload_time)
559             entry->unload_time = 0;
560     }
561     LeaveCriticalSection(&apt->cs);
562 }
563
564 DWORD apartment_release(struct apartment *apt)
565 {
566     DWORD ret;
567
568     EnterCriticalSection(&csApartment);
569
570     ret = InterlockedDecrement(&apt->refs);
571     TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
572     /* destruction stuff that needs to happen under csApartment CS */
573     if (ret == 0)
574     {
575         if (apt == MTA) MTA = NULL;
576         else if (apt == MainApartment) MainApartment = NULL;
577         list_remove(&apt->entry);
578     }
579
580     LeaveCriticalSection(&csApartment);
581
582     if (ret == 0)
583     {
584         struct list *cursor, *cursor2;
585
586         TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
587
588         /* Release the references to the registered class objects */
589         COM_RevokeAllClasses(apt);
590
591         /* no locking is needed for this apartment, because no other thread
592          * can access it at this point */
593
594         apartment_disconnectproxies(apt);
595
596         if (apt->win) DestroyWindow(apt->win);
597         if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
598
599         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
600         {
601             struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
602             /* release the implicit reference given by the fact that the
603              * stub has external references (it must do since it is in the
604              * stub manager list in the apartment and all non-apartment users
605              * must have a ref on the apartment and so it cannot be destroyed).
606              */
607             stub_manager_int_release(stubmgr);
608         }
609
610         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
611         {
612             struct registered_psclsid *registered_psclsid =
613                 LIST_ENTRY(cursor, struct registered_psclsid, entry);
614
615             list_remove(&registered_psclsid->entry);
616             HeapFree(GetProcessHeap(), 0, registered_psclsid);
617         }
618
619         /* if this assert fires, then another thread took a reference to a
620          * stub manager without taking a reference to the containing
621          * apartment, which it must do. */
622         assert(list_empty(&apt->stubmgrs));
623
624         if (apt->filter) IUnknown_Release(apt->filter);
625
626         /* free as many unused libraries as possible... */
627         apartment_freeunusedlibraries(apt, 0);
628
629         /* ... and free the memory for the apartment loaded dll entry and
630          * release the dll list reference without freeing the library for the
631          * rest */
632         while ((cursor = list_head(&apt->loaded_dlls)))
633         {
634             struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
635             COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
636             list_remove(cursor);
637             HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
638         }
639
640         DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
641         DeleteCriticalSection(&apt->cs);
642
643         HeapFree(GetProcessHeap(), 0, apt);
644     }
645
646     return ret;
647 }
648
649 /* The given OXID must be local to this process: 
650  *
651  * The ref parameter is here mostly to ensure people remember that
652  * they get one, you should normally take a ref for thread safety.
653  */
654 APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
655 {
656     APARTMENT *result = NULL;
657     struct list *cursor;
658
659     EnterCriticalSection(&csApartment);
660     LIST_FOR_EACH( cursor, &apts )
661     {
662         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
663         if (apt->oxid == oxid)
664         {
665             result = apt;
666             if (ref) apartment_addref(result);
667             break;
668         }
669     }
670     LeaveCriticalSection(&csApartment);
671
672     return result;
673 }
674
675 /* gets the apartment which has a given creator thread ID. The caller must
676  * release the reference from the apartment as soon as the apartment pointer
677  * is no longer required. */
678 APARTMENT *apartment_findfromtid(DWORD tid)
679 {
680     APARTMENT *result = NULL;
681     struct list *cursor;
682
683     EnterCriticalSection(&csApartment);
684     LIST_FOR_EACH( cursor, &apts )
685     {
686         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
687         if (apt->tid == tid)
688         {
689             result = apt;
690             apartment_addref(result);
691             break;
692         }
693     }
694     LeaveCriticalSection(&csApartment);
695
696     return result;
697 }
698
699 /* gets the main apartment if it exists. The caller must
700  * release the reference from the apartment as soon as the apartment pointer
701  * is no longer required. */
702 static APARTMENT *apartment_findmain(void)
703 {
704     APARTMENT *result;
705
706     EnterCriticalSection(&csApartment);
707
708     result = MainApartment;
709     if (result) apartment_addref(result);
710
711     LeaveCriticalSection(&csApartment);
712
713     return result;
714 }
715
716 /* gets the multi-threaded apartment if it exists. The caller must
717  * release the reference from the apartment as soon as the apartment pointer
718  * is no longer required. */
719 static APARTMENT *apartment_find_multi_threaded(void)
720 {
721     APARTMENT *result = NULL;
722     struct list *cursor;
723
724     EnterCriticalSection(&csApartment);
725
726     LIST_FOR_EACH( cursor, &apts )
727     {
728         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
729         if (apt->multi_threaded)
730         {
731             result = apt;
732             apartment_addref(result);
733             break;
734         }
735     }
736
737     LeaveCriticalSection(&csApartment);
738     return result;
739 }
740
741 /* gets the specified class object by loading the appropriate DLL, if
742  * necessary and calls the DllGetClassObject function for the DLL */
743 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
744                                         BOOL apartment_threaded,
745                                         REFCLSID rclsid, REFIID riid, void **ppv)
746 {
747     static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
748     HRESULT hr = S_OK;
749     BOOL found = FALSE;
750     struct apartment_loaded_dll *apartment_loaded_dll;
751
752     if (!strcmpiW(dllpath, wszOle32))
753     {
754         /* we don't need to control the lifetime of this dll, so use the local
755          * implementation of DllGetClassObject directly */
756         TRACE("calling ole32!DllGetClassObject\n");
757         hr = DllGetClassObject(rclsid, riid, ppv);
758
759         if (hr != S_OK)
760             ERR("DllGetClassObject returned error 0x%08x\n", hr);
761
762         return hr;
763     }
764
765     EnterCriticalSection(&apt->cs);
766
767     LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
768         if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
769         {
770             TRACE("found %s already loaded\n", debugstr_w(dllpath));
771             found = TRUE;
772             break;
773         }
774
775     if (!found)
776     {
777         apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
778         if (!apartment_loaded_dll)
779             hr = E_OUTOFMEMORY;
780         if (SUCCEEDED(hr))
781         {
782             apartment_loaded_dll->unload_time = 0;
783             apartment_loaded_dll->multi_threaded = FALSE;
784             hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
785             if (FAILED(hr))
786                 HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
787         }
788         if (SUCCEEDED(hr))
789         {
790             TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
791             list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
792         }
793     }
794
795     LeaveCriticalSection(&apt->cs);
796
797     if (SUCCEEDED(hr))
798     {
799         /* one component being multi-threaded overrides any number of
800          * apartment-threaded components */
801         if (!apartment_threaded)
802             apartment_loaded_dll->multi_threaded = TRUE;
803
804         TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
805         /* OK: get the ClassObject */
806         hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
807
808         if (hr != S_OK)
809             ERR("DllGetClassObject returned error 0x%08x\n", hr);
810     }
811
812     return hr;
813 }
814
815 /***********************************************************************
816  *      COM_RegReadPath [internal]
817  *
818  *      Reads a registry value and expands it when necessary
819  */
820 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
821 {
822         DWORD ret;
823         HKEY key;
824         DWORD keytype;
825         WCHAR src[MAX_PATH];
826         DWORD dwLength = dstlen * sizeof(WCHAR);
827
828         if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
829           if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
830             if (keytype == REG_EXPAND_SZ) {
831               if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
832             } else {
833               const WCHAR *quote_start;
834               quote_start = strchrW(src, '\"');
835               if (quote_start) {
836                 const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
837                 if (quote_end) {
838                   memmove(src, quote_start + 1,
839                           (quote_end - quote_start - 1) * sizeof(WCHAR));
840                   src[quote_end - quote_start - 1] = '\0';
841                 }
842               }
843               lstrcpynW(dst, src, dstlen);
844             }
845           }
846           RegCloseKey (key);
847         }
848         return ret;
849 }
850
851 struct host_object_params
852 {
853     HKEY hkeydll;
854     CLSID clsid; /* clsid of object to marshal */
855     IID iid; /* interface to marshal */
856     HANDLE event; /* event signalling when ready for multi-threaded case */
857     HRESULT hr; /* result for multi-threaded case */
858     IStream *stream; /* stream that the object will be marshaled into */
859     BOOL apartment_threaded; /* is the component purely apartment-threaded? */
860 };
861
862 static HRESULT apartment_hostobject(struct apartment *apt,
863                                     const struct host_object_params *params)
864 {
865     IUnknown *object;
866     HRESULT hr;
867     static const LARGE_INTEGER llZero;
868     WCHAR dllpath[MAX_PATH+1];
869
870     TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
871
872     if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
873     {
874         /* failure: CLSID is not found in registry */
875         WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
876         return REGDB_E_CLASSNOTREG;
877     }
878
879     hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
880                                   &params->clsid, &params->iid, (void **)&object);
881     if (FAILED(hr))
882         return hr;
883
884     hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
885     if (FAILED(hr))
886         IUnknown_Release(object);
887     IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
888
889     return hr;
890 }
891
892 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
893 {
894     switch (msg)
895     {
896     case DM_EXECUTERPC:
897         RPC_ExecuteCall((struct dispatch_params *)lParam);
898         return 0;
899     case DM_HOSTOBJECT:
900         return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
901     default:
902         return DefWindowProcW(hWnd, msg, wParam, lParam);
903     }
904 }
905
906 struct host_thread_params
907 {
908     COINIT threading_model;
909     HANDLE ready_event;
910     HWND apartment_hwnd;
911 };
912
913 /* thread for hosting an object to allow an object to appear to be created in
914  * an apartment with an incompatible threading model */
915 static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
916 {
917     struct host_thread_params *params = p;
918     MSG msg;
919     HRESULT hr;
920     struct apartment *apt;
921
922     TRACE("\n");
923
924     hr = CoInitializeEx(NULL, params->threading_model);
925     if (FAILED(hr)) return hr;
926
927     apt = COM_CurrentApt();
928     if (params->threading_model == COINIT_APARTMENTTHREADED)
929     {
930         apartment_createwindowifneeded(apt);
931         params->apartment_hwnd = apartment_getwindow(apt);
932     }
933     else
934         params->apartment_hwnd = NULL;
935
936     /* force the message queue to be created before signaling parent thread */
937     PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
938
939     SetEvent(params->ready_event);
940     params = NULL; /* can't touch params after here as it may be invalid */
941
942     while (GetMessageW(&msg, NULL, 0, 0))
943     {
944         if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
945         {
946             struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
947             obj_params->hr = apartment_hostobject(apt, obj_params);
948             SetEvent(obj_params->event);
949         }
950         else
951         {
952             TranslateMessage(&msg);
953             DispatchMessageW(&msg);
954         }
955     }
956
957     TRACE("exiting\n");
958
959     CoUninitialize();
960
961     return S_OK;
962 }
963
964 /* finds or creates a host apartment, creates the object inside it and returns
965  * a proxy to it so that the object can be used in the apartment of the
966  * caller of this function */
967 static HRESULT apartment_hostobject_in_hostapt(
968     struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
969     HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
970 {
971     struct host_object_params params;
972     HWND apartment_hwnd = NULL;
973     DWORD apartment_tid = 0;
974     HRESULT hr;
975
976     if (!multi_threaded && main_apartment)
977     {
978         APARTMENT *host_apt = apartment_findmain();
979         if (host_apt)
980         {
981             apartment_hwnd = apartment_getwindow(host_apt);
982             apartment_release(host_apt);
983         }
984     }
985
986     if (!apartment_hwnd)
987     {
988         EnterCriticalSection(&apt->cs);
989
990         if (!apt->host_apt_tid)
991         {
992             struct host_thread_params thread_params;
993             HANDLE handles[2];
994             DWORD wait_value;
995
996             thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
997             handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
998             thread_params.apartment_hwnd = NULL;
999             handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
1000             if (!handles[1])
1001             {
1002                 CloseHandle(handles[0]);
1003                 LeaveCriticalSection(&apt->cs);
1004                 return E_OUTOFMEMORY;
1005             }
1006             wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1007             CloseHandle(handles[0]);
1008             CloseHandle(handles[1]);
1009             if (wait_value == WAIT_OBJECT_0)
1010                 apt->host_apt_hwnd = thread_params.apartment_hwnd;
1011             else
1012             {
1013                 LeaveCriticalSection(&apt->cs);
1014                 return E_OUTOFMEMORY;
1015             }
1016         }
1017
1018         if (multi_threaded || !main_apartment)
1019         {
1020             apartment_hwnd = apt->host_apt_hwnd;
1021             apartment_tid = apt->host_apt_tid;
1022         }
1023
1024         LeaveCriticalSection(&apt->cs);
1025     }
1026
1027     /* another thread may have become the main apartment in the time it took
1028      * us to create the thread for the host apartment */
1029     if (!apartment_hwnd && !multi_threaded && main_apartment)
1030     {
1031         APARTMENT *host_apt = apartment_findmain();
1032         if (host_apt)
1033         {
1034             apartment_hwnd = apartment_getwindow(host_apt);
1035             apartment_release(host_apt);
1036         }
1037     }
1038
1039     params.hkeydll = hkeydll;
1040     params.clsid = *rclsid;
1041     params.iid = *riid;
1042     hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
1043     if (FAILED(hr))
1044         return hr;
1045     params.apartment_threaded = !multi_threaded;
1046     if (multi_threaded)
1047     {
1048         params.hr = S_OK;
1049         params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
1050         if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
1051             hr = E_OUTOFMEMORY;
1052         else
1053         {
1054             WaitForSingleObject(params.event, INFINITE);
1055             hr = params.hr;
1056         }
1057         CloseHandle(params.event);
1058     }
1059     else
1060     {
1061         if (!apartment_hwnd)
1062         {
1063             ERR("host apartment didn't create window\n");
1064             hr = E_OUTOFMEMORY;
1065         }
1066         else
1067             hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1068     }
1069     if (SUCCEEDED(hr))
1070         hr = CoUnmarshalInterface(params.stream, riid, ppv);
1071     IStream_Release(params.stream);
1072     return hr;
1073 }
1074
1075 /* create a window for the apartment or return the current one if one has
1076  * already been created */
1077 HRESULT apartment_createwindowifneeded(struct apartment *apt)
1078 {
1079     if (apt->multi_threaded)
1080         return S_OK;
1081
1082     if (!apt->win)
1083     {
1084         HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
1085                                   0, 0, 0, 0,
1086                                   HWND_MESSAGE, 0, hProxyDll, NULL);
1087         if (!hwnd)
1088         {
1089             ERR("CreateWindow failed with error %d\n", GetLastError());
1090             return HRESULT_FROM_WIN32(GetLastError());
1091         }
1092         if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
1093             /* someone beat us to it */
1094             DestroyWindow(hwnd);
1095     }
1096
1097     return S_OK;
1098 }
1099
1100 /* retrieves the window for the main- or apartment-threaded apartment */
1101 HWND apartment_getwindow(const struct apartment *apt)
1102 {
1103     assert(!apt->multi_threaded);
1104     return apt->win;
1105 }
1106
1107 void apartment_joinmta(void)
1108 {
1109     apartment_addref(MTA);
1110     COM_CurrentInfo()->apt = MTA;
1111 }
1112
1113 static void COMPOBJ_InitProcess( void )
1114 {
1115     WNDCLASSW wclass;
1116
1117     /* Dispatching to the correct thread in an apartment is done through
1118      * window messages rather than RPC transports. When an interface is
1119      * marshalled into another apartment in the same process, a window of the
1120      * following class is created. The *caller* of CoMarshalInterface (i.e., the
1121      * application) is responsible for pumping the message loop in that thread.
1122      * The WM_USER messages which point to the RPCs are then dispatched to
1123      * apartment_wndproc by the user's code from the apartment in which the
1124      * interface was unmarshalled.
1125      */
1126     memset(&wclass, 0, sizeof(wclass));
1127     wclass.lpfnWndProc = apartment_wndproc;
1128     wclass.hInstance = hProxyDll;
1129     wclass.lpszClassName = wszAptWinClass;
1130     RegisterClassW(&wclass);
1131 }
1132
1133 static void COMPOBJ_UninitProcess( void )
1134 {
1135     UnregisterClassW(wszAptWinClass, hProxyDll);
1136 }
1137
1138 static void COM_TlsDestroy(void)
1139 {
1140     struct oletls *info = NtCurrentTeb()->ReservedForOle;
1141     if (info)
1142     {
1143         if (info->apt) apartment_release(info->apt);
1144         if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
1145         if (info->state) IUnknown_Release(info->state);
1146         if (info->spy) IUnknown_Release(info->spy);
1147         if (info->context_token) IObjContext_Release(info->context_token);
1148         HeapFree(GetProcessHeap(), 0, info);
1149         NtCurrentTeb()->ReservedForOle = NULL;
1150     }
1151 }
1152
1153 /******************************************************************************
1154  *           CoBuildVersion [OLE32.@]
1155  *
1156  * Gets the build version of the DLL.
1157  *
1158  * PARAMS
1159  *
1160  * RETURNS
1161  *      Current build version, hiword is majornumber, loword is minornumber
1162  */
1163 DWORD WINAPI CoBuildVersion(void)
1164 {
1165     TRACE("Returning version %d, build %d.\n", rmm, rup);
1166     return (rmm<<16)+rup;
1167 }
1168
1169 /******************************************************************************
1170  *              CoRegisterInitializeSpy [OLE32.@]
1171  *
1172  * Add a Spy that watches CoInitializeEx calls
1173  *
1174  * PARAMS
1175  *  spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
1176  *  cookie [II] cookie receiver
1177  *
1178  * RETURNS
1179  *  Success: S_OK if not already initialized, S_FALSE otherwise.
1180  *  Failure: HRESULT code.
1181  *
1182  * SEE ALSO
1183  *   CoInitializeEx
1184  */
1185 HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
1186 {
1187     struct oletls *info = COM_CurrentInfo();
1188     HRESULT hr;
1189
1190     TRACE("(%p, %p)\n", spy, cookie);
1191
1192     if (!spy || !cookie || !info)
1193     {
1194         if (!info)
1195             WARN("Could not allocate tls\n");
1196         return E_INVALIDARG;
1197     }
1198
1199     if (info->spy)
1200     {
1201         FIXME("Already registered?\n");
1202         return E_UNEXPECTED;
1203     }
1204
1205     hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
1206     if (SUCCEEDED(hr))
1207     {
1208         cookie->QuadPart = (DWORD_PTR)spy;
1209         return S_OK;
1210     }
1211     return hr;
1212 }
1213
1214 /******************************************************************************
1215  *              CoRevokeInitializeSpy [OLE32.@]
1216  *
1217  * Remove a spy that previously watched CoInitializeEx calls
1218  *
1219  * PARAMS
1220  *  cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
1221  *
1222  * RETURNS
1223  *  Success: S_OK if a spy is removed
1224  *  Failure: E_INVALIDARG
1225  *
1226  * SEE ALSO
1227  *   CoInitializeEx
1228  */
1229 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1230 {
1231     struct oletls *info = COM_CurrentInfo();
1232     TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1233
1234     if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1235         return E_INVALIDARG;
1236
1237     IUnknown_Release(info->spy);
1238     info->spy = NULL;
1239     return S_OK;
1240 }
1241
1242
1243 /******************************************************************************
1244  *              CoInitialize    [OLE32.@]
1245  *
1246  * Initializes the COM libraries by calling CoInitializeEx with
1247  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1248  *
1249  * PARAMS
1250  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1251  *
1252  * RETURNS
1253  *  Success: S_OK if not already initialized, S_FALSE otherwise.
1254  *  Failure: HRESULT code.
1255  *
1256  * SEE ALSO
1257  *   CoInitializeEx
1258  */
1259 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1260 {
1261   /*
1262    * Just delegate to the newer method.
1263    */
1264   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1265 }
1266
1267 /******************************************************************************
1268  *              CoInitializeEx  [OLE32.@]
1269  *
1270  * Initializes the COM libraries.
1271  *
1272  * PARAMS
1273  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1274  *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
1275  *
1276  * RETURNS
1277  *  S_OK               if successful,
1278  *  S_FALSE            if this function was called already.
1279  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1280  *                     threading model.
1281  *
1282  * NOTES
1283  *
1284  * The behavior used to set the IMalloc used for memory management is
1285  * obsolete.
1286  * The dwCoInit parameter must specify one of the following apartment
1287  * threading models:
1288  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1289  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1290  * The parameter may also specify zero or more of the following flags:
1291  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1292  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1293  *
1294  * SEE ALSO
1295  *   CoUninitialize
1296  */
1297 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1298 {
1299   struct oletls *info = COM_CurrentInfo();
1300   HRESULT hr = S_OK;
1301   APARTMENT *apt;
1302
1303   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1304
1305   if (lpReserved!=NULL)
1306   {
1307     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1308   }
1309
1310   /*
1311    * Check the lock count. If this is the first time going through the initialize
1312    * process, we have to initialize the libraries.
1313    *
1314    * And crank-up that lock count.
1315    */
1316   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1317   {
1318     /*
1319      * Initialize the various COM libraries and data structures.
1320      */
1321     TRACE("() - Initializing the COM libraries\n");
1322
1323     /* we may need to defer this until after apartment initialisation */
1324     RunningObjectTableImpl_Initialize();
1325   }
1326
1327   if (info->spy)
1328       IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1329
1330   if (!(apt = info->apt))
1331   {
1332     apt = apartment_get_or_create(dwCoInit);
1333     if (!apt) return E_OUTOFMEMORY;
1334   }
1335   else if (!apartment_is_model(apt, dwCoInit))
1336   {
1337     /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1338        code then we are probably using the wrong threading model to implement that API. */
1339     ERR("Attempt to change threading model of this apartment from %s to %s\n",
1340         apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1341         dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1342     return RPC_E_CHANGED_MODE;
1343   }
1344   else
1345     hr = S_FALSE;
1346
1347   info->inits++;
1348
1349   if (info->spy)
1350       IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1351
1352   return hr;
1353 }
1354
1355 /***********************************************************************
1356  *           CoUninitialize   [OLE32.@]
1357  *
1358  * This method will decrement the refcount on the current apartment, freeing
1359  * the resources associated with it if it is the last thread in the apartment.
1360  * If the last apartment is freed, the function will additionally release
1361  * any COM resources associated with the process.
1362  *
1363  * PARAMS
1364  *
1365  * RETURNS
1366  *  Nothing.
1367  *
1368  * SEE ALSO
1369  *   CoInitializeEx
1370  */
1371 void WINAPI CoUninitialize(void)
1372 {
1373   struct oletls * info = COM_CurrentInfo();
1374   LONG lCOMRefCnt;
1375
1376   TRACE("()\n");
1377
1378   /* will only happen on OOM */
1379   if (!info) return;
1380
1381   if (info->spy)
1382       IInitializeSpy_PreUninitialize(info->spy, info->inits);
1383
1384   /* sanity check */
1385   if (!info->inits)
1386   {
1387     ERR("Mismatched CoUninitialize\n");
1388
1389     if (info->spy)
1390         IInitializeSpy_PostUninitialize(info->spy, info->inits);
1391     return;
1392   }
1393
1394   if (!--info->inits)
1395   {
1396     apartment_release(info->apt);
1397     info->apt = NULL;
1398   }
1399
1400   /*
1401    * Decrease the reference count.
1402    * If we are back to 0 locks on the COM library, make sure we free
1403    * all the associated data structures.
1404    */
1405   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1406   if (lCOMRefCnt==1)
1407   {
1408     TRACE("() - Releasing the COM libraries\n");
1409
1410     RunningObjectTableImpl_UnInitialize();
1411   }
1412   else if (lCOMRefCnt<1) {
1413     ERR( "CoUninitialize() - not CoInitialized.\n" );
1414     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1415   }
1416   if (info->spy)
1417       IInitializeSpy_PostUninitialize(info->spy, info->inits);
1418 }
1419
1420 /******************************************************************************
1421  *              CoDisconnectObject      [OLE32.@]
1422  *
1423  * Disconnects all connections to this object from remote processes. Dispatches
1424  * pending RPCs while blocking new RPCs from occurring, and then calls
1425  * IMarshal::DisconnectObject on the given object.
1426  *
1427  * Typically called when the object server is forced to shut down, for instance by
1428  * the user.
1429  *
1430  * PARAMS
1431  *  lpUnk    [I] The object whose stub should be disconnected.
1432  *  reserved [I] Reserved. Should be set to 0.
1433  *
1434  * RETURNS
1435  *  Success: S_OK.
1436  *  Failure: HRESULT code.
1437  *
1438  * SEE ALSO
1439  *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1440  */
1441 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1442 {
1443     HRESULT hr;
1444     IMarshal *marshal;
1445     APARTMENT *apt;
1446
1447     TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1448
1449     hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1450     if (hr == S_OK)
1451     {
1452         hr = IMarshal_DisconnectObject(marshal, reserved);
1453         IMarshal_Release(marshal);
1454         return hr;
1455     }
1456
1457     apt = COM_CurrentApt();
1458     if (!apt)
1459         return CO_E_NOTINITIALIZED;
1460
1461     apartment_disconnectobject(apt, lpUnk);
1462
1463     /* Note: native is pretty broken here because it just silently
1464      * fails, without returning an appropriate error code if the object was
1465      * not found, making apps think that the object was disconnected, when
1466      * it actually wasn't */
1467
1468     return S_OK;
1469 }
1470
1471 /******************************************************************************
1472  *              CoCreateGuid [OLE32.@]
1473  *
1474  * Simply forwards to UuidCreate in RPCRT4.
1475  *
1476  * PARAMS
1477  *  pguid [O] Points to the GUID to initialize.
1478  *
1479  * RETURNS
1480  *  Success: S_OK.
1481  *  Failure: HRESULT code.
1482  *
1483  * SEE ALSO
1484  *   UuidCreate
1485  */
1486 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1487 {
1488     DWORD status = UuidCreate(pguid);
1489     if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1490     return HRESULT_FROM_WIN32( status );
1491 }
1492
1493 /******************************************************************************
1494  *              CLSIDFromString [OLE32.@]
1495  *              IIDFromString   [OLE32.@]
1496  *
1497  * Converts a unique identifier from its string representation into
1498  * the GUID struct.
1499  *
1500  * PARAMS
1501  *  idstr [I] The string representation of the GUID.
1502  *  id    [O] GUID converted from the string.
1503  *
1504  * RETURNS
1505  *   S_OK on success
1506  *   CO_E_CLASSSTRING if idstr is not a valid CLSID
1507  *
1508  * SEE ALSO
1509  *  StringFromCLSID
1510  */
1511 static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1512 {
1513   int   i;
1514   BYTE table[256];
1515
1516   if (!s) {
1517     memset( id, 0, sizeof (CLSID) );
1518     return S_OK;
1519   }
1520
1521   /* validate the CLSID string */
1522   if (strlenW(s) != 38)
1523     return CO_E_CLASSSTRING;
1524
1525   if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1526     return CO_E_CLASSSTRING;
1527
1528   for (i=1; i<37; i++) {
1529     if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1530     if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
1531           ((s[i] >= 'a') && (s[i] <= 'f'))  ||
1532           ((s[i] >= 'A') && (s[i] <= 'F'))))
1533        return CO_E_CLASSSTRING;
1534   }
1535
1536   TRACE("%s -> %p\n", debugstr_w(s), id);
1537
1538   /* quick lookup table */
1539   memset(table, 0, 256);
1540
1541   for (i = 0; i < 10; i++) {
1542     table['0' + i] = i;
1543   }
1544   for (i = 0; i < 6; i++) {
1545     table['A' + i] = i+10;
1546     table['a' + i] = i+10;
1547   }
1548
1549   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1550
1551   id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1552                table[s[5]] << 12 | table[s[6]] << 8  | table[s[7]] << 4  | table[s[8]]);
1553   id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1554   id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1555
1556   /* these are just sequential bytes */
1557   id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1558   id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1559   id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1560   id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1561   id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1562   id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1563   id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1564   id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1565
1566   return S_OK;
1567 }
1568
1569 /*****************************************************************************/
1570
1571 HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1572 {
1573     HRESULT ret;
1574
1575     if (!id)
1576         return E_INVALIDARG;
1577
1578     ret = __CLSIDFromString(idstr, id);
1579     if(ret != S_OK) { /* It appears a ProgID is also valid */
1580         ret = CLSIDFromProgID(idstr, id);
1581     }
1582     return ret;
1583 }
1584
1585
1586 /******************************************************************************
1587  *              StringFromCLSID [OLE32.@]
1588  *              StringFromIID   [OLE32.@]
1589  *
1590  * Converts a GUID into the respective string representation.
1591  * The target string is allocated using the OLE IMalloc.
1592  *
1593  * PARAMS
1594  *  id    [I] the GUID to be converted.
1595  *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1596  *
1597  * RETURNS
1598  *   S_OK
1599  *   E_FAIL
1600  *
1601  * SEE ALSO
1602  *  StringFromGUID2, CLSIDFromString
1603  */
1604 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1605 {
1606     HRESULT ret;
1607     LPMALLOC mllc;
1608
1609     if ((ret = CoGetMalloc(0,&mllc))) return ret;
1610     if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
1611     StringFromGUID2( id, *idstr, CHARS_IN_GUID );
1612     return S_OK;
1613 }
1614
1615 /******************************************************************************
1616  *              StringFromGUID2 [OLE32.@]
1617  *
1618  * Modified version of StringFromCLSID that allows you to specify max
1619  * buffer size.
1620  *
1621  * PARAMS
1622  *  id   [I] GUID to convert to string.
1623  *  str  [O] Buffer where the result will be stored.
1624  *  cmax [I] Size of the buffer in characters.
1625  *
1626  * RETURNS
1627  *      Success: The length of the resulting string in characters.
1628  *  Failure: 0.
1629  */
1630 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1631 {
1632     static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
1633                                      '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
1634                                      '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
1635                                      '%','0','2','X','%','0','2','X','}',0 };
1636     if (!id || cmax < CHARS_IN_GUID) return 0;
1637     sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
1638               id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1639               id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1640     return CHARS_IN_GUID;
1641 }
1642
1643 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1644 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1645 {
1646     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1647     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1648     LONG res;
1649     HKEY key;
1650
1651     strcpyW(path, wszCLSIDSlash);
1652     StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1653     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1654     if (res == ERROR_FILE_NOT_FOUND)
1655         return REGDB_E_CLASSNOTREG;
1656     else if (res != ERROR_SUCCESS)
1657         return REGDB_E_READREGDB;
1658
1659     if (!keyname)
1660     {
1661         *subkey = key;
1662         return S_OK;
1663     }
1664
1665     res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1666     RegCloseKey(key);
1667     if (res == ERROR_FILE_NOT_FOUND)
1668         return REGDB_E_KEYMISSING;
1669     else if (res != ERROR_SUCCESS)
1670         return REGDB_E_READREGDB;
1671
1672     return S_OK;
1673 }
1674
1675 /* open HKCR\\AppId\\{string form of appid clsid} key */
1676 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1677 {
1678     static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1679     static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1680     DWORD res;
1681     WCHAR buf[CHARS_IN_GUID];
1682     WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1683     DWORD size;
1684     HKEY hkey;
1685     DWORD type;
1686     HRESULT hr;
1687
1688     /* read the AppID value under the class's key */
1689     hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1690     if (FAILED(hr))
1691         return hr;
1692
1693     size = sizeof(buf);
1694     res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1695     RegCloseKey(hkey);
1696     if (res == ERROR_FILE_NOT_FOUND)
1697         return REGDB_E_KEYMISSING;
1698     else if (res != ERROR_SUCCESS || type!=REG_SZ)
1699         return REGDB_E_READREGDB;
1700
1701     strcpyW(keyname, szAppIdKey);
1702     strcatW(keyname, buf);
1703     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1704     if (res == ERROR_FILE_NOT_FOUND)
1705         return REGDB_E_KEYMISSING;
1706     else if (res != ERROR_SUCCESS)
1707         return REGDB_E_READREGDB;
1708
1709     return S_OK;
1710 }
1711
1712 /******************************************************************************
1713  *               ProgIDFromCLSID [OLE32.@]
1714  *
1715  * Converts a class id into the respective program ID.
1716  *
1717  * PARAMS
1718  *  clsid        [I] Class ID, as found in registry.
1719  *  ppszProgID [O] Associated ProgID.
1720  *
1721  * RETURNS
1722  *   S_OK
1723  *   E_OUTOFMEMORY
1724  *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1725  */
1726 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1727 {
1728     static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1729     HKEY     hkey;
1730     HRESULT  ret;
1731     LONG progidlen = 0;
1732
1733     if (!ppszProgID)
1734     {
1735         ERR("ppszProgId isn't optional\n");
1736         return E_INVALIDARG;
1737     }
1738
1739     *ppszProgID = NULL;
1740     ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1741     if (FAILED(ret))
1742         return ret;
1743
1744     if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1745       ret = REGDB_E_CLASSNOTREG;
1746
1747     if (ret == S_OK)
1748     {
1749       *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1750       if (*ppszProgID)
1751       {
1752         if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1753           ret = REGDB_E_CLASSNOTREG;
1754       }
1755       else
1756         ret = E_OUTOFMEMORY;
1757     }
1758
1759     RegCloseKey(hkey);
1760     return ret;
1761 }
1762
1763 /******************************************************************************
1764  *              CLSIDFromProgID [OLE32.@]
1765  *
1766  * Converts a program id into the respective GUID.
1767  *
1768  * PARAMS
1769  *  progid [I] Unicode program ID, as found in registry.
1770  *  clsid  [O] Associated CLSID.
1771  *
1772  * RETURNS
1773  *      Success: S_OK
1774  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1775  */
1776 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1777 {
1778     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1779     WCHAR buf2[CHARS_IN_GUID];
1780     LONG buf2len = sizeof(buf2);
1781     HKEY xhkey;
1782     WCHAR *buf;
1783
1784     if (!progid || !clsid)
1785     {
1786         ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1787         return E_INVALIDARG;
1788     }
1789
1790     /* initialise clsid in case of failure */
1791     memset(clsid, 0, sizeof(*clsid));
1792
1793     buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1794     strcpyW( buf, progid );
1795     strcatW( buf, clsidW );
1796     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1797     {
1798         HeapFree(GetProcessHeap(),0,buf);
1799         WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1800         return CO_E_CLASSSTRING;
1801     }
1802     HeapFree(GetProcessHeap(),0,buf);
1803
1804     if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1805     {
1806         RegCloseKey(xhkey);
1807         WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1808         return CO_E_CLASSSTRING;
1809     }
1810     RegCloseKey(xhkey);
1811     return __CLSIDFromString(buf2,clsid);
1812 }
1813
1814
1815 /*****************************************************************************
1816  *             CoGetPSClsid [OLE32.@]
1817  *
1818  * Retrieves the CLSID of the proxy/stub factory that implements
1819  * IPSFactoryBuffer for the specified interface.
1820  *
1821  * PARAMS
1822  *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
1823  *  pclsid [O] Where to store returned proxy/stub CLSID.
1824  * 
1825  * RETURNS
1826  *   S_OK
1827  *   E_OUTOFMEMORY
1828  *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1829  *
1830  * NOTES
1831  *
1832  * The standard marshaller activates the object with the CLSID
1833  * returned and uses the CreateProxy and CreateStub methods on its
1834  * IPSFactoryBuffer interface to construct the proxies and stubs for a
1835  * given object.
1836  *
1837  * CoGetPSClsid determines this CLSID by searching the
1838  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1839  * in the registry and any interface id registered by
1840  * CoRegisterPSClsid within the current process.
1841  *
1842  * BUGS
1843  *
1844  * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1845  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1846  * considered a bug in native unless an application depends on this (unlikely).
1847  *
1848  * SEE ALSO
1849  *  CoRegisterPSClsid.
1850  */
1851 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1852 {
1853     static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1854     static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1855     WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1856     WCHAR value[CHARS_IN_GUID];
1857     LONG len;
1858     HKEY hkey;
1859     APARTMENT *apt = COM_CurrentApt();
1860     struct registered_psclsid *registered_psclsid;
1861
1862     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1863
1864     if (!apt)
1865     {
1866         ERR("apartment not initialised\n");
1867         return CO_E_NOTINITIALIZED;
1868     }
1869
1870     if (!pclsid)
1871     {
1872         ERR("pclsid isn't optional\n");
1873         return E_INVALIDARG;
1874     }
1875
1876     EnterCriticalSection(&apt->cs);
1877
1878     LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1879         if (IsEqualIID(&registered_psclsid->iid, riid))
1880         {
1881             *pclsid = registered_psclsid->clsid;
1882             LeaveCriticalSection(&apt->cs);
1883             return S_OK;
1884         }
1885
1886     LeaveCriticalSection(&apt->cs);
1887
1888     /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1889     strcpyW(path, wszInterface);
1890     StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1891     strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1892
1893     /* Open the key.. */
1894     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1895     {
1896         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1897         return REGDB_E_IIDNOTREG;
1898     }
1899
1900     /* ... Once we have the key, query the registry to get the
1901        value of CLSID as a string, and convert it into a
1902        proper CLSID structure to be passed back to the app */
1903     len = sizeof(value);
1904     if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1905     {
1906         RegCloseKey(hkey);
1907         return REGDB_E_IIDNOTREG;
1908     }
1909     RegCloseKey(hkey);
1910
1911     /* We have the CLSID we want back from the registry as a string, so
1912        let's convert it into a CLSID structure */
1913     if (CLSIDFromString(value, pclsid) != NOERROR)
1914         return REGDB_E_IIDNOTREG;
1915
1916     TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1917     return S_OK;
1918 }
1919
1920 /*****************************************************************************
1921  *             CoRegisterPSClsid [OLE32.@]
1922  *
1923  * Register a proxy/stub CLSID for the given interface in the current process
1924  * only.
1925  *
1926  * PARAMS
1927  *  riid   [I] Interface whose proxy/stub CLSID is to be registered.
1928  *  rclsid [I] CLSID of the proxy/stub.
1929  * 
1930  * RETURNS
1931  *   Success: S_OK
1932  *   Failure: E_OUTOFMEMORY
1933  *
1934  * NOTES
1935  *
1936  * This function does not add anything to the registry and the effects are
1937  * limited to the lifetime of the current process.
1938  *
1939  * SEE ALSO
1940  *  CoGetPSClsid.
1941  */
1942 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1943 {
1944     APARTMENT *apt = COM_CurrentApt();
1945     struct registered_psclsid *registered_psclsid;
1946
1947     TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1948
1949     if (!apt)
1950     {
1951         ERR("apartment not initialised\n");
1952         return CO_E_NOTINITIALIZED;
1953     }
1954
1955     EnterCriticalSection(&apt->cs);
1956
1957     LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1958         if (IsEqualIID(&registered_psclsid->iid, riid))
1959         {
1960             registered_psclsid->clsid = *rclsid;
1961             LeaveCriticalSection(&apt->cs);
1962             return S_OK;
1963         }
1964
1965     registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1966     if (!registered_psclsid)
1967     {
1968         LeaveCriticalSection(&apt->cs);
1969         return E_OUTOFMEMORY;
1970     }
1971
1972     registered_psclsid->iid = *riid;
1973     registered_psclsid->clsid = *rclsid;
1974     list_add_head(&apt->psclsids, &registered_psclsid->entry);
1975
1976     LeaveCriticalSection(&apt->cs);
1977
1978     return S_OK;
1979 }
1980
1981
1982 /***
1983  * COM_GetRegisteredClassObject
1984  *
1985  * This internal method is used to scan the registered class list to
1986  * find a class object.
1987  *
1988  * Params:
1989  *   rclsid        Class ID of the class to find.
1990  *   dwClsContext  Class context to match.
1991  *   ppv           [out] returns a pointer to the class object. Complying
1992  *                 to normal COM usage, this method will increase the
1993  *                 reference count on this object.
1994  */
1995 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1996                                             DWORD dwClsContext, LPUNKNOWN* ppUnk)
1997 {
1998   HRESULT hr = S_FALSE;
1999   RegisteredClass *curClass;
2000
2001   EnterCriticalSection( &csRegisteredClassList );
2002
2003   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2004   {
2005     /*
2006      * Check if we have a match on the class ID and context.
2007      */
2008     if ((apt->oxid == curClass->apartment_id) &&
2009         (dwClsContext & curClass->runContext) &&
2010         IsEqualGUID(&(curClass->classIdentifier), rclsid))
2011     {
2012       /*
2013        * We have a match, return the pointer to the class object.
2014        */
2015       *ppUnk = curClass->classObject;
2016
2017       IUnknown_AddRef(curClass->classObject);
2018
2019       hr = S_OK;
2020       break;
2021     }
2022   }
2023
2024   LeaveCriticalSection( &csRegisteredClassList );
2025
2026   return hr;
2027 }
2028
2029 /******************************************************************************
2030  *              CoRegisterClassObject   [OLE32.@]
2031  *
2032  * Registers the class object for a given class ID. Servers housed in EXE
2033  * files use this method instead of exporting DllGetClassObject to allow
2034  * other code to connect to their objects.
2035  *
2036  * PARAMS
2037  *  rclsid       [I] CLSID of the object to register.
2038  *  pUnk         [I] IUnknown of the object.
2039  *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
2040  *  flags        [I] REGCLS flags indicating how connections are made.
2041  *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
2042  *
2043  * RETURNS
2044  *   S_OK on success,
2045  *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
2046  *   CO_E_OBJISREG if the object is already registered. We should not return this.
2047  *
2048  * SEE ALSO
2049  *   CoRevokeClassObject, CoGetClassObject
2050  *
2051  * NOTES
2052  *  In-process objects are only registered for the current apartment.
2053  *  CoGetClassObject() and CoCreateInstance() will not return objects registered
2054  *  in other apartments.
2055  *
2056  * BUGS
2057  *  MSDN claims that multiple interface registrations are legal, but we
2058  *  can't do that with our current implementation.
2059  */
2060 HRESULT WINAPI CoRegisterClassObject(
2061     REFCLSID rclsid,
2062     LPUNKNOWN pUnk,
2063     DWORD dwClsContext,
2064     DWORD flags,
2065     LPDWORD lpdwRegister)
2066 {
2067   static LONG next_cookie;
2068   RegisteredClass* newClass;
2069   LPUNKNOWN        foundObject;
2070   HRESULT          hr;
2071   APARTMENT *apt;
2072
2073   TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2074         debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2075
2076   if ( (lpdwRegister==0) || (pUnk==0) )
2077     return E_INVALIDARG;
2078
2079   apt = COM_CurrentApt();
2080   if (!apt)
2081   {
2082       ERR("COM was not initialized\n");
2083       return CO_E_NOTINITIALIZED;
2084   }
2085
2086   *lpdwRegister = 0;
2087
2088   /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
2089    * differentiates the flag from REGCLS_MULTI_SEPARATE. */
2090   if (flags & REGCLS_MULTIPLEUSE)
2091     dwClsContext |= CLSCTX_INPROC_SERVER;
2092
2093   /*
2094    * First, check if the class is already registered.
2095    * If it is, this should cause an error.
2096    */
2097   hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2098   if (hr == S_OK) {
2099     if (flags & REGCLS_MULTIPLEUSE) {
2100       if (dwClsContext & CLSCTX_LOCAL_SERVER)
2101         hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
2102       IUnknown_Release(foundObject);
2103       return hr;
2104     }
2105     IUnknown_Release(foundObject);
2106     ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2107     return CO_E_OBJISREG;
2108   }
2109
2110   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2111   if ( newClass == NULL )
2112     return E_OUTOFMEMORY;
2113
2114   newClass->classIdentifier = *rclsid;
2115   newClass->apartment_id    = apt->oxid;
2116   newClass->runContext      = dwClsContext;
2117   newClass->connectFlags    = flags;
2118   newClass->pMarshaledData  = NULL;
2119   newClass->RpcRegistration = NULL;
2120
2121   if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
2122       newClass->dwCookie = InterlockedIncrement( &next_cookie );
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     TRACE("(%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         switch (res)
3650         {
3651         case WAIT_TIMEOUT:
3652             hr = RPC_S_CALLPENDING;
3653             break;
3654         case WAIT_FAILED:
3655             hr = HRESULT_FROM_WIN32( GetLastError() );
3656             break;
3657         default:
3658             *lpdwindex = res;
3659             break;
3660         }
3661         break;
3662     }
3663     TRACE("-- 0x%08x\n", hr);
3664     return hr;
3665 }
3666
3667
3668 /***********************************************************************
3669  *           CoGetObject [OLE32.@]
3670  *
3671  * Gets the object named by converting the name to a moniker and binding to it.
3672  *
3673  * PARAMS
3674  *  pszName      [I] String representing the object.
3675  *  pBindOptions [I] Parameters affecting the binding to the named object.
3676  *  riid         [I] Interface to bind to on the objecct.
3677  *  ppv          [O] On output, the interface riid of the object represented
3678  *                   by pszName.
3679  *
3680  * RETURNS
3681  *  Success: S_OK.
3682  *  Failure: HRESULT code.
3683  *
3684  * SEE ALSO
3685  *  MkParseDisplayName.
3686  */
3687 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3688     REFIID riid, void **ppv)
3689 {
3690     IBindCtx *pbc;
3691     HRESULT hr;
3692
3693     *ppv = NULL;
3694
3695     hr = CreateBindCtx(0, &pbc);
3696     if (SUCCEEDED(hr))
3697     {
3698         if (pBindOptions)
3699             hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3700
3701         if (SUCCEEDED(hr))
3702         {
3703             ULONG chEaten;
3704             IMoniker *pmk;
3705
3706             hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3707             if (SUCCEEDED(hr))
3708             {
3709                 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3710                 IMoniker_Release(pmk);
3711             }
3712         }
3713
3714         IBindCtx_Release(pbc);
3715     }
3716     return hr;
3717 }
3718
3719 /***********************************************************************
3720  *           CoRegisterChannelHook [OLE32.@]
3721  *
3722  * Registers a process-wide hook that is called during ORPC calls.
3723  *
3724  * PARAMS
3725  *  guidExtension [I] GUID of the channel hook to register.
3726  *  pChannelHook  [I] Channel hook object to register.
3727  *
3728  * RETURNS
3729  *  Success: S_OK.
3730  *  Failure: HRESULT code.
3731  */
3732 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3733 {
3734     TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3735
3736     return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3737 }
3738
3739 typedef struct Context
3740 {
3741     IComThreadingInfo IComThreadingInfo_iface;
3742     IContextCallback IContextCallback_iface;
3743     IObjContext IObjContext_iface;
3744     LONG refs;
3745     APTTYPE apttype;
3746 } Context;
3747
3748 static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
3749 {
3750         return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
3751 }
3752
3753 static inline Context *impl_from_IContextCallback( IContextCallback *iface )
3754 {
3755         return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
3756 }
3757
3758 static inline Context *impl_from_IObjContext( IObjContext *iface )
3759 {
3760         return CONTAINING_RECORD(iface, Context, IObjContext_iface);
3761 }
3762
3763 static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3764 {
3765     *ppv = NULL;
3766
3767     if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3768         IsEqualIID(riid, &IID_IUnknown))
3769     {
3770         *ppv = &iface->IComThreadingInfo_iface;
3771     }
3772     else if (IsEqualIID(riid, &IID_IContextCallback))
3773     {
3774         *ppv = &iface->IContextCallback_iface;
3775     }
3776     else if (IsEqualIID(riid, &IID_IObjContext))
3777     {
3778         *ppv = &iface->IObjContext_iface;
3779     }
3780
3781     if (*ppv)
3782     {
3783         IUnknown_AddRef((IUnknown*)*ppv);
3784         return S_OK;
3785     }
3786
3787     FIXME("interface not implemented %s\n", debugstr_guid(riid));
3788     return E_NOINTERFACE;
3789 }
3790
3791 static ULONG Context_AddRef(Context *This)
3792 {
3793     return InterlockedIncrement(&This->refs);
3794 }
3795
3796 static ULONG Context_Release(Context *This)
3797 {
3798     ULONG refs = InterlockedDecrement(&This->refs);
3799     if (!refs)
3800         HeapFree(GetProcessHeap(), 0, This);
3801     return refs;
3802 }
3803
3804 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3805 {
3806     Context *This = impl_from_IComThreadingInfo(iface);
3807     return Context_QueryInterface(This, riid, ppv);
3808 }
3809
3810 static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
3811 {
3812     Context *This = impl_from_IComThreadingInfo(iface);
3813     return Context_AddRef(This);
3814 }
3815
3816 static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
3817 {
3818     Context *This = impl_from_IComThreadingInfo(iface);
3819     return Context_Release(This);
3820 }
3821
3822 static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3823 {
3824     Context *This = impl_from_IComThreadingInfo(iface);
3825
3826     TRACE("(%p)\n", apttype);
3827
3828     *apttype = This->apttype;
3829     return S_OK;
3830 }
3831
3832 static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3833 {
3834     Context *This = impl_from_IComThreadingInfo(iface);
3835
3836     TRACE("(%p)\n", thdtype);
3837
3838     switch (This->apttype)
3839     {
3840     case APTTYPE_STA:
3841     case APTTYPE_MAINSTA:
3842         *thdtype = THDTYPE_PROCESSMESSAGES;
3843         break;
3844     default:
3845         *thdtype = THDTYPE_BLOCKMESSAGES;
3846         break;
3847     }
3848     return S_OK;
3849 }
3850
3851 static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3852 {
3853     FIXME("(%p): stub\n", logical_thread_id);
3854     return E_NOTIMPL;
3855 }
3856
3857 static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3858 {
3859     FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3860     return E_NOTIMPL;
3861 }
3862
3863 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3864 {
3865     Context_CTI_QueryInterface,
3866     Context_CTI_AddRef,
3867     Context_CTI_Release,
3868     Context_CTI_GetCurrentApartmentType,
3869     Context_CTI_GetCurrentThreadType,
3870     Context_CTI_GetCurrentLogicalThreadId,
3871     Context_CTI_SetCurrentLogicalThreadId
3872 };
3873
3874 static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
3875 {
3876     Context *This = impl_from_IContextCallback(iface);
3877     return Context_QueryInterface(This, riid, ppv);
3878 }
3879
3880 static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
3881 {
3882     Context *This = impl_from_IContextCallback(iface);
3883     return Context_AddRef(This);
3884 }
3885
3886 static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
3887 {
3888     Context *This = impl_from_IContextCallback(iface);
3889     return Context_Release(This);
3890 }
3891
3892 static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
3893                             ComCallData *param, REFIID riid, int method, IUnknown *punk)
3894 {
3895     Context *This = impl_from_IContextCallback(iface);
3896
3897     FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
3898     return E_NOTIMPL;
3899 }
3900
3901 static const IContextCallbackVtbl Context_Callback_Vtbl =
3902 {
3903     Context_CC_QueryInterface,
3904     Context_CC_AddRef,
3905     Context_CC_Release,
3906     Context_CC_ContextCallback
3907 };
3908
3909 static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
3910 {
3911     Context *This = impl_from_IObjContext(iface);
3912     return Context_QueryInterface(This, riid, ppv);
3913 }
3914
3915 static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
3916 {
3917     Context *This = impl_from_IObjContext(iface);
3918     return Context_AddRef(This);
3919 }
3920
3921 static ULONG WINAPI Context_OC_Release(IObjContext *iface)
3922 {
3923     Context *This = impl_from_IObjContext(iface);
3924     return Context_Release(This);
3925 }
3926
3927 static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
3928 {
3929     Context *This = impl_from_IObjContext(iface);
3930
3931     FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3932     return E_NOTIMPL;
3933 }
3934
3935 static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
3936 {
3937     Context *This = impl_from_IObjContext(iface);
3938
3939     FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
3940     return E_NOTIMPL;
3941 }
3942
3943 static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
3944 {
3945     Context *This = impl_from_IObjContext(iface);
3946
3947     FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
3948     return E_NOTIMPL;
3949 }
3950
3951 static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
3952 {
3953     Context *This = impl_from_IObjContext(iface);
3954
3955     FIXME("(%p/%p)->(%p)\n", This, iface, props);
3956     return E_NOTIMPL;
3957 }
3958
3959 static void WINAPI Context_OC_Reserved1(IObjContext *iface)
3960 {
3961     Context *This = impl_from_IObjContext(iface);
3962     FIXME("(%p/%p)\n", This, iface);
3963 }
3964
3965 static void WINAPI Context_OC_Reserved2(IObjContext *iface)
3966 {
3967     Context *This = impl_from_IObjContext(iface);
3968     FIXME("(%p/%p)\n", This, iface);
3969 }
3970
3971 static void WINAPI Context_OC_Reserved3(IObjContext *iface)
3972 {
3973     Context *This = impl_from_IObjContext(iface);
3974     FIXME("(%p/%p)\n", This, iface);
3975 }
3976
3977 static void WINAPI Context_OC_Reserved4(IObjContext *iface)
3978 {
3979     Context *This = impl_from_IObjContext(iface);
3980     FIXME("(%p/%p)\n", This, iface);
3981 }
3982
3983 static void WINAPI Context_OC_Reserved5(IObjContext *iface)
3984 {
3985     Context *This = impl_from_IObjContext(iface);
3986     FIXME("(%p/%p)\n", This, iface);
3987 }
3988
3989 static void WINAPI Context_OC_Reserved6(IObjContext *iface)
3990 {
3991     Context *This = impl_from_IObjContext(iface);
3992     FIXME("(%p/%p)\n", This, iface);
3993 }
3994
3995 static void WINAPI Context_OC_Reserved7(IObjContext *iface)
3996 {
3997     Context *This = impl_from_IObjContext(iface);
3998     FIXME("(%p/%p)\n", This, iface);
3999 }
4000
4001 static const IObjContextVtbl Context_Object_Vtbl =
4002 {
4003     Context_OC_QueryInterface,
4004     Context_OC_AddRef,
4005     Context_OC_Release,
4006     Context_OC_SetProperty,
4007     Context_OC_RemoveProperty,
4008     Context_OC_GetProperty,
4009     Context_OC_EnumContextProps,
4010     Context_OC_Reserved1,
4011     Context_OC_Reserved2,
4012     Context_OC_Reserved3,
4013     Context_OC_Reserved4,
4014     Context_OC_Reserved5,
4015     Context_OC_Reserved6,
4016     Context_OC_Reserved7
4017 };
4018
4019 /***********************************************************************
4020  *           CoGetObjectContext [OLE32.@]
4021  *
4022  * Retrieves an object associated with the current context (i.e. apartment).
4023  *
4024  * PARAMS
4025  *  riid [I] ID of the interface of the object to retrieve.
4026  *  ppv  [O] Address where object will be stored on return.
4027  *
4028  * RETURNS
4029  *  Success: S_OK.
4030  *  Failure: HRESULT code.
4031  */
4032 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
4033 {
4034     APARTMENT *apt = COM_CurrentApt();
4035     Context *context;
4036     HRESULT hr;
4037
4038     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
4039
4040     *ppv = NULL;
4041     if (!apt)
4042     {
4043         if (!(apt = apartment_find_multi_threaded()))
4044         {
4045             ERR("apartment not initialised\n");
4046             return CO_E_NOTINITIALIZED;
4047         }
4048         apartment_release(apt);
4049     }
4050
4051     context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
4052     if (!context)
4053         return E_OUTOFMEMORY;
4054
4055     context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
4056     context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
4057     context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4058     context->refs = 1;
4059     if (apt->multi_threaded)
4060         context->apttype = APTTYPE_MTA;
4061     else if (apt->main)
4062         context->apttype = APTTYPE_MAINSTA;
4063     else
4064         context->apttype = APTTYPE_STA;
4065
4066     hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
4067     IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4068
4069     return hr;
4070 }
4071
4072
4073 /***********************************************************************
4074  *           CoGetContextToken [OLE32.@]
4075  */
4076 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
4077 {
4078     struct oletls *info = COM_CurrentInfo();
4079
4080     TRACE("(%p)\n", token);
4081
4082     if (!info)
4083         return E_OUTOFMEMORY;
4084
4085     if (!info->apt)
4086     {
4087         APARTMENT *apt;
4088         if (!(apt = apartment_find_multi_threaded()))
4089         {
4090             ERR("apartment not initialised\n");
4091             return CO_E_NOTINITIALIZED;
4092         }
4093         apartment_release(apt);
4094     }
4095
4096     if (!token)
4097         return E_POINTER;
4098
4099     if (!info->context_token)
4100     {
4101         HRESULT hr;
4102         IObjContext *ctx;
4103
4104         hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
4105         if (FAILED(hr)) return hr;
4106         info->context_token = ctx;
4107     }
4108
4109     *token = (ULONG_PTR)info->context_token;
4110     TRACE("apt->context_token=%p\n", info->context_token);
4111
4112     return S_OK;
4113 }
4114
4115 HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
4116 {
4117     static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
4118     HKEY hkey;
4119     HRESULT hres;
4120
4121     hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
4122     if (SUCCEEDED(hres))
4123     {
4124         WCHAR dllpath[MAX_PATH+1];
4125
4126         if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
4127         {
4128             static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
4129             if (!strcmpiW(dllpath, wszOle32))
4130             {
4131                 RegCloseKey(hkey);
4132                 return HandlerCF_Create(rclsid, riid, ppv);
4133             }
4134         }
4135         else
4136             WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
4137         RegCloseKey(hkey);
4138     }
4139
4140     return CLASS_E_CLASSNOTAVAILABLE;
4141 }
4142
4143 /***********************************************************************
4144  *              DllMain (OLE32.@)
4145  */
4146 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
4147 {
4148     TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4149
4150     switch(fdwReason) {
4151     case DLL_PROCESS_ATTACH:
4152         hProxyDll = hinstDLL;
4153         COMPOBJ_InitProcess();
4154         break;
4155
4156     case DLL_PROCESS_DETACH:
4157         COMPOBJ_UninitProcess();
4158         RPC_UnregisterAllChannelHooks();
4159         COMPOBJ_DllList_Free();
4160         break;
4161
4162     case DLL_THREAD_DETACH:
4163         COM_TlsDestroy();
4164         break;
4165     }
4166     return TRUE;
4167 }
4168
4169 /***********************************************************************
4170  *              DllRegisterServer (OLE32.@)
4171  */
4172 HRESULT WINAPI DllRegisterServer(void)
4173 {
4174     return OLE32_DllRegisterServer();
4175 }
4176
4177 /***********************************************************************
4178  *              DllUnregisterServer (OLE32.@)
4179  */
4180 HRESULT WINAPI DllUnregisterServer(void)
4181 {
4182     return OLE32_DllUnregisterServer();
4183 }