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