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