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