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