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