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