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