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