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