ole32: Add Co*InitializeSpy functions.
[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
59 #include "compobj_private.h"
60
61 #include "wine/unicode.h"
62 #include "wine/debug.h"
63
64 WINE_DEFAULT_DEBUG_CHANNEL(ole);
65
66 HINSTANCE OLE32_hInstance = 0;
67
68 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
69
70 /****************************************************************************
71  * This section defines variables internal to the COM module.
72  */
73
74 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
75                                             DWORD dwClsContext, LPUNKNOWN*  ppUnk);
76 static void COM_RevokeAllClasses(const struct apartment *apt);
77 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv);
78
79 static APARTMENT *MTA; /* protected by csApartment */
80 static APARTMENT *MainApartment; /* the first STA apartment */
81 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
82
83 static CRITICAL_SECTION csApartment;
84 static CRITICAL_SECTION_DEBUG critsect_debug =
85 {
86     0, 0, &csApartment,
87     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
88       0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
89 };
90 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
91
92 struct registered_psclsid
93 {
94     struct list entry;
95     IID iid;
96     CLSID clsid;
97 };
98
99 /*
100  * This lock count counts the number of times CoInitialize is called. It is
101  * decreased every time CoUninitialize is called. When it hits 0, the COM
102  * libraries are freed
103  */
104 static LONG s_COMLockCount = 0;
105 /* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
106 static LONG s_COMServerProcessReferences = 0;
107
108 /*
109  * This linked list contains the list of registered class objects. These
110  * are mostly used to register the factories for out-of-proc servers of OLE
111  * objects.
112  *
113  * TODO: Make this data structure aware of inter-process communication. This
114  *       means that parts of this will be exported to rpcss.
115  */
116 typedef struct tagRegisteredClass
117 {
118   struct list entry;
119   CLSID     classIdentifier;
120   OXID      apartment_id;
121   LPUNKNOWN classObject;
122   DWORD     runContext;
123   DWORD     connectFlags;
124   DWORD     dwCookie;
125   LPSTREAM  pMarshaledData; /* FIXME: only really need to store OXID and IPID */
126   void     *RpcRegistration;
127 } RegisteredClass;
128
129 static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
130
131 static CRITICAL_SECTION csRegisteredClassList;
132 static CRITICAL_SECTION_DEBUG class_cs_debug =
133 {
134     0, 0, &csRegisteredClassList,
135     { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
136       0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
137 };
138 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
139
140 /*****************************************************************************
141  * This section contains OpenDllList definitions
142  *
143  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
144  * other functions that do LoadLibrary _without_ giving back a HMODULE.
145  * Without this list these handles would never be freed.
146  *
147  * FIXME: a DLL that says OK when asked for unloading is unloaded in the
148  * next unload-call but not before 600 sec.
149  */
150
151 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
152 typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
153
154 typedef struct tagOpenDll
155 {
156   LONG refs;
157   LPWSTR library_name;
158   HANDLE library;
159   DllGetClassObjectFunc DllGetClassObject;
160   DllCanUnloadNowFunc DllCanUnloadNow;
161   struct list entry;
162 } OpenDll;
163
164 static struct list openDllList = LIST_INIT(openDllList);
165
166 static CRITICAL_SECTION csOpenDllList;
167 static CRITICAL_SECTION_DEBUG dll_cs_debug =
168 {
169     0, 0, &csOpenDllList,
170     { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
171       0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
172 };
173 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
174
175 struct apartment_loaded_dll
176 {
177     struct list entry;
178     OpenDll *dll;
179     DWORD unload_time;
180     BOOL multi_threaded;
181 };
182
183 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',' ',
184                                        '0','x','#','#','#','#','#','#','#','#',' ',0};
185 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
186 static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
187                                         BOOL apartment_threaded,
188                                         REFCLSID rclsid, REFIID riid, void **ppv);
189 static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
190
191 static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
192 static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
193 static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
194
195 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);
196
197 static void COMPOBJ_InitProcess( void )
198 {
199     WNDCLASSW wclass;
200
201     /* Dispatching to the correct thread in an apartment is done through
202      * window messages rather than RPC transports. When an interface is
203      * marshalled into another apartment in the same process, a window of the
204      * following class is created. The *caller* of CoMarshalInterface (i.e., the
205      * application) is responsible for pumping the message loop in that thread.
206      * The WM_USER messages which point to the RPCs are then dispatched to
207      * apartment_wndproc by the user's code from the apartment in which the
208      * interface was unmarshalled.
209      */
210     memset(&wclass, 0, sizeof(wclass));
211     wclass.lpfnWndProc = apartment_wndproc;
212     wclass.hInstance = OLE32_hInstance;
213     wclass.lpszClassName = wszAptWinClass;
214     RegisterClassW(&wclass);
215 }
216
217 static void COMPOBJ_UninitProcess( void )
218 {
219     UnregisterClassW(wszAptWinClass, OLE32_hInstance);
220 }
221
222 static void COM_TlsDestroy(void)
223 {
224     struct oletls *info = NtCurrentTeb()->ReservedForOle;
225     if (info)
226     {
227         if (info->apt) apartment_release(info->apt);
228         if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
229         if (info->state) IUnknown_Release(info->state);
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, OLE32_hInstance, 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 HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
1062 {
1063     struct oletls *info = COM_CurrentInfo();
1064     TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
1065
1066     if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
1067         return E_INVALIDARG;
1068
1069     IUnknown_Release(info->spy);
1070     return S_OK;
1071 }
1072
1073
1074 /******************************************************************************
1075  *              CoInitialize    [OLE32.@]
1076  *
1077  * Initializes the COM libraries by calling CoInitializeEx with
1078  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1079  *
1080  * PARAMS
1081  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1082  *
1083  * RETURNS
1084  *  Success: S_OK if not already initialized, S_FALSE otherwise.
1085  *  Failure: HRESULT code.
1086  *
1087  * SEE ALSO
1088  *   CoInitializeEx
1089  */
1090 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1091 {
1092   /*
1093    * Just delegate to the newer method.
1094    */
1095   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
1096 }
1097
1098 /******************************************************************************
1099  *              CoInitializeEx  [OLE32.@]
1100  *
1101  * Initializes the COM libraries.
1102  *
1103  * PARAMS
1104  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
1105  *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
1106  *
1107  * RETURNS
1108  *  S_OK               if successful,
1109  *  S_FALSE            if this function was called already.
1110  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
1111  *                     threading model.
1112  *
1113  * NOTES
1114  *
1115  * The behavior used to set the IMalloc used for memory management is
1116  * obsolete.
1117  * The dwCoInit parameter must specify one of the following apartment
1118  * threading models:
1119  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
1120  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
1121  * The parameter may also specify zero or more of the following flags:
1122  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
1123  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
1124  *
1125  * SEE ALSO
1126  *   CoUninitialize
1127  */
1128 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1129 {
1130   struct oletls *info = COM_CurrentInfo();
1131   HRESULT hr = S_OK;
1132   APARTMENT *apt;
1133
1134   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1135
1136   if (lpReserved!=NULL)
1137   {
1138     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1139   }
1140
1141   /*
1142    * Check the lock count. If this is the first time going through the initialize
1143    * process, we have to initialize the libraries.
1144    *
1145    * And crank-up that lock count.
1146    */
1147   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1148   {
1149     /*
1150      * Initialize the various COM libraries and data structures.
1151      */
1152     TRACE("() - Initializing the COM libraries\n");
1153
1154     /* we may need to defer this until after apartment initialisation */
1155     RunningObjectTableImpl_Initialize();
1156   }
1157
1158   if (info->spy)
1159       IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);
1160
1161   if (!(apt = info->apt))
1162   {
1163     apt = apartment_get_or_create(dwCoInit);
1164     if (!apt) return E_OUTOFMEMORY;
1165   }
1166   else if (!apartment_is_model(apt, dwCoInit))
1167   {
1168     /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
1169        code then we are probably using the wrong threading model to implement that API. */
1170     ERR("Attempt to change threading model of this apartment from %s to %s\n",
1171         apt->multi_threaded ? "multi-threaded" : "apartment threaded",
1172         dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1173     return RPC_E_CHANGED_MODE;
1174   }
1175   else
1176     hr = S_FALSE;
1177
1178   info->inits++;
1179
1180   if (info->spy)
1181       IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1182
1183   return hr;
1184 }
1185
1186 /***********************************************************************
1187  *           CoUninitialize   [OLE32.@]
1188  *
1189  * This method will decrement the refcount on the current apartment, freeing
1190  * the resources associated with it if it is the last thread in the apartment.
1191  * If the last apartment is freed, the function will additionally release
1192  * any COM resources associated with the process.
1193  *
1194  * PARAMS
1195  *
1196  * RETURNS
1197  *  Nothing.
1198  *
1199  * SEE ALSO
1200  *   CoInitializeEx
1201  */
1202 void WINAPI CoUninitialize(void)
1203 {
1204   struct oletls * info = COM_CurrentInfo();
1205   LONG lCOMRefCnt;
1206
1207   TRACE("()\n");
1208
1209   /* will only happen on OOM */
1210   if (!info) return;
1211
1212   if (info->spy)
1213       IInitializeSpy_PreUninitialize(info->spy, info->inits);
1214
1215   /* sanity check */
1216   if (!info->inits)
1217   {
1218     ERR("Mismatched CoUninitialize\n");
1219
1220     if (info->spy)
1221         IInitializeSpy_PostUninitialize(info->spy, info->inits);
1222     return;
1223   }
1224
1225   if (!--info->inits)
1226   {
1227     apartment_release(info->apt);
1228     info->apt = NULL;
1229   }
1230
1231   /*
1232    * Decrease the reference count.
1233    * If we are back to 0 locks on the COM library, make sure we free
1234    * all the associated data structures.
1235    */
1236   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
1237   if (lCOMRefCnt==1)
1238   {
1239     TRACE("() - Releasing the COM libraries\n");
1240
1241     RunningObjectTableImpl_UnInitialize();
1242   }
1243   else if (lCOMRefCnt<1) {
1244     ERR( "CoUninitialize() - not CoInitialized.\n" );
1245     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
1246   }
1247   if (info->spy)
1248       IInitializeSpy_PostUninitialize(info->spy, info->inits);
1249 }
1250
1251 /******************************************************************************
1252  *              CoDisconnectObject      [OLE32.@]
1253  *
1254  * Disconnects all connections to this object from remote processes. Dispatches
1255  * pending RPCs while blocking new RPCs from occurring, and then calls
1256  * IMarshal::DisconnectObject on the given object.
1257  *
1258  * Typically called when the object server is forced to shut down, for instance by
1259  * the user.
1260  *
1261  * PARAMS
1262  *  lpUnk    [I] The object whose stub should be disconnected.
1263  *  reserved [I] Reserved. Should be set to 0.
1264  *
1265  * RETURNS
1266  *  Success: S_OK.
1267  *  Failure: HRESULT code.
1268  *
1269  * SEE ALSO
1270  *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
1271  */
1272 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
1273 {
1274     HRESULT hr;
1275     IMarshal *marshal;
1276     APARTMENT *apt;
1277
1278     TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1279
1280     hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
1281     if (hr == S_OK)
1282     {
1283         hr = IMarshal_DisconnectObject(marshal, reserved);
1284         IMarshal_Release(marshal);
1285         return hr;
1286     }
1287
1288     apt = COM_CurrentApt();
1289     if (!apt)
1290         return CO_E_NOTINITIALIZED;
1291
1292     apartment_disconnectobject(apt, lpUnk);
1293
1294     /* Note: native is pretty broken here because it just silently
1295      * fails, without returning an appropriate error code if the object was
1296      * not found, making apps think that the object was disconnected, when
1297      * it actually wasn't */
1298
1299     return S_OK;
1300 }
1301
1302 /******************************************************************************
1303  *              CoCreateGuid [OLE32.@]
1304  *              CoCreateGuid [COMPOBJ.73]
1305  *
1306  * Simply forwards to UuidCreate in RPCRT4.
1307  *
1308  * PARAMS
1309  *  pguid [O] Points to the GUID to initialize.
1310  *
1311  * RETURNS
1312  *  Success: S_OK.
1313  *  Failure: HRESULT code.
1314  *
1315  * SEE ALSO
1316  *   UuidCreate
1317  */
1318 HRESULT WINAPI CoCreateGuid(GUID *pguid)
1319 {
1320     DWORD status = UuidCreate(pguid);
1321     if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
1322     return HRESULT_FROM_WIN32( status );
1323 }
1324
1325 /******************************************************************************
1326  *              CLSIDFromString [OLE32.@]
1327  *              IIDFromString   [OLE32.@]
1328  *
1329  * Converts a unique identifier from its string representation into
1330  * the GUID struct.
1331  *
1332  * PARAMS
1333  *  idstr [I] The string representation of the GUID.
1334  *  id    [O] GUID converted from the string.
1335  *
1336  * RETURNS
1337  *   S_OK on success
1338  *   CO_E_CLASSSTRING if idstr is not a valid CLSID
1339  *
1340  * SEE ALSO
1341  *  StringFromCLSID
1342  */
1343 static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1344 {
1345   int   i;
1346   BYTE table[256];
1347
1348   if (!s) {
1349     memset( id, 0, sizeof (CLSID) );
1350     return S_OK;
1351   }
1352
1353   /* validate the CLSID string */
1354   if (strlenW(s) != 38)
1355     return CO_E_CLASSSTRING;
1356
1357   if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
1358     return CO_E_CLASSSTRING;
1359
1360   for (i=1; i<37; i++) {
1361     if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
1362     if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
1363           ((s[i] >= 'a') && (s[i] <= 'f'))  ||
1364           ((s[i] >= 'A') && (s[i] <= 'F'))))
1365        return CO_E_CLASSSTRING;
1366   }
1367
1368   TRACE("%s -> %p\n", debugstr_w(s), id);
1369
1370   /* quick lookup table */
1371   memset(table, 0, 256);
1372
1373   for (i = 0; i < 10; i++) {
1374     table['0' + i] = i;
1375   }
1376   for (i = 0; i < 6; i++) {
1377     table['A' + i] = i+10;
1378     table['a' + i] = i+10;
1379   }
1380
1381   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
1382
1383   id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
1384                table[s[5]] << 12 | table[s[6]] << 8  | table[s[7]] << 4  | table[s[8]]);
1385   id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
1386   id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
1387
1388   /* these are just sequential bytes */
1389   id->Data4[0] = table[s[20]] << 4 | table[s[21]];
1390   id->Data4[1] = table[s[22]] << 4 | table[s[23]];
1391   id->Data4[2] = table[s[25]] << 4 | table[s[26]];
1392   id->Data4[3] = table[s[27]] << 4 | table[s[28]];
1393   id->Data4[4] = table[s[29]] << 4 | table[s[30]];
1394   id->Data4[5] = table[s[31]] << 4 | table[s[32]];
1395   id->Data4[6] = table[s[33]] << 4 | table[s[34]];
1396   id->Data4[7] = table[s[35]] << 4 | table[s[36]];
1397
1398   return S_OK;
1399 }
1400
1401 /*****************************************************************************/
1402
1403 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1404 {
1405     HRESULT ret;
1406
1407     if (!id)
1408         return E_INVALIDARG;
1409
1410     ret = __CLSIDFromString(idstr, id);
1411     if(ret != S_OK) { /* It appears a ProgID is also valid */
1412         ret = CLSIDFromProgID(idstr, id);
1413     }
1414     return ret;
1415 }
1416
1417 /* Converts a GUID into the respective string representation. */
1418 HRESULT WINE_StringFromCLSID(
1419         const CLSID *id,        /* [in] GUID to be converted */
1420         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
1421 ) {
1422   static const char hex[] = "0123456789ABCDEF";
1423   char *s;
1424   int   i;
1425
1426   if (!id)
1427         { ERR("called with id=Null\n");
1428           *idstr = 0x00;
1429           return E_FAIL;
1430         }
1431
1432   sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
1433           id->Data1, id->Data2, id->Data3,
1434           id->Data4[0], id->Data4[1]);
1435   s = &idstr[25];
1436
1437   /* 6 hex bytes */
1438   for (i = 2; i < 8; i++) {
1439     *s++ = hex[id->Data4[i]>>4];
1440     *s++ = hex[id->Data4[i] & 0xf];
1441   }
1442
1443   *s++ = '}';
1444   *s++ = '\0';
1445
1446   TRACE("%p->%s\n", id, idstr);
1447
1448   return S_OK;
1449 }
1450
1451
1452 /******************************************************************************
1453  *              StringFromCLSID [OLE32.@]
1454  *              StringFromIID   [OLE32.@]
1455  *
1456  * Converts a GUID into the respective string representation.
1457  * The target string is allocated using the OLE IMalloc.
1458  *
1459  * PARAMS
1460  *  id    [I] the GUID to be converted.
1461  *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
1462  *
1463  * RETURNS
1464  *   S_OK
1465  *   E_FAIL
1466  *
1467  * SEE ALSO
1468  *  StringFromGUID2, CLSIDFromString
1469  */
1470 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
1471 {
1472         char            buf[80];
1473         HRESULT       ret;
1474         LPMALLOC        mllc;
1475
1476         if ((ret = CoGetMalloc(0,&mllc)))
1477                 return ret;
1478
1479         ret=WINE_StringFromCLSID(id,buf);
1480         if (ret == S_OK) {
1481             DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
1482             *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
1483             MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
1484         }
1485         return ret;
1486 }
1487
1488 /******************************************************************************
1489  *              StringFromGUID2 [OLE32.@]
1490  *              StringFromGUID2 [COMPOBJ.76]
1491  *
1492  * Modified version of StringFromCLSID that allows you to specify max
1493  * buffer size.
1494  *
1495  * PARAMS
1496  *  id   [I] GUID to convert to string.
1497  *  str  [O] Buffer where the result will be stored.
1498  *  cmax [I] Size of the buffer in characters.
1499  *
1500  * RETURNS
1501  *      Success: The length of the resulting string in characters.
1502  *  Failure: 0.
1503  */
1504 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
1505 {
1506   char          xguid[80];
1507
1508   if (WINE_StringFromCLSID(id,xguid))
1509         return 0;
1510   return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
1511 }
1512
1513 /* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
1514 HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1515 {
1516     static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
1517     WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1518     LONG res;
1519     HKEY key;
1520
1521     strcpyW(path, wszCLSIDSlash);
1522     StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1523     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
1524     if (res == ERROR_FILE_NOT_FOUND)
1525         return REGDB_E_CLASSNOTREG;
1526     else if (res != ERROR_SUCCESS)
1527         return REGDB_E_READREGDB;
1528
1529     if (!keyname)
1530     {
1531         *subkey = key;
1532         return S_OK;
1533     }
1534
1535     res = RegOpenKeyExW(key, keyname, 0, access, subkey);
1536     RegCloseKey(key);
1537     if (res == ERROR_FILE_NOT_FOUND)
1538         return REGDB_E_KEYMISSING;
1539     else if (res != ERROR_SUCCESS)
1540         return REGDB_E_READREGDB;
1541
1542     return S_OK;
1543 }
1544
1545 /* open HKCR\\AppId\\{string form of appid clsid} key */
1546 HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
1547 {
1548     static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
1549     static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
1550     DWORD res;
1551     WCHAR buf[CHARS_IN_GUID];
1552     WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
1553     DWORD size;
1554     HKEY hkey;
1555     DWORD type;
1556     HRESULT hr;
1557
1558     /* read the AppID value under the class's key */
1559     hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1560     if (FAILED(hr))
1561         return hr;
1562
1563     size = sizeof(buf);
1564     res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1565     RegCloseKey(hkey);
1566     if (res == ERROR_FILE_NOT_FOUND)
1567         return REGDB_E_KEYMISSING;
1568     else if (res != ERROR_SUCCESS || type!=REG_SZ)
1569         return REGDB_E_READREGDB;
1570
1571     strcpyW(keyname, szAppIdKey);
1572     strcatW(keyname, buf);
1573     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1574     if (res == ERROR_FILE_NOT_FOUND)
1575         return REGDB_E_KEYMISSING;
1576     else if (res != ERROR_SUCCESS)
1577         return REGDB_E_READREGDB;
1578
1579     return S_OK;
1580 }
1581
1582 /******************************************************************************
1583  *               ProgIDFromCLSID [OLE32.@]
1584  *
1585  * Converts a class id into the respective program ID.
1586  *
1587  * PARAMS
1588  *  clsid        [I] Class ID, as found in registry.
1589  *  ppszProgID [O] Associated ProgID.
1590  *
1591  * RETURNS
1592  *   S_OK
1593  *   E_OUTOFMEMORY
1594  *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1595  */
1596 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1597 {
1598     static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
1599     HKEY     hkey;
1600     HRESULT  ret;
1601     LONG progidlen = 0;
1602
1603     if (!ppszProgID)
1604     {
1605         ERR("ppszProgId isn't optional\n");
1606         return E_INVALIDARG;
1607     }
1608
1609     *ppszProgID = NULL;
1610     ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
1611     if (FAILED(ret))
1612         return ret;
1613
1614     if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1615       ret = REGDB_E_CLASSNOTREG;
1616
1617     if (ret == S_OK)
1618     {
1619       *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
1620       if (*ppszProgID)
1621       {
1622         if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1623           ret = REGDB_E_CLASSNOTREG;
1624       }
1625       else
1626         ret = E_OUTOFMEMORY;
1627     }
1628
1629     RegCloseKey(hkey);
1630     return ret;
1631 }
1632
1633 /******************************************************************************
1634  *              CLSIDFromProgID [OLE32.@]
1635  *
1636  * Converts a program id into the respective GUID.
1637  *
1638  * PARAMS
1639  *  progid [I] Unicode program ID, as found in registry.
1640  *  clsid  [O] Associated CLSID.
1641  *
1642  * RETURNS
1643  *      Success: S_OK
1644  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1645  */
1646 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1647 {
1648     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1649     WCHAR buf2[CHARS_IN_GUID];
1650     LONG buf2len = sizeof(buf2);
1651     HKEY xhkey;
1652     WCHAR *buf;
1653
1654     if (!progid || !clsid)
1655     {
1656         ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
1657         return E_INVALIDARG;
1658     }
1659
1660     /* initialise clsid in case of failure */
1661     memset(clsid, 0, sizeof(*clsid));
1662
1663     buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1664     strcpyW( buf, progid );
1665     strcatW( buf, clsidW );
1666     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1667     {
1668         HeapFree(GetProcessHeap(),0,buf);
1669         WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1670         return CO_E_CLASSSTRING;
1671     }
1672     HeapFree(GetProcessHeap(),0,buf);
1673
1674     if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1675     {
1676         RegCloseKey(xhkey);
1677         WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1678         return CO_E_CLASSSTRING;
1679     }
1680     RegCloseKey(xhkey);
1681     return CLSIDFromString(buf2,clsid);
1682 }
1683
1684
1685 /*****************************************************************************
1686  *             CoGetPSClsid [OLE32.@]
1687  *
1688  * Retrieves the CLSID of the proxy/stub factory that implements
1689  * IPSFactoryBuffer for the specified interface.
1690  *
1691  * PARAMS
1692  *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
1693  *  pclsid [O] Where to store returned proxy/stub CLSID.
1694  * 
1695  * RETURNS
1696  *   S_OK
1697  *   E_OUTOFMEMORY
1698  *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1699  *
1700  * NOTES
1701  *
1702  * The standard marshaller activates the object with the CLSID
1703  * returned and uses the CreateProxy and CreateStub methods on its
1704  * IPSFactoryBuffer interface to construct the proxies and stubs for a
1705  * given object.
1706  *
1707  * CoGetPSClsid determines this CLSID by searching the
1708  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1709  * in the registry and any interface id registered by
1710  * CoRegisterPSClsid within the current process.
1711  *
1712  * BUGS
1713  *
1714  * Native returns S_OK for interfaces with a key in HKCR\Interface, but
1715  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1716  * considered a bug in native unless an application depends on this (unlikely).
1717  *
1718  * SEE ALSO
1719  *  CoRegisterPSClsid.
1720  */
1721 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1722 {
1723     static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
1724     static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
1725     WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
1726     WCHAR value[CHARS_IN_GUID];
1727     LONG len;
1728     HKEY hkey;
1729     APARTMENT *apt = COM_CurrentApt();
1730     struct registered_psclsid *registered_psclsid;
1731
1732     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1733
1734     if (!apt)
1735     {
1736         ERR("apartment not initialised\n");
1737         return CO_E_NOTINITIALIZED;
1738     }
1739
1740     if (!pclsid)
1741     {
1742         ERR("pclsid isn't optional\n");
1743         return E_INVALIDARG;
1744     }
1745
1746     EnterCriticalSection(&apt->cs);
1747
1748     LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1749         if (IsEqualIID(&registered_psclsid->iid, riid))
1750         {
1751             *pclsid = registered_psclsid->clsid;
1752             LeaveCriticalSection(&apt->cs);
1753             return S_OK;
1754         }
1755
1756     LeaveCriticalSection(&apt->cs);
1757
1758     /* Interface\\{string form of riid}\\ProxyStubClsid32 */
1759     strcpyW(path, wszInterface);
1760     StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
1761     strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1762
1763     /* Open the key.. */
1764     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1765     {
1766         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1767         return REGDB_E_IIDNOTREG;
1768     }
1769
1770     /* ... Once we have the key, query the registry to get the
1771        value of CLSID as a string, and convert it into a
1772        proper CLSID structure to be passed back to the app */
1773     len = sizeof(value);
1774     if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1775     {
1776         RegCloseKey(hkey);
1777         return REGDB_E_IIDNOTREG;
1778     }
1779     RegCloseKey(hkey);
1780
1781     /* We have the CLSID we want back from the registry as a string, so
1782        let's convert it into a CLSID structure */
1783     if (CLSIDFromString(value, pclsid) != NOERROR)
1784         return REGDB_E_IIDNOTREG;
1785
1786     TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1787     return S_OK;
1788 }
1789
1790 /*****************************************************************************
1791  *             CoRegisterPSClsid [OLE32.@]
1792  *
1793  * Register a proxy/stub CLSID for the given interface in the current process
1794  * only.
1795  *
1796  * PARAMS
1797  *  riid   [I] Interface whose proxy/stub CLSID is to be registered.
1798  *  rclsid [I] CLSID of the proxy/stub.
1799  * 
1800  * RETURNS
1801  *   Success: S_OK
1802  *   Failure: E_OUTOFMEMORY
1803  *
1804  * NOTES
1805  *
1806  * This function does not add anything to the registry and the effects are
1807  * limited to the lifetime of the current process.
1808  *
1809  * SEE ALSO
1810  *  CoGetPSClsid.
1811  */
1812 HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
1813 {
1814     APARTMENT *apt = COM_CurrentApt();
1815     struct registered_psclsid *registered_psclsid;
1816
1817     TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));
1818
1819     if (!apt)
1820     {
1821         ERR("apartment not initialised\n");
1822         return CO_E_NOTINITIALIZED;
1823     }
1824
1825     EnterCriticalSection(&apt->cs);
1826
1827     LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
1828         if (IsEqualIID(&registered_psclsid->iid, riid))
1829         {
1830             registered_psclsid->clsid = *rclsid;
1831             LeaveCriticalSection(&apt->cs);
1832             return S_OK;
1833         }
1834
1835     registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
1836     if (!registered_psclsid)
1837     {
1838         LeaveCriticalSection(&apt->cs);
1839         return E_OUTOFMEMORY;
1840     }
1841
1842     registered_psclsid->iid = *riid;
1843     registered_psclsid->clsid = *rclsid;
1844     list_add_head(&apt->psclsids, &registered_psclsid->entry);
1845
1846     LeaveCriticalSection(&apt->cs);
1847
1848     return S_OK;
1849 }
1850
1851
1852 /***
1853  * COM_GetRegisteredClassObject
1854  *
1855  * This internal method is used to scan the registered class list to
1856  * find a class object.
1857  *
1858  * Params:
1859  *   rclsid        Class ID of the class to find.
1860  *   dwClsContext  Class context to match.
1861  *   ppv           [out] returns a pointer to the class object. Complying
1862  *                 to normal COM usage, this method will increase the
1863  *                 reference count on this object.
1864  */
1865 static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
1866                                             DWORD dwClsContext, LPUNKNOWN* ppUnk)
1867 {
1868   HRESULT hr = S_FALSE;
1869   RegisteredClass *curClass;
1870
1871   EnterCriticalSection( &csRegisteredClassList );
1872
1873   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1874   {
1875     /*
1876      * Check if we have a match on the class ID and context.
1877      */
1878     if ((apt->oxid == curClass->apartment_id) &&
1879         (dwClsContext & curClass->runContext) &&
1880         IsEqualGUID(&(curClass->classIdentifier), rclsid))
1881     {
1882       /*
1883        * We have a match, return the pointer to the class object.
1884        */
1885       *ppUnk = curClass->classObject;
1886
1887       IUnknown_AddRef(curClass->classObject);
1888
1889       hr = S_OK;
1890       break;
1891     }
1892   }
1893
1894   LeaveCriticalSection( &csRegisteredClassList );
1895
1896   return hr;
1897 }
1898
1899 /******************************************************************************
1900  *              CoRegisterClassObject   [OLE32.@]
1901  *
1902  * Registers the class object for a given class ID. Servers housed in EXE
1903  * files use this method instead of exporting DllGetClassObject to allow
1904  * other code to connect to their objects.
1905  *
1906  * PARAMS
1907  *  rclsid       [I] CLSID of the object to register.
1908  *  pUnk         [I] IUnknown of the object.
1909  *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1910  *  flags        [I] REGCLS flags indicating how connections are made.
1911  *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1912  *
1913  * RETURNS
1914  *   S_OK on success,
1915  *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
1916  *   CO_E_OBJISREG if the object is already registered. We should not return this.
1917  *
1918  * SEE ALSO
1919  *   CoRevokeClassObject, CoGetClassObject
1920  *
1921  * NOTES
1922  *  In-process objects are only registered for the current apartment.
1923  *  CoGetClassObject() and CoCreateInstance() will not return objects registered
1924  *  in other apartments.
1925  *
1926  * BUGS
1927  *  MSDN claims that multiple interface registrations are legal, but we
1928  *  can't do that with our current implementation.
1929  */
1930 HRESULT WINAPI CoRegisterClassObject(
1931     REFCLSID rclsid,
1932     LPUNKNOWN pUnk,
1933     DWORD dwClsContext,
1934     DWORD flags,
1935     LPDWORD lpdwRegister)
1936 {
1937   RegisteredClass* newClass;
1938   LPUNKNOWN        foundObject;
1939   HRESULT          hr;
1940   APARTMENT *apt;
1941
1942   TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1943         debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1944
1945   if ( (lpdwRegister==0) || (pUnk==0) )
1946     return E_INVALIDARG;
1947
1948   apt = COM_CurrentApt();
1949   if (!apt)
1950   {
1951       ERR("COM was not initialized\n");
1952       return CO_E_NOTINITIALIZED;
1953   }
1954
1955   *lpdwRegister = 0;
1956
1957   /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
1958    * differentiates the flag from REGCLS_MULTI_SEPARATE. */
1959   if (flags & REGCLS_MULTIPLEUSE)
1960     dwClsContext |= CLSCTX_INPROC_SERVER;
1961
1962   /*
1963    * First, check if the class is already registered.
1964    * If it is, this should cause an error.
1965    */
1966   hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1967   if (hr == S_OK) {
1968     if (flags & REGCLS_MULTIPLEUSE) {
1969       if (dwClsContext & CLSCTX_LOCAL_SERVER)
1970         hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
1971       IUnknown_Release(foundObject);
1972       return hr;
1973     }
1974     IUnknown_Release(foundObject);
1975     ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1976     return CO_E_OBJISREG;
1977   }
1978
1979   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1980   if ( newClass == NULL )
1981     return E_OUTOFMEMORY;
1982
1983   newClass->classIdentifier = *rclsid;
1984   newClass->apartment_id    = apt->oxid;
1985   newClass->runContext      = dwClsContext;
1986   newClass->connectFlags    = flags;
1987   newClass->pMarshaledData  = NULL;
1988   newClass->RpcRegistration = NULL;
1989
1990   /*
1991    * Use the address of the chain node as the cookie since we are sure it's
1992    * unique. FIXME: not on 64-bit platforms.
1993    */
1994   newClass->dwCookie        = (DWORD)newClass;
1995
1996   /*
1997    * Since we're making a copy of the object pointer, we have to increase its
1998    * reference count.
1999    */
2000   newClass->classObject     = pUnk;
2001   IUnknown_AddRef(newClass->classObject);
2002
2003   EnterCriticalSection( &csRegisteredClassList );
2004   list_add_tail(&RegisteredClassList, &newClass->entry);
2005   LeaveCriticalSection( &csRegisteredClassList );
2006
2007   *lpdwRegister = newClass->dwCookie;
2008
2009   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2010       hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
2011       if (hr) {
2012           FIXME("Failed to create stream on hglobal, %x\n", hr);
2013           return hr;
2014       }
2015       hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
2016                               newClass->classObject, MSHCTX_LOCAL, NULL,
2017                               MSHLFLAGS_TABLESTRONG);
2018       if (hr) {
2019           FIXME("CoMarshalInterface failed, %x!\n",hr);
2020           return hr;
2021       }
2022
2023       hr = RPC_StartLocalServer(&newClass->classIdentifier,
2024                                 newClass->pMarshaledData,
2025                                 flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2026                                 &newClass->RpcRegistration);
2027   }
2028   return S_OK;
2029 }
2030
2031 static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
2032 {
2033     list_remove(&curClass->entry);
2034
2035     if (curClass->runContext & CLSCTX_LOCAL_SERVER)
2036         RPC_StopLocalServer(curClass->RpcRegistration);
2037
2038     /*
2039      * Release the reference to the class object.
2040      */
2041     IUnknown_Release(curClass->classObject);
2042
2043     if (curClass->pMarshaledData)
2044     {
2045         LARGE_INTEGER zero;
2046         memset(&zero, 0, sizeof(zero));
2047         IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
2048         CoReleaseMarshalData(curClass->pMarshaledData);
2049         IStream_Release(curClass->pMarshaledData);
2050     }
2051
2052     HeapFree(GetProcessHeap(), 0, curClass);
2053 }
2054
2055 static void COM_RevokeAllClasses(const struct apartment *apt)
2056 {
2057   RegisteredClass *curClass, *cursor;
2058
2059   EnterCriticalSection( &csRegisteredClassList );
2060
2061   LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
2062   {
2063     if (curClass->apartment_id == apt->oxid)
2064       COM_RevokeRegisteredClassObject(curClass);
2065   }
2066
2067   LeaveCriticalSection( &csRegisteredClassList );
2068 }
2069
2070 /***********************************************************************
2071  *           CoRevokeClassObject [OLE32.@]
2072  *
2073  * Removes a class object from the class registry.
2074  *
2075  * PARAMS
2076  *  dwRegister [I] Cookie returned from CoRegisterClassObject().
2077  *
2078  * RETURNS
2079  *  Success: S_OK.
2080  *  Failure: HRESULT code.
2081  *
2082  * NOTES
2083  *  Must be called from the same apartment that called CoRegisterClassObject(),
2084  *  otherwise it will fail with RPC_E_WRONG_THREAD.
2085  *
2086  * SEE ALSO
2087  *  CoRegisterClassObject
2088  */
2089 HRESULT WINAPI CoRevokeClassObject(
2090         DWORD dwRegister)
2091 {
2092   HRESULT hr = E_INVALIDARG;
2093   RegisteredClass *curClass;
2094   APARTMENT *apt;
2095
2096   TRACE("(%08x)\n",dwRegister);
2097
2098   apt = COM_CurrentApt();
2099   if (!apt)
2100   {
2101     ERR("COM was not initialized\n");
2102     return CO_E_NOTINITIALIZED;
2103   }
2104
2105   EnterCriticalSection( &csRegisteredClassList );
2106
2107   LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2108   {
2109     /*
2110      * Check if we have a match on the cookie.
2111      */
2112     if (curClass->dwCookie == dwRegister)
2113     {
2114       if (curClass->apartment_id == apt->oxid)
2115       {
2116           COM_RevokeRegisteredClassObject(curClass);
2117           hr = S_OK;
2118       }
2119       else
2120       {
2121           ERR("called from wrong apartment, should be called from %s\n",
2122               wine_dbgstr_longlong(curClass->apartment_id));
2123           hr = RPC_E_WRONG_THREAD;
2124       }
2125       break;
2126     }
2127   }
2128
2129   LeaveCriticalSection( &csRegisteredClassList );
2130
2131   return hr;
2132 }
2133
2134 /***********************************************************************
2135  *      COM_RegReadPath [internal]
2136  *
2137  *      Reads a registry value and expands it when necessary
2138  */
2139 static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2140 {
2141         DWORD ret;
2142         HKEY key;
2143         DWORD keytype;
2144         WCHAR src[MAX_PATH];
2145         DWORD dwLength = dstlen * sizeof(WCHAR);
2146
2147         if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
2148           if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2149             if (keytype == REG_EXPAND_SZ) {
2150               if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2151             } else {
2152               lstrcpynW(dst, src, dstlen);
2153             }
2154           }
2155           RegCloseKey (key);
2156         }
2157         return ret;
2158 }
2159
2160 static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
2161 {
2162     static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
2163     DWORD keytype;
2164     DWORD ret;
2165     DWORD dwLength = len * sizeof(WCHAR);
2166
2167     ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
2168     if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
2169         value[0] = '\0';
2170 }
2171
2172 static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2173                                        REFCLSID rclsid, REFIID riid,
2174                                        BOOL hostifnecessary, void **ppv)
2175 {
2176     WCHAR dllpath[MAX_PATH+1];
2177     BOOL apartment_threaded;
2178
2179     if (hostifnecessary)
2180     {
2181         static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
2182         static const WCHAR wszFree[] = {'F','r','e','e',0};
2183         static const WCHAR wszBoth[] = {'B','o','t','h',0};
2184         WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];
2185
2186         get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
2187         /* "Apartment" */
2188         if (!strcmpiW(threading_model, wszApartment))
2189         {
2190             apartment_threaded = TRUE;
2191             if (apt->multi_threaded)
2192                 return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
2193         }
2194         /* "Free" */
2195         else if (!strcmpiW(threading_model, wszFree))
2196         {
2197             apartment_threaded = FALSE;
2198             if (!apt->multi_threaded)
2199                 return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
2200         }
2201         /* everything except "Apartment", "Free" and "Both" */
2202         else if (strcmpiW(threading_model, wszBoth))
2203         {
2204             apartment_threaded = TRUE;
2205             /* everything else is main-threaded */
2206             if (threading_model[0])
2207                 FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
2208                     debugstr_w(threading_model), debugstr_guid(rclsid));
2209
2210             if (apt->multi_threaded || !apt->main)
2211                 return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
2212         }
2213         else
2214             apartment_threaded = FALSE;
2215     }
2216     else
2217         apartment_threaded = !apt->multi_threaded;
2218
2219     if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
2220     {
2221         /* failure: CLSID is not found in registry */
2222         WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
2223         return REGDB_E_CLASSNOTREG;
2224     }
2225
2226     return apartment_getclassobject(apt, dllpath, apartment_threaded,
2227                                     rclsid, riid, ppv);
2228 }
2229
2230 /***********************************************************************
2231  *           CoGetClassObject [OLE32.@]
2232  *
2233  * Creates an object of the specified class.
2234  *
2235  * PARAMS
2236  *  rclsid       [I] Class ID to create an instance of.
2237  *  dwClsContext [I] Flags to restrict the location of the created instance.
2238  *  pServerInfo  [I] Optional. Details for connecting to a remote server.
2239  *  iid          [I] The ID of the interface of the instance to return.
2240  *  ppv          [O] On returns, contains a pointer to the specified interface of the object.
2241  *
2242  * RETURNS
2243  *  Success: S_OK
2244  *  Failure: HRESULT code.
2245  *
2246  * NOTES
2247  *  The dwClsContext parameter can be one or more of the following:
2248  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2249  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2250  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2251  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2252  *
2253  * SEE ALSO
2254  *  CoCreateInstance()
2255  */
2256 HRESULT WINAPI CoGetClassObject(
2257     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2258     REFIID iid, LPVOID *ppv)
2259 {
2260     LPUNKNOWN   regClassObject;
2261     HRESULT     hres = E_UNEXPECTED;
2262     APARTMENT  *apt;
2263
2264     TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
2265
2266     if (!ppv)
2267         return E_INVALIDARG;
2268
2269     *ppv = NULL;
2270
2271     apt = COM_CurrentApt();
2272     if (!apt)
2273     {
2274         ERR("apartment not initialised\n");
2275         return CO_E_NOTINITIALIZED;
2276     }
2277
2278     if (pServerInfo) {
2279         FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
2280         FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
2281     }
2282
2283     /*
2284      * First, try and see if we can't match the class ID with one of the
2285      * registered classes.
2286      */
2287     if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
2288                                              &regClassObject))
2289     {
2290       /* Get the required interface from the retrieved pointer. */
2291       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
2292
2293       /*
2294        * Since QI got another reference on the pointer, we want to release the
2295        * one we already have. If QI was unsuccessful, this will release the object. This
2296        * is good since we are not returning it in the "out" parameter.
2297        */
2298       IUnknown_Release(regClassObject);
2299
2300       return hres;
2301     }
2302
2303     /* First try in-process server */
2304     if (CLSCTX_INPROC_SERVER & dwClsContext)
2305     {
2306         static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
2307         HKEY hkey;
2308
2309         if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2310             return FTMarshalCF_Create(iid, ppv);
2311
2312         hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
2313         if (FAILED(hres))
2314         {
2315             if (hres == REGDB_E_CLASSNOTREG)
2316                 ERR("class %s not registered\n", debugstr_guid(rclsid));
2317             else if (hres == REGDB_E_KEYMISSING)
2318             {
2319                 WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2320                 hres = REGDB_E_CLASSNOTREG;
2321             }
2322         }
2323
2324         if (SUCCEEDED(hres))
2325         {
2326             hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2327                 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2328             RegCloseKey(hkey);
2329         }
2330
2331         /* return if we got a class, otherwise fall through to one of the
2332          * other types */
2333         if (SUCCEEDED(hres))
2334             return hres;
2335     }
2336
2337     /* Next try in-process handler */
2338     if (CLSCTX_INPROC_HANDLER & dwClsContext)
2339     {
2340         static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
2341         HKEY hkey;
2342
2343         hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
2344         if (FAILED(hres))
2345         {
2346             if (hres == REGDB_E_CLASSNOTREG)
2347                 ERR("class %s not registered\n", debugstr_guid(rclsid));
2348             else if (hres == REGDB_E_KEYMISSING)
2349             {
2350                 WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2351                 hres = REGDB_E_CLASSNOTREG;
2352             }
2353         }
2354
2355         if (SUCCEEDED(hres))
2356         {
2357             hres = get_inproc_class_object(apt, hkey, rclsid, iid,
2358                 !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2359             RegCloseKey(hkey);
2360         }
2361
2362         /* return if we got a class, otherwise fall through to one of the
2363          * other types */
2364         if (SUCCEEDED(hres))
2365             return hres;
2366     }
2367
2368     /* Next try out of process */
2369     if (CLSCTX_LOCAL_SERVER & dwClsContext)
2370     {
2371         hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
2372         if (SUCCEEDED(hres))
2373             return hres;
2374     }
2375
2376     /* Finally try remote: this requires networked DCOM (a lot of work) */
2377     if (CLSCTX_REMOTE_SERVER & dwClsContext)
2378     {
2379         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2380         hres = E_NOINTERFACE;
2381     }
2382
2383     if (FAILED(hres))
2384         ERR("no class object %s could be created for context 0x%x\n",
2385             debugstr_guid(rclsid), dwClsContext);
2386     return hres;
2387 }
2388
2389 /***********************************************************************
2390  *        CoResumeClassObjects (OLE32.@)
2391  *
2392  * Resumes all class objects registered with REGCLS_SUSPENDED.
2393  *
2394  * RETURNS
2395  *  Success: S_OK.
2396  *  Failure: HRESULT code.
2397  */
2398 HRESULT WINAPI CoResumeClassObjects(void)
2399 {
2400        FIXME("stub\n");
2401         return S_OK;
2402 }
2403
2404 /***********************************************************************
2405  *           CoCreateInstance [OLE32.@]
2406  *
2407  * Creates an instance of the specified class.
2408  *
2409  * PARAMS
2410  *  rclsid       [I] Class ID to create an instance of.
2411  *  pUnkOuter    [I] Optional outer unknown to allow aggregation with another object.
2412  *  dwClsContext [I] Flags to restrict the location of the created instance.
2413  *  iid          [I] The ID of the interface of the instance to return.
2414  *  ppv          [O] On returns, contains a pointer to the specified interface of the instance.
2415  *
2416  * RETURNS
2417  *  Success: S_OK
2418  *  Failure: HRESULT code.
2419  *
2420  * NOTES
2421  *  The dwClsContext parameter can be one or more of the following:
2422  *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
2423  *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
2424  *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
2425  *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
2426  *
2427  * Aggregation is the concept of deferring the IUnknown of an object to another
2428  * object. This allows a separate object to behave as though it was part of
2429  * the object and to allow this the pUnkOuter parameter can be set. Note that
2430  * not all objects support having an outer of unknown.
2431  *
2432  * SEE ALSO
2433  *  CoGetClassObject()
2434  */
2435 HRESULT WINAPI CoCreateInstance(
2436         REFCLSID rclsid,
2437         LPUNKNOWN pUnkOuter,
2438         DWORD dwClsContext,
2439         REFIID iid,
2440         LPVOID *ppv)
2441 {
2442   HRESULT hres;
2443   LPCLASSFACTORY lpclf = 0;
2444
2445   TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2446         pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);
2447
2448   /*
2449    * Sanity check
2450    */
2451   if (ppv==0)
2452     return E_POINTER;
2453
2454   /*
2455    * Initialize the "out" parameter
2456    */
2457   *ppv = 0;
2458
2459   if (!COM_CurrentApt())
2460   {
2461       ERR("apartment not initialised\n");
2462       return CO_E_NOTINITIALIZED;
2463   }
2464
2465   /*
2466    * The Standard Global Interface Table (GIT) object is a process-wide singleton.
2467    * Rather than create a class factory, we can just check for it here
2468    */
2469   if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2470     if (StdGlobalInterfaceTableInstance == NULL)
2471       StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
2472     hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
2473     if (hres) return hres;
2474
2475     TRACE("Retrieved GIT (%p)\n", *ppv);
2476     return S_OK;
2477   }
2478
2479   /*
2480    * Get a class factory to construct the object we want.
2481    */
2482   hres = CoGetClassObject(rclsid,
2483                           dwClsContext,
2484                           NULL,
2485                           &IID_IClassFactory,
2486                           (LPVOID)&lpclf);
2487
2488   if (FAILED(hres))
2489     return hres;
2490
2491   /*
2492    * Create the object and don't forget to release the factory
2493    */
2494         hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
2495         IClassFactory_Release(lpclf);
2496         if(FAILED(hres))
2497         {
2498           if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
2499               FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
2500           else
2501               FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
2502         }
2503
2504         return hres;
2505 }
2506
2507 /***********************************************************************
2508  *           CoCreateInstanceEx [OLE32.@]
2509  */
2510 HRESULT WINAPI CoCreateInstanceEx(
2511   REFCLSID      rclsid,
2512   LPUNKNOWN     pUnkOuter,
2513   DWORD         dwClsContext,
2514   COSERVERINFO* pServerInfo,
2515   ULONG         cmq,
2516   MULTI_QI*     pResults)
2517 {
2518   IUnknown* pUnk = NULL;
2519   HRESULT   hr;
2520   ULONG     index;
2521   ULONG     successCount = 0;
2522
2523   /*
2524    * Sanity check
2525    */
2526   if ( (cmq==0) || (pResults==NULL))
2527     return E_INVALIDARG;
2528
2529   if (pServerInfo!=NULL)
2530     FIXME("() non-NULL pServerInfo not supported!\n");
2531
2532   /*
2533    * Initialize all the "out" parameters.
2534    */
2535   for (index = 0; index < cmq; index++)
2536   {
2537     pResults[index].pItf = NULL;
2538     pResults[index].hr   = E_NOINTERFACE;
2539   }
2540
2541   /*
2542    * Get the object and get its IUnknown pointer.
2543    */
2544   hr = CoCreateInstance(rclsid,
2545                         pUnkOuter,
2546                         dwClsContext,
2547                         &IID_IUnknown,
2548                         (VOID**)&pUnk);
2549
2550   if (hr)
2551     return hr;
2552
2553   /*
2554    * Then, query for all the interfaces requested.
2555    */
2556   for (index = 0; index < cmq; index++)
2557   {
2558     pResults[index].hr = IUnknown_QueryInterface(pUnk,
2559                                                  pResults[index].pIID,
2560                                                  (VOID**)&(pResults[index].pItf));
2561
2562     if (pResults[index].hr == S_OK)
2563       successCount++;
2564   }
2565
2566   /*
2567    * Release our temporary unknown pointer.
2568    */
2569   IUnknown_Release(pUnk);
2570
2571   if (successCount == 0)
2572     return E_NOINTERFACE;
2573
2574   if (successCount!=cmq)
2575     return CO_S_NOTALLINTERFACES;
2576
2577   return S_OK;
2578 }
2579
2580 /***********************************************************************
2581  *           CoLoadLibrary (OLE32.@)
2582  *
2583  * Loads a library.
2584  *
2585  * PARAMS
2586  *  lpszLibName [I] Path to library.
2587  *  bAutoFree   [I] Whether the library should automatically be freed.
2588  *
2589  * RETURNS
2590  *  Success: Handle to loaded library.
2591  *  Failure: NULL.
2592  *
2593  * SEE ALSO
2594  *  CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2595  */
2596 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
2597 {
2598     TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2599
2600     return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
2601 }
2602
2603 /***********************************************************************
2604  *           CoFreeLibrary [OLE32.@]
2605  *
2606  * Unloads a library from memory.
2607  *
2608  * PARAMS
2609  *  hLibrary [I] Handle to library to unload.
2610  *
2611  * RETURNS
2612  *  Nothing
2613  *
2614  * SEE ALSO
2615  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2616  */
2617 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
2618 {
2619     FreeLibrary(hLibrary);
2620 }
2621
2622
2623 /***********************************************************************
2624  *           CoFreeAllLibraries [OLE32.@]
2625  *
2626  * Function for backwards compatibility only. Does nothing.
2627  *
2628  * RETURNS
2629  *  Nothing.
2630  *
2631  * SEE ALSO
2632  *  CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2633  */
2634 void WINAPI CoFreeAllLibraries(void)
2635 {
2636     /* NOP */
2637 }
2638
2639 /***********************************************************************
2640  *           CoFreeUnusedLibrariesEx [OLE32.@]
2641  *
2642  * Frees any previously unused libraries whose delay has expired and marks
2643  * currently unused libraries for unloading. Unused are identified as those that
2644  * return S_OK from their DllCanUnloadNow function.
2645  *
2646  * PARAMS
2647  *  dwUnloadDelay [I] Unload delay in milliseconds.
2648  *  dwReserved    [I] Reserved. Set to 0.
2649  *
2650  * RETURNS
2651  *  Nothing.
2652  *
2653  * SEE ALSO
2654  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2655  */
2656 void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
2657 {
2658     struct apartment *apt = COM_CurrentApt();
2659     if (!apt)
2660     {
2661         ERR("apartment not initialised\n");
2662         return;
2663     }
2664
2665     apartment_freeunusedlibraries(apt, dwUnloadDelay);
2666 }
2667
2668 /***********************************************************************
2669  *           CoFreeUnusedLibraries [OLE32.@]
2670  *           CoFreeUnusedLibraries [COMPOBJ.17]
2671  *
2672  * Frees any unused libraries. Unused are identified as those that return
2673  * S_OK from their DllCanUnloadNow function.
2674  *
2675  * RETURNS
2676  *  Nothing.
2677  *
2678  * SEE ALSO
2679  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
2680  */
2681 void WINAPI CoFreeUnusedLibraries(void)
2682 {
2683     CoFreeUnusedLibrariesEx(INFINITE, 0);
2684 }
2685
2686 /***********************************************************************
2687  *           CoFileTimeNow [OLE32.@]
2688  *           CoFileTimeNow [COMPOBJ.82]
2689  *
2690  * Retrieves the current time in FILETIME format.
2691  *
2692  * PARAMS
2693  *  lpFileTime [O] The current time.
2694  *
2695  * RETURNS
2696  *      S_OK.
2697  */
2698 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2699 {
2700     GetSystemTimeAsFileTime( lpFileTime );
2701     return S_OK;
2702 }
2703
2704 /******************************************************************************
2705  *              CoLockObjectExternal    [OLE32.@]
2706  *
2707  * Increments or decrements the external reference count of a stub object.
2708  *
2709  * PARAMS
2710  *  pUnk                [I] Stub object.
2711  *  fLock               [I] If TRUE then increments the external ref-count,
2712  *                          otherwise decrements.
2713  *  fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2714  *                          calling CoDisconnectObject.
2715  *
2716  * RETURNS
2717  *  Success: S_OK.
2718  *  Failure: HRESULT code.
2719  *
2720  * NOTES
2721  *  If fLock is TRUE and an object is passed in that doesn't have a stub
2722  *  manager then a new stub manager is created for the object.
2723  */
2724 HRESULT WINAPI CoLockObjectExternal(
2725     LPUNKNOWN pUnk,
2726     BOOL fLock,
2727     BOOL fLastUnlockReleases)
2728 {
2729     struct stub_manager *stubmgr;
2730     struct apartment *apt;
2731
2732     TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2733           pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2734
2735     apt = COM_CurrentApt();
2736     if (!apt) return CO_E_NOTINITIALIZED;
2737
2738     stubmgr = get_stub_manager_from_object(apt, pUnk);
2739     
2740     if (stubmgr)
2741     {
2742         if (fLock)
2743             stub_manager_ext_addref(stubmgr, 1, FALSE);
2744         else
2745             stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2746         
2747         stub_manager_int_release(stubmgr);
2748
2749         return S_OK;
2750     }
2751     else if (fLock)
2752     {
2753         stubmgr = new_stub_manager(apt, pUnk);
2754
2755         if (stubmgr)
2756         {
2757             stub_manager_ext_addref(stubmgr, 1, FALSE);
2758             stub_manager_int_release(stubmgr);
2759         }
2760
2761         return S_OK;
2762     }
2763     else
2764     {
2765         WARN("stub object not found %p\n", pUnk);
2766         /* Note: native is pretty broken here because it just silently
2767          * fails, without returning an appropriate error code, making apps
2768          * think that the object was disconnected, when it actually wasn't */
2769         return S_OK;
2770     }
2771 }
2772
2773 /***********************************************************************
2774  *           CoInitializeWOW (OLE32.@)
2775  *
2776  * WOW equivalent of CoInitialize?
2777  *
2778  * PARAMS
2779  *  x [I] Unknown.
2780  *  y [I] Unknown.
2781  *
2782  * RETURNS
2783  *  Unknown.
2784  */
2785 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2786 {
2787     FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2788     return 0;
2789 }
2790
2791 /***********************************************************************
2792  *           CoGetState [OLE32.@]
2793  *
2794  * Retrieves the thread state object previously stored by CoSetState().
2795  *
2796  * PARAMS
2797  *  ppv [I] Address where pointer to object will be stored.
2798  *
2799  * RETURNS
2800  *  Success: S_OK.
2801  *  Failure: E_OUTOFMEMORY.
2802  *
2803  * NOTES
2804  *  Crashes on all invalid ppv addresses, including NULL.
2805  *  If the function returns a non-NULL object then the caller must release its
2806  *  reference on the object when the object is no longer required.
2807  *
2808  * SEE ALSO
2809  *  CoSetState().
2810  */
2811 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2812 {
2813     struct oletls *info = COM_CurrentInfo();
2814     if (!info) return E_OUTOFMEMORY;
2815
2816     *ppv = NULL;
2817
2818     if (info->state)
2819     {
2820         IUnknown_AddRef(info->state);
2821         *ppv = info->state;
2822         TRACE("apt->state=%p\n", info->state);
2823     }
2824
2825     return S_OK;
2826 }
2827
2828 /***********************************************************************
2829  *           CoSetState [OLE32.@]
2830  *
2831  * Sets the thread state object.
2832  *
2833  * PARAMS
2834  *  pv [I] Pointer to state object to be stored.
2835  *
2836  * NOTES
2837  *  The system keeps a reference on the object while the object stored.
2838  *
2839  * RETURNS
2840  *  Success: S_OK.
2841  *  Failure: E_OUTOFMEMORY.
2842  */
2843 HRESULT WINAPI CoSetState(IUnknown * pv)
2844 {
2845     struct oletls *info = COM_CurrentInfo();
2846     if (!info) return E_OUTOFMEMORY;
2847
2848     if (pv) IUnknown_AddRef(pv);
2849
2850     if (info->state)
2851     {
2852         TRACE("-- release %p now\n", info->state);
2853         IUnknown_Release(info->state);
2854     }
2855
2856     info->state = pv;
2857
2858     return S_OK;
2859 }
2860
2861
2862 /******************************************************************************
2863  *              CoTreatAsClass        [OLE32.@]
2864  *
2865  * Sets the TreatAs value of a class.
2866  *
2867  * PARAMS
2868  *  clsidOld [I] Class to set TreatAs value on.
2869  *  clsidNew [I] The class the clsidOld should be treated as.
2870  *
2871  * RETURNS
2872  *  Success: S_OK.
2873  *  Failure: HRESULT code.
2874  *
2875  * SEE ALSO
2876  *  CoGetTreatAsClass
2877  */
2878 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2879 {
2880     static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
2881     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2882     HKEY hkey = NULL;
2883     WCHAR szClsidNew[CHARS_IN_GUID];
2884     HRESULT res = S_OK;
2885     WCHAR auto_treat_as[CHARS_IN_GUID];
2886     LONG auto_treat_as_size = sizeof(auto_treat_as);
2887     CLSID id;
2888
2889     res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2890     if (FAILED(res))
2891         goto done;
2892     if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2893     {
2894        if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2895            CLSIDFromString(auto_treat_as, &id) == S_OK)
2896        {
2897            if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2898            {
2899                res = REGDB_E_WRITEREGDB;
2900                goto done;
2901            }
2902        }
2903        else
2904        {
2905            RegDeleteKeyW(hkey, wszTreatAs);
2906            goto done;
2907        }
2908     }
2909     else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
2910              !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2911     {
2912         res = REGDB_E_WRITEREGDB;
2913         goto done;
2914     }
2915
2916 done:
2917     if (hkey) RegCloseKey(hkey);
2918     return res;
2919 }
2920
2921 /******************************************************************************
2922  *              CoGetTreatAsClass        [OLE32.@]
2923  *
2924  * Gets the TreatAs value of a class.
2925  *
2926  * PARAMS
2927  *  clsidOld [I] Class to get the TreatAs value of.
2928  *  clsidNew [I] The class the clsidOld should be treated as.
2929  *
2930  * RETURNS
2931  *  Success: S_OK.
2932  *  Failure: HRESULT code.
2933  *
2934  * SEE ALSO
2935  *  CoSetTreatAsClass
2936  */
2937 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2938 {
2939     static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
2940     HKEY hkey = NULL;
2941     WCHAR szClsidNew[CHARS_IN_GUID];
2942     HRESULT res = S_OK;
2943     LONG len = sizeof(szClsidNew);
2944
2945     FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2946     *clsidNew = *clsidOld; /* copy over old value */
2947
2948     res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
2949     if (FAILED(res))
2950         goto done;
2951     if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2952     {
2953         res = S_FALSE;
2954         goto done;
2955     }
2956     res = CLSIDFromString(szClsidNew,clsidNew);
2957     if (FAILED(res))
2958         ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2959 done:
2960     if (hkey) RegCloseKey(hkey);
2961     return res;
2962 }
2963
2964 /******************************************************************************
2965  *              CoGetCurrentProcess     [OLE32.@]
2966  *              CoGetCurrentProcess     [COMPOBJ.34]
2967  *
2968  * Gets the current process ID.
2969  *
2970  * RETURNS
2971  *  The current process ID.
2972  *
2973  * NOTES
2974  *   Is DWORD really the correct return type for this function?
2975  */
2976 DWORD WINAPI CoGetCurrentProcess(void)
2977 {
2978         return GetCurrentProcessId();
2979 }
2980
2981 /******************************************************************************
2982  *              CoRegisterMessageFilter [OLE32.@]
2983  *
2984  * Registers a message filter.
2985  *
2986  * PARAMS
2987  *  lpMessageFilter [I] Pointer to interface.
2988  *  lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2989  *
2990  * RETURNS
2991  *  Success: S_OK.
2992  *  Failure: HRESULT code.
2993  *
2994  * NOTES
2995  *  Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
2996  *  lpMessageFilter removes the message filter.
2997  *
2998  *  If lplpMessageFilter is not NULL the previous message filter will be
2999  *  returned in the memory pointer to this parameter and the caller is
3000  *  responsible for releasing the object.
3001  *
3002  *  The current thread be in an apartment otherwise the function will crash.
3003  */
3004 HRESULT WINAPI CoRegisterMessageFilter(
3005     LPMESSAGEFILTER lpMessageFilter,
3006     LPMESSAGEFILTER *lplpMessageFilter)
3007 {
3008     struct apartment *apt;
3009     IMessageFilter *lpOldMessageFilter;
3010
3011     TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);
3012
3013     apt = COM_CurrentApt();
3014
3015     /* can't set a message filter in a multi-threaded apartment */
3016     if (!apt || apt->multi_threaded)
3017     {
3018         WARN("can't set message filter in MTA or uninitialized apt\n");
3019         return CO_E_NOT_SUPPORTED;
3020     }
3021
3022     if (lpMessageFilter)
3023         IMessageFilter_AddRef(lpMessageFilter);
3024
3025     EnterCriticalSection(&apt->cs);
3026
3027     lpOldMessageFilter = apt->filter;
3028     apt->filter = lpMessageFilter;
3029
3030     LeaveCriticalSection(&apt->cs);
3031
3032     if (lplpMessageFilter)
3033         *lplpMessageFilter = lpOldMessageFilter;
3034     else if (lpOldMessageFilter)
3035         IMessageFilter_Release(lpOldMessageFilter);
3036
3037     return S_OK;
3038 }
3039
3040 /***********************************************************************
3041  *           CoIsOle1Class [OLE32.@]
3042  *
3043  * Determines whether the specified class an OLE v1 class.
3044  *
3045  * PARAMS
3046  *  clsid [I] Class to test.
3047  *
3048  * RETURNS
3049  *  TRUE if the class is an OLE v1 class, or FALSE otherwise.
3050  */
3051 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
3052 {
3053   FIXME("%s\n", debugstr_guid(clsid));
3054   return FALSE;
3055 }
3056
3057 /***********************************************************************
3058  *           IsEqualGUID [OLE32.@]
3059  *
3060  * Compares two Unique Identifiers.
3061  *
3062  * PARAMS
3063  *  rguid1 [I] The first GUID to compare.
3064  *  rguid2 [I] The other GUID to compare.
3065  *
3066  * RETURNS
3067  *      TRUE if equal
3068  */
3069 #undef IsEqualGUID
3070 BOOL WINAPI IsEqualGUID(
3071      REFGUID rguid1,
3072      REFGUID rguid2)
3073 {
3074     return !memcmp(rguid1,rguid2,sizeof(GUID));
3075 }
3076
3077 /***********************************************************************
3078  *           CoInitializeSecurity [OLE32.@]
3079  */
3080 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
3081                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
3082                                     void* pReserved1, DWORD dwAuthnLevel,
3083                                     DWORD dwImpLevel, void* pReserved2,
3084                                     DWORD dwCapabilities, void* pReserved3)
3085 {
3086   FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3087         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
3088         dwCapabilities, pReserved3);
3089   return S_OK;
3090 }
3091
3092 /***********************************************************************
3093  *           CoSuspendClassObjects [OLE32.@]
3094  *
3095  * Suspends all registered class objects to prevent further requests coming in
3096  * for those objects.
3097  *
3098  * RETURNS
3099  *  Success: S_OK.
3100  *  Failure: HRESULT code.
3101  */
3102 HRESULT WINAPI CoSuspendClassObjects(void)
3103 {
3104     FIXME("\n");
3105     return S_OK;
3106 }
3107
3108 /***********************************************************************
3109  *           CoAddRefServerProcess [OLE32.@]
3110  *
3111  * Helper function for incrementing the reference count of a local-server
3112  * process.
3113  *
3114  * RETURNS
3115  *  New reference count.
3116  *
3117  * SEE ALSO
3118  *  CoReleaseServerProcess().
3119  */
3120 ULONG WINAPI CoAddRefServerProcess(void)
3121 {
3122     ULONG refs;
3123
3124     TRACE("\n");
3125
3126     EnterCriticalSection(&csRegisteredClassList);
3127     refs = ++s_COMServerProcessReferences;
3128     LeaveCriticalSection(&csRegisteredClassList);
3129
3130     TRACE("refs before: %d\n", refs - 1);
3131
3132     return refs;
3133 }
3134
3135 /***********************************************************************
3136  *           CoReleaseServerProcess [OLE32.@]
3137  *
3138  * Helper function for decrementing the reference count of a local-server
3139  * process.
3140  *
3141  * RETURNS
3142  *  New reference count.
3143  *
3144  * NOTES
3145  *  When reference count reaches 0, this function suspends all registered
3146  *  classes so no new connections are accepted.
3147  *
3148  * SEE ALSO
3149  *  CoAddRefServerProcess(), CoSuspendClassObjects().
3150  */
3151 ULONG WINAPI CoReleaseServerProcess(void)
3152 {
3153     ULONG refs;
3154
3155     TRACE("\n");
3156
3157     EnterCriticalSection(&csRegisteredClassList);
3158
3159     refs = --s_COMServerProcessReferences;
3160     /* FIXME: if (!refs) COM_SuspendClassObjects(); */
3161
3162     LeaveCriticalSection(&csRegisteredClassList);
3163
3164     TRACE("refs after: %d\n", refs);
3165
3166     return refs;
3167 }
3168
3169 /***********************************************************************
3170  *           CoIsHandlerConnected [OLE32.@]
3171  *
3172  * Determines whether a proxy is connected to a remote stub.
3173  *
3174  * PARAMS
3175  *  pUnk [I] Pointer to object that may or may not be connected.
3176  *
3177  * RETURNS
3178  *  TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
3179  *  FALSE otherwise.
3180  */
3181 BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
3182 {
3183     FIXME("%p\n", pUnk);
3184
3185     return TRUE;
3186 }
3187
3188 /***********************************************************************
3189  *           CoAllowSetForegroundWindow [OLE32.@]
3190  *
3191  */
3192 HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
3193 {
3194     FIXME("(%p, %p): stub\n", pUnk, pvReserved);
3195     return S_OK;
3196 }
3197  
3198 /***********************************************************************
3199  *           CoQueryProxyBlanket [OLE32.@]
3200  *
3201  * Retrieves the security settings being used by a proxy.
3202  *
3203  * PARAMS
3204  *  pProxy        [I] Pointer to the proxy object.
3205  *  pAuthnSvc     [O] The type of authentication service.
3206  *  pAuthzSvc     [O] The type of authorization service.
3207  *  ppServerPrincName [O] Optional. The server prinicple name.
3208  *  pAuthnLevel   [O] The authentication level.
3209  *  pImpLevel     [O] The impersonation level.
3210  *  ppAuthInfo    [O] Information specific to the authorization/authentication service.
3211  *  pCapabilities [O] Flags affecting the security behaviour.
3212  *
3213  * RETURNS
3214  *  Success: S_OK.
3215  *  Failure: HRESULT code.
3216  *
3217  * SEE ALSO
3218  *  CoCopyProxy, CoSetProxyBlanket.
3219  */
3220 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
3221     DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
3222     DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
3223 {
3224     IClientSecurity *pCliSec;
3225     HRESULT hr;
3226
3227     TRACE("%p\n", pProxy);
3228
3229     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3230     if (SUCCEEDED(hr))
3231     {
3232         hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
3233                                           pAuthzSvc, ppServerPrincName,
3234                                           pAuthnLevel, pImpLevel, ppAuthInfo,
3235                                           pCapabilities);
3236         IClientSecurity_Release(pCliSec);
3237     }
3238
3239     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3240     return hr;
3241 }
3242
3243 /***********************************************************************
3244  *           CoSetProxyBlanket [OLE32.@]
3245  *
3246  * Sets the security settings for a proxy.
3247  *
3248  * PARAMS
3249  *  pProxy       [I] Pointer to the proxy object.
3250  *  AuthnSvc     [I] The type of authentication service.
3251  *  AuthzSvc     [I] The type of authorization service.
3252  *  pServerPrincName [I] The server prinicple name.
3253  *  AuthnLevel   [I] The authentication level.
3254  *  ImpLevel     [I] The impersonation level.
3255  *  pAuthInfo    [I] Information specific to the authorization/authentication service.
3256  *  Capabilities [I] Flags affecting the security behaviour.
3257  *
3258  * RETURNS
3259  *  Success: S_OK.
3260  *  Failure: HRESULT code.
3261  *
3262  * SEE ALSO
3263  *  CoQueryProxyBlanket, CoCopyProxy.
3264  */
3265 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
3266     DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
3267     DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
3268 {
3269     IClientSecurity *pCliSec;
3270     HRESULT hr;
3271
3272     TRACE("%p\n", pProxy);
3273
3274     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3275     if (SUCCEEDED(hr))
3276     {
3277         hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
3278                                         AuthzSvc, pServerPrincName,
3279                                         AuthnLevel, ImpLevel, pAuthInfo,
3280                                         Capabilities);
3281         IClientSecurity_Release(pCliSec);
3282     }
3283
3284     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3285     return hr;
3286 }
3287
3288 /***********************************************************************
3289  *           CoCopyProxy [OLE32.@]
3290  *
3291  * Copies a proxy.
3292  *
3293  * PARAMS
3294  *  pProxy [I] Pointer to the proxy object.
3295  *  ppCopy [O] Copy of the proxy.
3296  *
3297  * RETURNS
3298  *  Success: S_OK.
3299  *  Failure: HRESULT code.
3300  *
3301  * SEE ALSO
3302  *  CoQueryProxyBlanket, CoSetProxyBlanket.
3303  */
3304 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
3305 {
3306     IClientSecurity *pCliSec;
3307     HRESULT hr;
3308
3309     TRACE("%p\n", pProxy);
3310
3311     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
3312     if (SUCCEEDED(hr))
3313     {
3314         hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3315         IClientSecurity_Release(pCliSec);
3316     }
3317
3318     if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3319     return hr;
3320 }
3321
3322
3323 /***********************************************************************
3324  *           CoGetCallContext [OLE32.@]
3325  *
3326  * Gets the context of the currently executing server call in the current
3327  * thread.
3328  *
3329  * PARAMS
3330  *  riid [I] Context interface to return.
3331  *  ppv  [O] Pointer to memory that will receive the context on return.
3332  *
3333  * RETURNS
3334  *  Success: S_OK.
3335  *  Failure: HRESULT code.
3336  */
3337 HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
3338 {
3339     FIXME("(%s, %p): stub\n", debugstr_guid(riid), ppv);
3340
3341     *ppv = NULL;
3342     return E_NOINTERFACE;
3343 }
3344
3345 /***********************************************************************
3346  *           CoQueryClientBlanket [OLE32.@]
3347  *
3348  * Retrieves the authentication information about the client of the currently
3349  * executing server call in the current thread.
3350  *
3351  * PARAMS
3352  *  pAuthnSvc     [O] Optional. The type of authentication service.
3353  *  pAuthzSvc     [O] Optional. The type of authorization service.
3354  *  pServerPrincName [O] Optional. The server prinicple name.
3355  *  pAuthnLevel   [O] Optional. The authentication level.
3356  *  pImpLevel     [O] Optional. The impersonation level.
3357  *  pPrivs        [O] Optional. Information about the privileges of the client.
3358  *  pCapabilities [IO] Optional. Flags affecting the security behaviour.
3359  *
3360  * RETURNS
3361  *  Success: S_OK.
3362  *  Failure: HRESULT code.
3363  *
3364  * SEE ALSO
3365  *  CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
3366  */
3367 HRESULT WINAPI CoQueryClientBlanket(
3368     DWORD *pAuthnSvc,
3369     DWORD *pAuthzSvc,
3370     OLECHAR **pServerPrincName,
3371     DWORD *pAuthnLevel,
3372     DWORD *pImpLevel,
3373     RPC_AUTHZ_HANDLE *pPrivs,
3374     DWORD *pCapabilities)
3375 {
3376     IServerSecurity *pSrvSec;
3377     HRESULT hr;
3378
3379     TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
3380         pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
3381         pPrivs, pCapabilities);
3382
3383     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3384     if (SUCCEEDED(hr))
3385     {
3386         hr = IServerSecurity_QueryBlanket(
3387             pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
3388             pImpLevel, pPrivs, pCapabilities);
3389         IServerSecurity_Release(pSrvSec);
3390     }
3391
3392     return hr;
3393 }
3394
3395 /***********************************************************************
3396  *           CoImpersonateClient [OLE32.@]
3397  *
3398  * Impersonates the client of the currently executing server call in the
3399  * current thread.
3400  *
3401  * PARAMS
3402  *  None.
3403  *
3404  * RETURNS
3405  *  Success: S_OK.
3406  *  Failure: HRESULT code.
3407  *
3408  * NOTES
3409  *  If this function fails then the current thread will not be impersonating
3410  *  the client and all actions will take place on behalf of the server.
3411  *  Therefore, it is important to check the return value from this function.
3412  *
3413  * SEE ALSO
3414  *  CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
3415  */
3416 HRESULT WINAPI CoImpersonateClient(void)
3417 {
3418     IServerSecurity *pSrvSec;
3419     HRESULT hr;
3420
3421     TRACE("\n");
3422
3423     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3424     if (SUCCEEDED(hr))
3425     {
3426         hr = IServerSecurity_ImpersonateClient(pSrvSec);
3427         IServerSecurity_Release(pSrvSec);
3428     }
3429
3430     return hr;
3431 }
3432
3433 /***********************************************************************
3434  *           CoRevertToSelf [OLE32.@]
3435  *
3436  * Ends the impersonation of the client of the currently executing server
3437  * call in the current thread.
3438  *
3439  * PARAMS
3440  *  None.
3441  *
3442  * RETURNS
3443  *  Success: S_OK.
3444  *  Failure: HRESULT code.
3445  *
3446  * SEE ALSO
3447  *  CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
3448  */
3449 HRESULT WINAPI CoRevertToSelf(void)
3450 {
3451     IServerSecurity *pSrvSec;
3452     HRESULT hr;
3453
3454     TRACE("\n");
3455
3456     hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
3457     if (SUCCEEDED(hr))
3458     {
3459         hr = IServerSecurity_RevertToSelf(pSrvSec);
3460         IServerSecurity_Release(pSrvSec);
3461     }
3462
3463     return hr;
3464 }
3465
3466 static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
3467 {
3468     /* first try to retrieve messages for incoming COM calls to the apartment window */
3469     return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3470            /* next retrieve other messages necessary for the app to remain responsive */
3471            PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3472 }
3473
3474 /***********************************************************************
3475  *           CoWaitForMultipleHandles [OLE32.@]
3476  *
3477  * Waits for one or more handles to become signaled.
3478  *
3479  * PARAMS
3480  *  dwFlags   [I] Flags. See notes.
3481  *  dwTimeout [I] Timeout in milliseconds.
3482  *  cHandles  [I] Number of handles pointed to by pHandles.
3483  *  pHandles  [I] Handles to wait for.
3484  *  lpdwindex [O] Index of handle that was signaled.
3485  *
3486  * RETURNS
3487  *  Success: S_OK.
3488  *  Failure: RPC_S_CALLPENDING on timeout.
3489  *
3490  * NOTES
3491  *
3492  * The dwFlags parameter can be zero or more of the following:
3493  *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
3494  *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
3495  *
3496  * SEE ALSO
3497  *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
3498  */
3499 HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3500     ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3501 {
3502     HRESULT hr = S_OK;
3503     DWORD start_time = GetTickCount();
3504     APARTMENT *apt = COM_CurrentApt();
3505     BOOL message_loop = apt && !apt->multi_threaded;
3506
3507     TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3508         pHandles, lpdwindex);
3509
3510     while (TRUE)
3511     {
3512         DWORD now = GetTickCount();
3513         DWORD res;
3514
3515         if (now - start_time > dwTimeout)
3516         {
3517             hr = RPC_S_CALLPENDING;
3518             break;
3519         }
3520
3521         if (message_loop)
3522         {
3523             DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
3524                     ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3525
3526             TRACE("waiting for rpc completion or window message\n");
3527
3528             res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
3529                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3530                 QS_ALLINPUT, wait_flags);
3531
3532             if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
3533             {
3534                 MSG msg;
3535
3536                 /* call message filter */
3537
3538                 if (COM_CurrentApt()->filter)
3539                 {
3540                     PENDINGTYPE pendingtype =
3541                         COM_CurrentInfo()->pending_call_count_server ?
3542                             PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3543                     DWORD be_handled = IMessageFilter_MessagePending(
3544                         COM_CurrentApt()->filter, 0 /* FIXME */,
3545                         now - start_time, pendingtype);
3546                     TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
3547                     switch (be_handled)
3548                     {
3549                     case PENDINGMSG_CANCELCALL:
3550                         WARN("call canceled\n");
3551                         hr = RPC_E_CALL_CANCELED;
3552                         break;
3553                     case PENDINGMSG_WAITNOPROCESS:
3554                     case PENDINGMSG_WAITDEFPROCESS:
3555                     default:
3556                         /* FIXME: MSDN is very vague about the difference
3557                          * between WAITNOPROCESS and WAITDEFPROCESS - there
3558                          * appears to be none, so it is possibly a left-over
3559                          * from the 16-bit world. */
3560                         break;
3561                     }
3562                 }
3563
3564                 /* note: using "if" here instead of "while" might seem less
3565                  * efficient, but only if we are optimising for quick delivery
3566                  * of pending messages, rather than quick completion of the
3567                  * COM call */
3568                 if (COM_PeekMessage(apt, &msg))
3569                 {
3570                     TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
3571                     TranslateMessage(&msg);
3572                     DispatchMessageW(&msg);
3573                     if (msg.message == WM_QUIT)
3574                     {
3575                         TRACE("resending WM_QUIT to outer message loop\n");
3576                         PostQuitMessage(msg.wParam);
3577                         /* no longer need to process messages */
3578                         message_loop = FALSE;
3579                     }
3580                 }
3581                 continue;
3582             }
3583         }
3584         else
3585         {
3586             TRACE("waiting for rpc completion\n");
3587
3588             res = WaitForMultipleObjectsEx(cHandles, pHandles,
3589                 (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
3590                 (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
3591                 (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
3592         }
3593
3594         if (res < WAIT_OBJECT_0 + cHandles)
3595         {
3596             /* handle signaled, store index */
3597             *lpdwindex = (res - WAIT_OBJECT_0);
3598             break;
3599         }
3600         else if (res == WAIT_TIMEOUT)
3601         {
3602             hr = RPC_S_CALLPENDING;
3603             break;
3604         }
3605         else
3606         {
3607             ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3608             hr = E_UNEXPECTED;
3609             break;
3610         }
3611     }
3612     TRACE("-- 0x%08x\n", hr);
3613     return hr;
3614 }
3615
3616
3617 /***********************************************************************
3618  *           CoGetObject [OLE32.@]
3619  *
3620  * Gets the object named by converting the name to a moniker and binding to it.
3621  *
3622  * PARAMS
3623  *  pszName      [I] String representing the object.
3624  *  pBindOptions [I] Parameters affecting the binding to the named object.
3625  *  riid         [I] Interface to bind to on the objecct.
3626  *  ppv          [O] On output, the interface riid of the object represented
3627  *                   by pszName.
3628  *
3629  * RETURNS
3630  *  Success: S_OK.
3631  *  Failure: HRESULT code.
3632  *
3633  * SEE ALSO
3634  *  MkParseDisplayName.
3635  */
3636 HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
3637     REFIID riid, void **ppv)
3638 {
3639     IBindCtx *pbc;
3640     HRESULT hr;
3641
3642     *ppv = NULL;
3643
3644     hr = CreateBindCtx(0, &pbc);
3645     if (SUCCEEDED(hr))
3646     {
3647         if (pBindOptions)
3648             hr = IBindCtx_SetBindOptions(pbc, pBindOptions);
3649
3650         if (SUCCEEDED(hr))
3651         {
3652             ULONG chEaten;
3653             IMoniker *pmk;
3654
3655             hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
3656             if (SUCCEEDED(hr))
3657             {
3658                 hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
3659                 IMoniker_Release(pmk);
3660             }
3661         }
3662
3663         IBindCtx_Release(pbc);
3664     }
3665     return hr;
3666 }
3667
3668 /***********************************************************************
3669  *           CoRegisterChannelHook [OLE32.@]
3670  *
3671  * Registers a process-wide hook that is called during ORPC calls.
3672  *
3673  * PARAMS
3674  *  guidExtension [I] GUID of the channel hook to register.
3675  *  pChannelHook  [I] Channel hook object to register.
3676  *
3677  * RETURNS
3678  *  Success: S_OK.
3679  *  Failure: HRESULT code.
3680  */
3681 HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
3682 {
3683     TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);
3684
3685     return RPC_RegisterChannelHook(guidExtension, pChannelHook);
3686 }
3687
3688 typedef struct Context
3689 {
3690     const IComThreadingInfoVtbl *lpVtbl;
3691     LONG refs;
3692     APTTYPE apttype;
3693 } Context;
3694
3695 static HRESULT WINAPI Context_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
3696 {
3697     *ppv = NULL;
3698
3699     if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
3700         IsEqualIID(riid, &IID_IUnknown))
3701     {
3702         *ppv = iface;
3703         IUnknown_AddRef(iface);
3704         return S_OK;
3705     }
3706
3707     FIXME("interface not implemented %s\n", debugstr_guid(riid));
3708     return E_NOINTERFACE;
3709 }
3710
3711 static ULONG WINAPI Context_AddRef(IComThreadingInfo *iface)
3712 {
3713     Context *This = (Context *)iface;
3714     return InterlockedIncrement(&This->refs);
3715 }
3716
3717 static ULONG WINAPI Context_Release(IComThreadingInfo *iface)
3718 {
3719     Context *This = (Context *)iface;
3720     ULONG refs = InterlockedDecrement(&This->refs);
3721     if (!refs)
3722         HeapFree(GetProcessHeap(), 0, This);
3723     return refs;
3724 }
3725
3726 static HRESULT WINAPI Context_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3727 {
3728     Context *This = (Context *)iface;
3729
3730     TRACE("(%p)\n", apttype);
3731
3732     *apttype = This->apttype;
3733     return S_OK;
3734 }
3735
3736 static HRESULT WINAPI Context_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3737 {
3738     Context *This = (Context *)iface;
3739
3740     TRACE("(%p)\n", thdtype);
3741
3742     switch (This->apttype)
3743     {
3744     case APTTYPE_STA:
3745     case APTTYPE_MAINSTA:
3746         *thdtype = THDTYPE_PROCESSMESSAGES;
3747         break;
3748     default:
3749         *thdtype = THDTYPE_BLOCKMESSAGES;
3750         break;
3751     }
3752     return S_OK;
3753 }
3754
3755 static HRESULT WINAPI Context_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3756 {
3757     FIXME("(%p): stub\n", logical_thread_id);
3758     return E_NOTIMPL;
3759 }
3760
3761 static HRESULT WINAPI Context_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3762 {
3763     FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
3764     return E_NOTIMPL;
3765 }
3766
3767 static const IComThreadingInfoVtbl Context_Threading_Vtbl =
3768 {
3769     Context_QueryInterface,
3770     Context_AddRef,
3771     Context_Release,
3772     Context_GetCurrentApartmentType,
3773     Context_GetCurrentThreadType,
3774     Context_GetCurrentLogicalThreadId,
3775     Context_SetCurrentLogicalThreadId
3776 };
3777
3778 /***********************************************************************
3779  *           CoGetObjectContext [OLE32.@]
3780  *
3781  * Retrieves an object associated with the current context (i.e. apartment).
3782  *
3783  * PARAMS
3784  *  riid [I] ID of the interface of the object to retrieve.
3785  *  ppv  [O] Address where object will be stored on return.
3786  *
3787  * RETURNS
3788  *  Success: S_OK.
3789  *  Failure: HRESULT code.
3790  */
3791 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
3792 {
3793     APARTMENT *apt = COM_CurrentApt();
3794     Context *context;
3795     HRESULT hr;
3796
3797     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
3798
3799     *ppv = NULL;
3800     if (!apt)
3801     {
3802         ERR("apartment not initialised\n");
3803         return CO_E_NOTINITIALIZED;
3804     }
3805
3806     context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
3807     if (!context)
3808         return E_OUTOFMEMORY;
3809
3810     context->lpVtbl = &Context_Threading_Vtbl;
3811     context->refs = 1;
3812     if (apt->multi_threaded)
3813         context->apttype = APTTYPE_MTA;
3814     else if (apt->main)
3815         context->apttype = APTTYPE_MAINSTA;
3816     else
3817         context->apttype = APTTYPE_STA;
3818
3819     hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
3820     IUnknown_Release((IUnknown *)&context->lpVtbl);
3821
3822     return hr;
3823 }
3824
3825
3826 /***********************************************************************
3827  *           CoGetContextToken [OLE32.@]
3828  */
3829 HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
3830 {
3831     static int calls;
3832     if(!(calls++)) FIXME( "stub\n" );
3833     if (token) *token = 0;
3834     return E_NOTIMPL;
3835 }
3836
3837
3838 /***********************************************************************
3839  *              DllMain (OLE32.@)
3840  */
3841 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
3842 {
3843     TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3844
3845     switch(fdwReason) {
3846     case DLL_PROCESS_ATTACH:
3847         OLE32_hInstance = hinstDLL;
3848         COMPOBJ_InitProcess();
3849         if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
3850         break;
3851
3852     case DLL_PROCESS_DETACH:
3853         if (TRACE_ON(ole)) CoRevokeMallocSpy();
3854         OLEDD_UnInitialize();
3855         COMPOBJ_UninitProcess();
3856         RPC_UnregisterAllChannelHooks();
3857         COMPOBJ_DllList_Free();
3858         OLE32_hInstance = 0;
3859         break;
3860
3861     case DLL_THREAD_DETACH:
3862         COM_TlsDestroy();
3863         break;
3864     }
3865     return TRUE;
3866 }
3867
3868 /* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */