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