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