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