- Implement CoDisconnectObject.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 pipe names for
34  *     clients and servers to meet up
35  *   - Flip our marshalling on top of the RPC runtime transport API,
36  *     so we no longer use named pipes to communicate
37  *   - Implement RPC thread affinity (should fix InstallShield painting
38  *     problems)
39  *
40  *   - Make all ole interface marshaling use NDR to be wire compatible with
41  *     native DCOM
42  *   - Use & interpret ORPCTHIS & ORPCTHAT.
43  *
44  */
45
46 #include "config.h"
47
48 #include <stdlib.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <assert.h>
53
54 #define COBJMACROS
55 #define NONAMELESSUNION
56 #define NONAMELESSSTRUCT
57
58 #include "windef.h"
59 #include "winbase.h"
60 #include "winuser.h"
61 #include "objbase.h"
62 #include "ole2.h"
63 #include "ole2ver.h"
64 #include "rpc.h"
65 #include "winerror.h"
66 #include "winreg.h"
67 #include "wownt32.h"
68 #include "wine/unicode.h"
69 #include "objbase.h"
70 #include "ole32_main.h"
71 #include "compobj_private.h"
72
73 #include "wine/debug.h"
74
75 WINE_DEFAULT_DEBUG_CHANNEL(ole);
76
77 typedef LPCSTR LPCOLESTR16;
78
79 /****************************************************************************
80  * This section defines variables internal to the COM module.
81  *
82  * TODO: Most of these things will have to be made thread-safe.
83  */
84
85 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN*  ppUnk);
86 static void COM_RevokeAllClasses(void);
87
88 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
89
90 APARTMENT *MTA; /* protected by csApartment */
91 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
92
93 static CRITICAL_SECTION csApartment;
94 static CRITICAL_SECTION_DEBUG critsect_debug =
95 {
96     0, 0, &csApartment,
97     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
98       0, 0, { 0, (DWORD)(__FILE__ ": csApartment") }
99 };
100 static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
101
102 /*
103  * This lock count counts the number of times CoInitialize is called. It is
104  * decreased every time CoUninitialize is called. When it hits 0, the COM
105  * libraries are freed
106  */
107 static LONG s_COMLockCount = 0;
108
109 /*
110  * This linked list contains the list of registered class objects. These
111  * are mostly used to register the factories for out-of-proc servers of OLE
112  * objects.
113  *
114  * TODO: Make this data structure aware of inter-process communication. This
115  *       means that parts of this will be exported to the Wine Server.
116  */
117 typedef struct tagRegisteredClass
118 {
119   CLSID     classIdentifier;
120   LPUNKNOWN classObject;
121   DWORD     runContext;
122   DWORD     connectFlags;
123   DWORD     dwCookie;
124   LPSTREAM  pMarshaledData; /* FIXME: only really need to store OXID and IPID */
125   struct tagRegisteredClass* nextClass;
126 } RegisteredClass;
127
128 static RegisteredClass* firstRegisteredClass = NULL;
129
130 static CRITICAL_SECTION csRegisteredClassList;
131 static CRITICAL_SECTION_DEBUG class_cs_debug =
132 {
133     0, 0, &csRegisteredClassList,
134     { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
135       0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") }
136 };
137 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
138
139 /*****************************************************************************
140  * This section contains OpenDllList definitions
141  *
142  * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
143  * other functions that do LoadLibrary _without_ giving back a HMODULE.
144  * Without this list these handles would never be freed.
145  *
146  * FIXME: a DLL that says OK when asked for unloading is unloaded in the
147  * next unload-call but not before 600 sec.
148  */
149
150 typedef struct tagOpenDll {
151   HINSTANCE hLibrary;
152   struct tagOpenDll *next;
153 } OpenDll;
154
155 static OpenDll *openDllList = NULL; /* linked list of open dlls */
156
157 static CRITICAL_SECTION csOpenDllList;
158 static CRITICAL_SECTION_DEBUG dll_cs_debug =
159 {
160     0, 0, &csOpenDllList,
161     { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
162       0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") }
163 };
164 static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };
165
166 static const char aptWinClass[] = "WINE_OLE32_APT_CLASS";
167 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
168
169 static void COMPOBJ_DLLList_Add(HANDLE hLibrary);
170 static void COMPOBJ_DllList_FreeUnused(int Timeout);
171
172 void COMPOBJ_InitProcess( void )
173 {
174     WNDCLASSA wclass;
175
176     /* Dispatching to the correct thread in an apartment is done through
177      * window messages rather than RPC transports. When an interface is
178      * marshalled into another apartment in the same process, a window of the
179      * following class is created. The *caller* of CoMarshalInterface (ie the
180      * application) is responsible for pumping the message loop in that thread.
181      * The WM_USER messages which point to the RPCs are then dispatched to
182      * COM_AptWndProc by the user's code from the apartment in which the interface
183      * was unmarshalled.
184      */
185     memset(&wclass, 0, sizeof(wclass));
186     wclass.lpfnWndProc = &COM_AptWndProc;
187     wclass.hInstance = OLE32_hInstance;
188     wclass.lpszClassName = aptWinClass;
189     RegisterClassA(&wclass);
190 }
191
192 void COMPOBJ_UninitProcess( void )
193 {
194     UnregisterClassA(aptWinClass, OLE32_hInstance);
195 }
196
197 void COM_TlsDestroy()
198 {
199     struct oletls *info = NtCurrentTeb()->ReservedForOle;
200     if (info)
201     {
202         if (info->apt) COM_ApartmentRelease(info->apt);
203         if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
204         if (info->state) IUnknown_Release(info->state);
205         HeapFree(GetProcessHeap(), 0, info);
206         NtCurrentTeb()->ReservedForOle = NULL;
207     }
208 }
209
210 /******************************************************************************
211  * Manage apartments.
212  */
213
214 /* allocates memory and fills in the necessary fields for a new apartment
215  * object */
216 static APARTMENT *apartment_construct(DWORD model)
217 {
218     APARTMENT *apt;
219
220     TRACE("creating new apartment, model=%ld\n", model);
221
222     apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
223     apt->tid = GetCurrentThreadId();
224     DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
225                     GetCurrentProcess(), &apt->thread,
226                     THREAD_ALL_ACCESS, FALSE, 0);
227
228     list_init(&apt->proxies);
229     list_init(&apt->stubmgrs);
230     apt->ipidc = 0;
231     apt->refs = 1;
232     apt->remunk_exported = FALSE;
233     apt->oidc = 1;
234     InitializeCriticalSection(&apt->cs);
235
236     apt->model = model;
237
238     if (model & COINIT_APARTMENTTHREADED)
239     {
240         /* FIXME: should be randomly generated by in an RPC call to rpcss */
241         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
242         apt->win = CreateWindowA(aptWinClass, NULL, 0,
243                                  0, 0, 0, 0,
244                                  0, 0, OLE32_hInstance, NULL);
245     }
246     else
247     {
248         /* FIXME: should be randomly generated by in an RPC call to rpcss */
249         apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
250     }
251
252     apt->shutdown_event = CreateEventW(NULL, TRUE, FALSE, NULL);
253     
254     TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
255
256     /* the locking here is not currently needed for the MTA case, but it
257      * doesn't hurt and makes the code simpler */
258     EnterCriticalSection(&csApartment);
259     list_add_head(&apts, &apt->entry);
260     LeaveCriticalSection(&csApartment);
261
262     return apt;
263 }
264
265 /* gets and existing apartment if one exists or otherwise creates an apartment
266  * structure which stores OLE apartment-local information and stores a pointer
267  * to it in the thread-local storage */
268 static APARTMENT *get_or_create_apartment(DWORD model)
269 {
270     APARTMENT *apt = COM_CurrentApt();
271
272     if (!apt)
273     {
274         if (model & COINIT_APARTMENTTHREADED)
275         {
276             apt = apartment_construct(model);
277             COM_CurrentInfo()->apt = apt;
278         }
279         else
280         {
281             EnterCriticalSection(&csApartment);
282
283             /* The multi-threaded apartment (MTA) contains zero or more threads interacting
284              * with free threaded (ie thread safe) COM objects. There is only ever one MTA
285              * in a process */
286             if (MTA)
287             {
288                 TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
289                 COM_ApartmentAddRef(MTA);
290             }
291             else
292                 MTA = apartment_construct(model);
293
294             apt = MTA;
295             COM_CurrentInfo()->apt = apt;
296
297             LeaveCriticalSection(&csApartment);
298         }
299     }
300
301     return apt;
302 }
303
304 DWORD COM_ApartmentAddRef(struct apartment *apt)
305 {
306     DWORD refs = InterlockedIncrement(&apt->refs);
307     TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
308     return refs;
309 }
310
311 DWORD COM_ApartmentRelease(struct apartment *apt)
312 {
313     DWORD ret;
314
315     EnterCriticalSection(&csApartment);
316
317     ret = InterlockedDecrement(&apt->refs);
318     TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret);
319     /* destruction stuff that needs to happen under csApartment CS */
320     if (ret == 0)
321     {
322         if (apt == MTA) MTA = NULL;
323         list_remove(&apt->entry);
324     }
325
326     LeaveCriticalSection(&csApartment);
327
328     if (ret == 0)
329     {
330         struct list *cursor, *cursor2;
331
332         TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
333
334         MARSHAL_Disconnect_Proxies(apt);
335
336         if (apt->win) DestroyWindow(apt->win);
337
338         LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
339         {
340             struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
341             /* release the implicit reference given by the fact that the
342              * stub has external references (it must do since it is in the
343              * stub manager list in the apartment and all non-apartment users
344              * must have a ref on the apartment and so it cannot be destroyed).
345              */
346             stub_manager_int_release(stubmgr);
347         }
348
349         /* if this assert fires, then another thread took a reference to a
350          * stub manager without taking a reference to the containing
351          * apartment, which it must do. */
352         assert(list_empty(&apt->stubmgrs));
353
354         if (apt->filter) IUnknown_Release(apt->filter);
355
356         DeleteCriticalSection(&apt->cs);
357         SetEvent(apt->shutdown_event);
358         CloseHandle(apt->shutdown_event);
359         CloseHandle(apt->thread);
360         HeapFree(GetProcessHeap(), 0, apt);
361     }
362
363     return ret;
364 }
365
366 /* The given OXID must be local to this process: you cannot use
367  * apartment windows to send RPCs to other processes. This all needs
368  * to move to rpcrt4.
369  *
370  * The ref parameter is here mostly to ensure people remember that
371  * they get one, you should normally take a ref for thread safety.
372  */
373 APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
374 {
375     APARTMENT *result = NULL;
376     struct list *cursor;
377
378     EnterCriticalSection(&csApartment);
379     LIST_FOR_EACH( cursor, &apts )
380     {
381         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
382         if (apt->oxid == oxid)
383         {
384             result = apt;
385             if (ref) COM_ApartmentAddRef(result);
386             break;
387         }
388     }
389     LeaveCriticalSection(&csApartment);
390
391     return result;
392 }
393
394 /* gets the apartment which has a given creator thread ID. The caller must
395  * release the reference from the apartment as soon as the apartment pointer
396  * is no longer required. */
397 APARTMENT *COM_ApartmentFromTID(DWORD tid)
398 {
399     APARTMENT *result = NULL;
400     struct list *cursor;
401
402     EnterCriticalSection(&csApartment);
403     LIST_FOR_EACH( cursor, &apts )
404     {
405         struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
406         if (apt->tid == tid)
407         {
408             result = apt;
409             COM_ApartmentAddRef(result);
410             break;
411         }
412     }
413     LeaveCriticalSection(&csApartment);
414
415     return result;
416 }
417
418 HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
419 {
420     APARTMENT *apt;
421
422     apt = COM_ApartmentFromOXID(oxid, ref);
423     if (!apt) return NULL;
424
425     return apt->win;
426 }
427
428 /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
429 static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
430 {
431   return DefWindowProcA(hWnd, msg, wParam, lParam);
432 }
433
434 /*****************************************************************************
435  * This section contains OpenDllList implemantation
436  */
437
438 static void COMPOBJ_DLLList_Add(HANDLE hLibrary)
439 {
440     OpenDll *ptr;
441     OpenDll *tmp;
442
443     TRACE("\n");
444
445     EnterCriticalSection( &csOpenDllList );
446
447     if (openDllList == NULL) {
448         /* empty list -- add first node */
449         openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
450         openDllList->hLibrary=hLibrary;
451         openDllList->next = NULL;
452     } else {
453         /* search for this dll */
454         int found = FALSE;
455         for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
456             if (ptr->hLibrary == hLibrary) {
457                 found = TRUE;
458                 break;
459             }
460         }
461         if (!found) {
462             /* dll not found, add it */
463             tmp = openDllList;
464             openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
465             openDllList->hLibrary = hLibrary;
466             openDllList->next = tmp;
467         }
468     }
469
470     LeaveCriticalSection( &csOpenDllList );
471 }
472
473 static void COMPOBJ_DllList_FreeUnused(int Timeout)
474 {
475     OpenDll *curr, *next, *prev = NULL;
476     typedef HRESULT(*DllCanUnloadNowFunc)(void);
477     DllCanUnloadNowFunc DllCanUnloadNow;
478
479     TRACE("\n");
480
481     EnterCriticalSection( &csOpenDllList );
482
483     for (curr = openDllList; curr != NULL; ) {
484         DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow");
485
486         if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) {
487             next = curr->next;
488
489             TRACE("freeing %p\n", curr->hLibrary);
490             FreeLibrary(curr->hLibrary);
491
492             HeapFree(GetProcessHeap(), 0, curr);
493             if (curr == openDllList) {
494                 openDllList = next;
495             } else {
496               prev->next = next;
497             }
498
499             curr = next;
500         } else {
501             prev = curr;
502             curr = curr->next;
503         }
504     }
505
506     LeaveCriticalSection( &csOpenDllList );
507 }
508
509 /******************************************************************************
510  *           CoBuildVersion [OLE32.@]
511  *           CoBuildVersion [COMPOBJ.1]
512  *
513  * Gets the build version of the DLL.
514  *
515  * PARAMS
516  *
517  * RETURNS
518  *      Current build version, hiword is majornumber, loword is minornumber
519  */
520 DWORD WINAPI CoBuildVersion(void)
521 {
522     TRACE("Returning version %d, build %d.\n", rmm, rup);
523     return (rmm<<16)+rup;
524 }
525
526 /******************************************************************************
527  *              CoInitialize    [OLE32.@]
528  *
529  * Initializes the COM libraries by calling CoInitializeEx with
530  * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
531  *
532  * PARAMS
533  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
534  *
535  * RETURNS
536  *  Success: S_OK if not already initialized, S_FALSE otherwise.
537  *  Failure: HRESULT code.
538  *
539  * SEE ALSO
540  *   CoInitializeEx
541  */
542 HRESULT WINAPI CoInitialize(LPVOID lpReserved)
543 {
544   /*
545    * Just delegate to the newer method.
546    */
547   return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
548 }
549
550 /******************************************************************************
551  *              CoInitializeEx  [OLE32.@]
552  *
553  * Initializes the COM libraries.
554  *
555  * PARAMS
556  *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
557  *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
558  *
559  * RETURNS
560  *  S_OK               if successful,
561  *  S_FALSE            if this function was called already.
562  *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
563  *                     threading model.
564  *
565  * NOTES
566  *
567  * The behavior used to set the IMalloc used for memory management is
568  * obsolete.
569  * The dwCoInit parameter must specify of of the following apartment
570  * threading models:
571  *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
572  *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
573  * The parameter may also specify zero or more of the following flags:
574  *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
575  *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
576  *
577  * SEE ALSO
578  *   CoUninitialize
579  */
580 HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
581 {
582   HRESULT hr = S_OK;
583   APARTMENT *apt;
584
585   TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
586
587   if (lpReserved!=NULL)
588   {
589     ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
590   }
591
592   /*
593    * Check the lock count. If this is the first time going through the initialize
594    * process, we have to initialize the libraries.
595    *
596    * And crank-up that lock count.
597    */
598   if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
599   {
600     /*
601      * Initialize the various COM libraries and data structures.
602      */
603     TRACE("() - Initializing the COM libraries\n");
604
605     /* we may need to defer this until after apartment initialisation */
606     RunningObjectTableImpl_Initialize();
607   }
608
609   if (!(apt = COM_CurrentInfo()->apt))
610   {
611     apt = get_or_create_apartment(dwCoInit);
612     if (!apt) return E_OUTOFMEMORY;
613   }
614   else if (dwCoInit != apt->model)
615   {
616     /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
617        code then we are probably using the wrong threading model to implement that API. */
618     ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit);
619     return RPC_E_CHANGED_MODE;
620   }
621   else
622     hr = S_FALSE;
623
624   COM_CurrentInfo()->inits++;
625
626   return hr;
627 }
628
629 /* On COM finalization for a STA thread, the message queue is flushed to ensure no
630    pending RPCs are ignored. Non-COM messages are discarded at this point.
631  */
632 void COM_FlushMessageQueue(void)
633 {
634     MSG message;
635     APARTMENT *apt = COM_CurrentApt();
636
637     if (!apt || !apt->win) return;
638
639     TRACE("Flushing STA message queue\n");
640
641     while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
642     {
643         if (message.hwnd != apt->win)
644         {
645             WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
646             continue;
647         }
648
649         TranslateMessage(&message);
650         DispatchMessageA(&message);
651     }
652 }
653
654 /***********************************************************************
655  *           CoUninitialize   [OLE32.@]
656  *
657  * This method will decrement the refcount on the current apartment, freeing
658  * the resources associated with it if it is the last thread in the apartment.
659  * If the last apartment is freed, the function will additionally release
660  * any COM resources associated with the process.
661  *
662  * PARAMS
663  *
664  * RETURNS
665  *  Nothing.
666  *
667  * SEE ALSO
668  *   CoInitializeEx
669  */
670 void WINAPI CoUninitialize(void)
671 {
672   struct oletls * info = COM_CurrentInfo();
673   LONG lCOMRefCnt;
674
675   TRACE("()\n");
676
677   /* will only happen on OOM */
678   if (!info) return;
679
680   /* sanity check */
681   if (!info->inits)
682   {
683     ERR("Mismatched CoUninitialize\n");
684     return;
685   }
686
687   if (!--info->inits)
688   {
689     COM_ApartmentRelease(info->apt);
690     info->apt = NULL;
691   }
692
693   /*
694    * Decrease the reference count.
695    * If we are back to 0 locks on the COM library, make sure we free
696    * all the associated data structures.
697    */
698   lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
699   if (lCOMRefCnt==1)
700   {
701     TRACE("() - Releasing the COM libraries\n");
702
703     RunningObjectTableImpl_UnInitialize();
704
705     /* Release the references to the registered class objects */
706     COM_RevokeAllClasses();
707
708     /* This will free the loaded COM Dlls  */
709     CoFreeAllLibraries();
710
711     /* This ensures we deal with any pending RPCs */
712     COM_FlushMessageQueue();
713   }
714   else if (lCOMRefCnt<1) {
715     ERR( "CoUninitialize() - not CoInitialized.\n" );
716     InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
717   }
718 }
719
720 /******************************************************************************
721  *              CoDisconnectObject      [OLE32.@]
722  *              CoDisconnectObject      [COMPOBJ.15]
723  *
724  * Disconnects all connections to this object from remote processes. Dispatches
725  * pending RPCs while blocking new RPCs from occurring, and then calls
726  * IMarshal::DisconnectObject on the given object.
727  *
728  * Typically called when the object server is forced to shut down, for instance by
729  * the user.
730  *
731  * PARAMS
732  *  lpUnk    [I] The object whose stub should be disconnected.
733  *  reserved [I] Reserved. Should be set to 0.
734  *
735  * RETURNS
736  *  Success: S_OK.
737  *  Failure: HRESULT code.
738  *
739  * SEE ALSO
740  *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
741  */
742 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
743 {
744     HRESULT hr;
745     IMarshal *marshal;
746     APARTMENT *apt;
747
748     TRACE("(%p, 0x%08lx)\n", lpUnk, reserved);
749
750     hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
751     if (hr == S_OK)
752     {
753         hr = IMarshal_DisconnectObject(marshal, reserved);
754         IMarshal_Release(marshal);
755         return hr;
756     }
757
758     apt = COM_CurrentApt();
759     if (!apt)
760         return CO_E_NOTINITIALIZED;
761
762     apartment_disconnect_object(apt, lpUnk);
763
764     /* Note: native is pretty broken here because it just silently
765      * fails, without returning an appropriate error code if the object was
766      * not found, making apps think that the object was disconnected, when
767      * it actually wasn't */
768
769     return S_OK;
770 }
771
772 /******************************************************************************
773  *              CoCreateGuid [OLE32.@]
774  *
775  * Simply forwards to UuidCreate in RPCRT4.
776  *
777  * PARAMS
778  *  pguid [O] Points to the GUID to initialize.
779  *
780  * RETURNS
781  *  Success: S_OK.
782  *  Failure: HRESULT code.
783  *
784  * SEE ALSO
785  *   UuidCreate
786  */
787 HRESULT WINAPI CoCreateGuid(GUID *pguid)
788 {
789     return UuidCreate(pguid);
790 }
791
792 /******************************************************************************
793  *              CLSIDFromString [OLE32.@]
794  *              IIDFromString   [OLE32.@]
795  *
796  * Converts a unique identifier from its string representation into
797  * the GUID struct.
798  *
799  * PARAMS
800  *  idstr [I] The string representation of the GUID.
801  *  id    [O] GUID converted from the string.
802  *
803  * RETURNS
804  *   S_OK on success
805  *   CO_E_CLASSSTRING if idstr is not a valid CLSID
806  *
807  * BUGS
808  *
809  * In Windows, if idstr is not a valid CLSID string then it gets
810  * treated as a ProgID. Wine currently doesn't do this. If idstr is
811  * NULL it's treated as an all-zero GUID.
812  *
813  * SEE ALSO
814  *  StringFromCLSID
815  */
816 HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id)
817 {
818   const BYTE *s = (const BYTE *) idstr;
819   int   i;
820   BYTE table[256];
821
822   if (!s)
823           s = "{00000000-0000-0000-0000-000000000000}";
824   else {  /* validate the CLSID string */
825
826       if (strlen(s) != 38)
827           return CO_E_CLASSSTRING;
828
829       if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
830           return CO_E_CLASSSTRING;
831
832       for (i=1; i<37; i++) {
833           if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
834           if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
835                 ((s[i] >= 'a') && (s[i] <= 'f'))  ||
836                 ((s[i] >= 'A') && (s[i] <= 'F'))))
837               return CO_E_CLASSSTRING;
838       }
839   }
840
841   TRACE("%s -> %p\n", s, id);
842
843   /* quick lookup table */
844   memset(table, 0, 256);
845
846   for (i = 0; i < 10; i++) {
847     table['0' + i] = i;
848   }
849   for (i = 0; i < 6; i++) {
850     table['A' + i] = i+10;
851     table['a' + i] = i+10;
852   }
853
854   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
855
856   id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
857                table[s[5]] << 12 | table[s[6]] << 8  | table[s[7]] << 4  | table[s[8]]);
858   id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
859   id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
860
861   /* these are just sequential bytes */
862   id->Data4[0] = table[s[20]] << 4 | table[s[21]];
863   id->Data4[1] = table[s[22]] << 4 | table[s[23]];
864   id->Data4[2] = table[s[25]] << 4 | table[s[26]];
865   id->Data4[3] = table[s[27]] << 4 | table[s[28]];
866   id->Data4[4] = table[s[29]] << 4 | table[s[30]];
867   id->Data4[5] = table[s[31]] << 4 | table[s[32]];
868   id->Data4[6] = table[s[33]] << 4 | table[s[34]];
869   id->Data4[7] = table[s[35]] << 4 | table[s[36]];
870
871   return S_OK;
872 }
873
874 /*****************************************************************************/
875
876 HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
877 {
878     char xid[40];
879     HRESULT ret;
880
881     if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL ))
882         return CO_E_CLASSSTRING;
883
884
885     ret = __CLSIDFromStringA(xid,id);
886     if(ret != S_OK) { /* It appears a ProgID is also valid */
887         ret = CLSIDFromProgID(idstr, id);
888     }
889     return ret;
890 }
891
892 /* Converts a GUID into the respective string representation. */
893 HRESULT WINE_StringFromCLSID(
894         const CLSID *id,        /* [in] GUID to be converted */
895         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
896 ) {
897   static const char *hex = "0123456789ABCDEF";
898   char *s;
899   int   i;
900
901   if (!id)
902         { ERR("called with id=Null\n");
903           *idstr = 0x00;
904           return E_FAIL;
905         }
906
907   sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
908           id->Data1, id->Data2, id->Data3,
909           id->Data4[0], id->Data4[1]);
910   s = &idstr[25];
911
912   /* 6 hex bytes */
913   for (i = 2; i < 8; i++) {
914     *s++ = hex[id->Data4[i]>>4];
915     *s++ = hex[id->Data4[i] & 0xf];
916   }
917
918   *s++ = '}';
919   *s++ = '\0';
920
921   TRACE("%p->%s\n", id, idstr);
922
923   return S_OK;
924 }
925
926
927 /******************************************************************************
928  *              StringFromCLSID [OLE32.@]
929  *              StringFromIID   [OLE32.@]
930  *
931  * Converts a GUID into the respective string representation.
932  * The target string is allocated using the OLE IMalloc.
933  *
934  * PARAMS
935  *  id    [I] the GUID to be converted.
936  *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
937  *
938  * RETURNS
939  *   S_OK
940  *   E_FAIL
941  *
942  * SEE ALSO
943  *  StringFromGUID2, CLSIDFromString
944  */
945 HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
946 {
947         char            buf[80];
948         HRESULT       ret;
949         LPMALLOC        mllc;
950
951         if ((ret = CoGetMalloc(0,&mllc)))
952                 return ret;
953
954         ret=WINE_StringFromCLSID(id,buf);
955         if (!ret) {
956             DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
957             *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
958             MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
959         }
960         return ret;
961 }
962
963 /******************************************************************************
964  *              StringFromGUID2 [OLE32.@]
965  *              StringFromGUID2 [COMPOBJ.76]
966  *
967  * Modified version of StringFromCLSID that allows you to specify max
968  * buffer size.
969  *
970  * PARAMS
971  *  id   [I] GUID to convert to string.
972  *  str  [O] Buffer where the result will be stored.
973  *  cmax [I] Size of the buffer in characters.
974  *
975  * RETURNS
976  *      Success: The length of the resulting string in characters.
977  *  Failure: 0.
978  */
979 INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
980 {
981   char          xguid[80];
982
983   if (WINE_StringFromCLSID(id,xguid))
984         return 0;
985   return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
986 }
987
988 /******************************************************************************
989  *               ProgIDFromCLSID [OLE32.@]
990  *
991  * Converts a class id into the respective program ID.
992  *
993  * PARAMS
994  *  clsid        [I] Class ID, as found in registry.
995  *  lplpszProgID [O] Associated ProgID.
996  *
997  * RETURNS
998  *   S_OK
999  *   E_OUTOFMEMORY
1000  *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1001  */
1002 HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
1003 {
1004   char     strCLSID[50], *buf, *buf2;
1005   DWORD    buf2len;
1006   HKEY     xhkey;
1007   LPMALLOC mllc;
1008   HRESULT  ret = S_OK;
1009
1010   WINE_StringFromCLSID(clsid, strCLSID);
1011
1012   buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
1013   sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
1014   if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1015     ret = REGDB_E_CLASSNOTREG;
1016
1017   HeapFree(GetProcessHeap(), 0, buf);
1018
1019   if (ret == S_OK)
1020   {
1021     buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
1022     buf2len = 255;
1023     if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
1024       ret = REGDB_E_CLASSNOTREG;
1025
1026     if (ret == S_OK)
1027     {
1028       if (CoGetMalloc(0,&mllc))
1029         ret = E_OUTOFMEMORY;
1030       else
1031       {
1032           DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
1033           *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
1034           MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
1035       }
1036     }
1037     HeapFree(GetProcessHeap(), 0, buf2);
1038   }
1039
1040   RegCloseKey(xhkey);
1041   return ret;
1042 }
1043
1044 HRESULT WINAPI CLSIDFromProgID16(
1045         LPCOLESTR16 progid,     /* [in] program id as found in registry */
1046         LPCLSID riid            /* [out] associated CLSID */
1047 ) {
1048         char    *buf,buf2[80];
1049         DWORD   buf2len;
1050         HRESULT err;
1051         HKEY    xhkey;
1052
1053         buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
1054         sprintf(buf,"%s\\CLSID",progid);
1055         if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
1056                 HeapFree(GetProcessHeap(),0,buf);
1057                 return CO_E_CLASSSTRING;
1058         }
1059         HeapFree(GetProcessHeap(),0,buf);
1060         buf2len = sizeof(buf2);
1061         if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
1062                 RegCloseKey(xhkey);
1063                 return CO_E_CLASSSTRING;
1064         }
1065         RegCloseKey(xhkey);
1066         return __CLSIDFromStringA(buf2,riid);
1067 }
1068
1069 /******************************************************************************
1070  *              CLSIDFromProgID [OLE32.@]
1071  *              CLSIDFromProgID [COMPOBJ.61]
1072  *
1073  * Converts a program id into the respective GUID.
1074  *
1075  * PARAMS
1076  *  progid [I] Unicode program ID, as found in registry.
1077  *  riid   [O] Associated CLSID.
1078  *
1079  * RETURNS
1080  *      Success: S_OK
1081  *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
1082  */
1083 HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid)
1084 {
1085     static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1086     char buf2[80];
1087     DWORD buf2len = sizeof(buf2);
1088     HKEY xhkey;
1089
1090     WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1091     strcpyW( buf, progid );
1092     strcatW( buf, clsidW );
1093     if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
1094     {
1095         HeapFree(GetProcessHeap(),0,buf);
1096         return CO_E_CLASSSTRING;
1097     }
1098     HeapFree(GetProcessHeap(),0,buf);
1099
1100     if (RegQueryValueA(xhkey,NULL,buf2,&buf2len))
1101     {
1102         RegCloseKey(xhkey);
1103         return CO_E_CLASSSTRING;
1104     }
1105     RegCloseKey(xhkey);
1106     return __CLSIDFromStringA(buf2,riid);
1107 }
1108
1109
1110
1111 /*****************************************************************************
1112  *             CoGetPSClsid [OLE32.@]
1113  *
1114  * Retrieves the CLSID of the proxy/stub factory that implements
1115  * IPSFactoryBuffer for the specified interface.
1116  *
1117  * PARAMS
1118  *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
1119  *  pclsid [O] Where to store returned proxy/stub CLSID.
1120  * 
1121  * RETURNS
1122  *   S_OK
1123  *   E_OUTOFMEMORY
1124  *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1125  *
1126  * NOTES
1127  *
1128  * The standard marshaller activates the object with the CLSID
1129  * returned and uses the CreateProxy and CreateStub methods on its
1130  * IPSFactoryBuffer interface to construct the proxies and stubs for a
1131  * given object.
1132  *
1133  * CoGetPSClsid determines this CLSID by searching the
1134  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
1135  * in the registry and any interface id registered by
1136  * CoRegisterPSClsid within the current process.
1137  *
1138  * BUGS
1139  *
1140  * We only search the registry, not ids registered with
1141  * CoRegisterPSClsid.
1142  * Also, native returns S_OK for interfaces with an key in HKCR\Interface, but
1143  * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
1144  * considered a bug in native unless an application depends on this (unlikely).
1145  */
1146 HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1147 {
1148     char *buf, buf2[40];
1149     DWORD buf2len;
1150     HKEY xhkey;
1151
1152     TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);
1153
1154     /* Get the input iid as a string */
1155     WINE_StringFromCLSID(riid, buf2);
1156     /* Allocate memory for the registry key we will construct.
1157        (length of iid string plus constant length of static text */
1158     buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
1159     if (buf == NULL)
1160         return E_OUTOFMEMORY;
1161
1162     /* Construct the registry key we want */
1163     sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
1164
1165     /* Open the key.. */
1166     if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
1167     {
1168         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
1169         HeapFree(GetProcessHeap(),0,buf);
1170         return REGDB_E_IIDNOTREG;
1171     }
1172     HeapFree(GetProcessHeap(),0,buf);
1173
1174     /* ... Once we have the key, query the registry to get the
1175        value of CLSID as a string, and convert it into a
1176        proper CLSID structure to be passed back to the app */
1177     buf2len = sizeof(buf2);
1178     if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
1179     {
1180         RegCloseKey(xhkey);
1181         return REGDB_E_IIDNOTREG;
1182     }
1183     RegCloseKey(xhkey);
1184
1185     /* We have the CLSid we want back from the registry as a string, so
1186        lets convert it into a CLSID structure */
1187     if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR)
1188         return REGDB_E_IIDNOTREG;
1189
1190     TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
1191     return S_OK;
1192 }
1193
1194
1195
1196 /***********************************************************************
1197  *              WriteClassStm (OLE32.@)
1198  *
1199  * Writes a CLSID to a stream.
1200  *
1201  * PARAMS
1202  *  pStm   [I] Stream to write to.
1203  *  rclsid [I] CLSID to write.
1204  *
1205  * RETURNS
1206  *  Success: S_OK.
1207  *  Failure: HRESULT code.
1208  */
1209 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
1210 {
1211     TRACE("(%p,%p)\n",pStm,rclsid);
1212
1213     if (rclsid==NULL)
1214         return E_INVALIDARG;
1215
1216     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
1217 }
1218
1219 /***********************************************************************
1220  *              ReadClassStm (OLE32.@)
1221  *
1222  * Reads a CLSID from a stream.
1223  *
1224  * PARAMS
1225  *  pStm   [I] Stream to read from.
1226  *  rclsid [O] CLSID to read.
1227  *
1228  * RETURNS
1229  *  Success: S_OK.
1230  *  Failure: HRESULT code.
1231  */
1232 HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid)
1233 {
1234     ULONG nbByte;
1235     HRESULT res;
1236
1237     TRACE("(%p,%p)\n",pStm,pclsid);
1238
1239     if (pclsid==NULL)
1240         return E_INVALIDARG;
1241
1242     res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte);
1243
1244     if (FAILED(res))
1245         return res;
1246
1247     if (nbByte != sizeof(CLSID))
1248         return S_FALSE;
1249     else
1250         return S_OK;
1251 }
1252
1253
1254 /***
1255  * COM_GetRegisteredClassObject
1256  *
1257  * This internal method is used to scan the registered class list to
1258  * find a class object.
1259  *
1260  * Params:
1261  *   rclsid        Class ID of the class to find.
1262  *   dwClsContext  Class context to match.
1263  *   ppv           [out] returns a pointer to the class object. Complying
1264  *                 to normal COM usage, this method will increase the
1265  *                 reference count on this object.
1266  */
1267 static HRESULT COM_GetRegisteredClassObject(
1268         REFCLSID    rclsid,
1269         DWORD       dwClsContext,
1270         LPUNKNOWN*  ppUnk)
1271 {
1272   HRESULT hr = S_FALSE;
1273   RegisteredClass* curClass;
1274
1275   EnterCriticalSection( &csRegisteredClassList );
1276
1277   /*
1278    * Sanity check
1279    */
1280   assert(ppUnk!=0);
1281
1282   /*
1283    * Iterate through the whole list and try to match the class ID.
1284    */
1285   curClass = firstRegisteredClass;
1286
1287   while (curClass != 0)
1288   {
1289     /*
1290      * Check if we have a match on the class ID.
1291      */
1292     if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
1293     {
1294       /*
1295        * Since we don't do out-of process or DCOM just right away, let's ignore the
1296        * class context.
1297        */
1298
1299       /*
1300        * We have a match, return the pointer to the class object.
1301        */
1302       *ppUnk = curClass->classObject;
1303
1304       IUnknown_AddRef(curClass->classObject);
1305
1306       hr = S_OK;
1307       goto end;
1308     }
1309
1310     /*
1311      * Step to the next class in the list.
1312      */
1313     curClass = curClass->nextClass;
1314   }
1315
1316 end:
1317   LeaveCriticalSection( &csRegisteredClassList );
1318   /*
1319    * If we get to here, we haven't found our class.
1320    */
1321   return hr;
1322 }
1323
1324 /******************************************************************************
1325  *              CoRegisterClassObject   [OLE32.@]
1326  *
1327  * Registers the class object for a given class ID. Servers housed in EXE
1328  * files use this method instead of exporting DllGetClassObject to allow
1329  * other code to connect to their objects.
1330  *
1331  * PARAMS
1332  *  rclsid       [I] CLSID of the object to register.
1333  *  pUnk         [I] IUnknown of the object.
1334  *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
1335  *  flags        [I] REGCLS flags indicating how connections are made.
1336  *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
1337  *
1338  * RETURNS
1339  *   S_OK on success,
1340  *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
1341  *   CO_E_OBJISREG if the object is already registered. We should not return this.
1342  *
1343  * SEE ALSO
1344  *   CoRevokeClassObject, CoGetClassObject
1345  *
1346  * BUGS
1347  *  MSDN claims that multiple interface registrations are legal, but we
1348  *  can't do that with our current implementation.
1349  */
1350 HRESULT WINAPI CoRegisterClassObject(
1351     REFCLSID rclsid,
1352     LPUNKNOWN pUnk,
1353     DWORD dwClsContext,
1354     DWORD flags,
1355     LPDWORD lpdwRegister)
1356 {
1357   RegisteredClass* newClass;
1358   LPUNKNOWN        foundObject;
1359   HRESULT          hr;
1360
1361   TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1362         debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1363
1364   if ( (lpdwRegister==0) || (pUnk==0) )
1365     return E_INVALIDARG;
1366
1367   if (!COM_CurrentApt())
1368   {
1369       ERR("COM was not initialized\n");
1370       return CO_E_NOTINITIALIZED;
1371   }
1372
1373   *lpdwRegister = 0;
1374
1375   /*
1376    * First, check if the class is already registered.
1377    * If it is, this should cause an error.
1378    */
1379   hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1380   if (hr == S_OK) {
1381     IUnknown_Release(foundObject);
1382     return CO_E_OBJISREG;
1383   }
1384
1385   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1386   if ( newClass == NULL )
1387     return E_OUTOFMEMORY;
1388
1389   EnterCriticalSection( &csRegisteredClassList );
1390
1391   newClass->classIdentifier = *rclsid;
1392   newClass->runContext      = dwClsContext;
1393   newClass->connectFlags    = flags;
1394   /*
1395    * Use the address of the chain node as the cookie since we are sure it's
1396    * unique. FIXME: not on 64-bit platforms.
1397    */
1398   newClass->dwCookie        = (DWORD)newClass;
1399   newClass->nextClass       = firstRegisteredClass;
1400
1401   /*
1402    * Since we're making a copy of the object pointer, we have to increase its
1403    * reference count.
1404    */
1405   newClass->classObject     = pUnk;
1406   IUnknown_AddRef(newClass->classObject);
1407
1408   firstRegisteredClass = newClass;
1409   LeaveCriticalSection( &csRegisteredClassList );
1410
1411   *lpdwRegister = newClass->dwCookie;
1412
1413   if (dwClsContext & CLSCTX_LOCAL_SERVER) {
1414       IClassFactory *classfac;
1415
1416       hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
1417                                    (LPVOID*)&classfac);
1418       if (hr) return hr;
1419
1420       hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
1421       if (hr) {
1422           FIXME("Failed to create stream on hglobal, %lx\n", hr);
1423           IUnknown_Release(classfac);
1424           return hr;
1425       }
1426       hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
1427                               (LPVOID)classfac, MSHCTX_LOCAL, NULL,
1428                               MSHLFLAGS_TABLESTRONG);
1429       if (hr) {
1430           FIXME("CoMarshalInterface failed, %lx!\n",hr);
1431           IUnknown_Release(classfac);
1432           return hr;
1433       }
1434
1435       IUnknown_Release(classfac);
1436
1437       RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData);
1438   }
1439   return S_OK;
1440 }
1441
1442 /***********************************************************************
1443  *           CoRevokeClassObject [OLE32.@]
1444  *
1445  * Removes a class object from the class registry.
1446  *
1447  * PARAMS
1448  *  dwRegister [I] Cookie returned from CoRegisterClassObject().
1449  *
1450  * RETURNS
1451  *  Success: S_OK.
1452  *  Failure: HRESULT code.
1453  *
1454  * SEE ALSO
1455  *  CoRegisterClassObject
1456  */
1457 HRESULT WINAPI CoRevokeClassObject(
1458         DWORD dwRegister)
1459 {
1460   HRESULT hr = E_INVALIDARG;
1461   RegisteredClass** prevClassLink;
1462   RegisteredClass*  curClass;
1463
1464   TRACE("(%08lx)\n",dwRegister);
1465
1466   EnterCriticalSection( &csRegisteredClassList );
1467
1468   /*
1469    * Iterate through the whole list and try to match the cookie.
1470    */
1471   curClass      = firstRegisteredClass;
1472   prevClassLink = &firstRegisteredClass;
1473
1474   while (curClass != 0)
1475   {
1476     /*
1477      * Check if we have a match on the cookie.
1478      */
1479     if (curClass->dwCookie == dwRegister)
1480     {
1481       /*
1482        * Remove the class from the chain.
1483        */
1484       *prevClassLink = curClass->nextClass;
1485
1486       /*
1487        * Release the reference to the class object.
1488        */
1489       IUnknown_Release(curClass->classObject);
1490
1491       if (curClass->pMarshaledData)
1492       {
1493         LARGE_INTEGER zero;
1494         memset(&zero, 0, sizeof(zero));
1495         /* FIXME: stop local server thread */
1496         IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL);
1497         CoReleaseMarshalData(curClass->pMarshaledData);
1498       }
1499
1500       /*
1501        * Free the memory used by the chain node.
1502        */
1503       HeapFree(GetProcessHeap(), 0, curClass);
1504
1505       hr = S_OK;
1506       goto end;
1507     }
1508
1509     /*
1510      * Step to the next class in the list.
1511      */
1512     prevClassLink = &(curClass->nextClass);
1513     curClass      = curClass->nextClass;
1514   }
1515
1516 end:
1517   LeaveCriticalSection( &csRegisteredClassList );
1518   /*
1519    * If we get to here, we haven't found our class.
1520    */
1521   return hr;
1522 }
1523
1524 /***********************************************************************
1525  *      compobj_RegReadPath     [internal]
1526  *
1527  *      Reads a registry value and expands it when necessary
1528  */
1529 HRESULT compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen)
1530 {
1531         HRESULT hres;
1532         HKEY key;
1533         DWORD keytype;
1534         char src[MAX_PATH];
1535         DWORD dwLength = dstlen;
1536
1537         if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
1538           if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
1539             if (keytype == REG_EXPAND_SZ) {
1540               if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA;
1541             } else {
1542               lstrcpynA(dst, src, dstlen);
1543             }
1544           }
1545           RegCloseKey (key);
1546         }
1547         return hres;
1548 }
1549
1550 /***********************************************************************
1551  *           CoGetClassObject [COMPOBJ.7]
1552  *           CoGetClassObject [OLE32.@]
1553  *
1554  * FIXME.  If request allows of several options and there is a failure
1555  *         with one (other than not being registered) do we try the
1556  *         others or return failure?  (E.g. inprocess is registered but
1557  *         the DLL is not found but the server version works)
1558  */
1559 HRESULT WINAPI CoGetClassObject(
1560     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1561     REFIID iid, LPVOID *ppv
1562 ) {
1563     LPUNKNOWN   regClassObject;
1564     HRESULT     hres = E_UNEXPECTED;
1565     char        xclsid[80];
1566     HINSTANCE hLibrary;
1567     typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
1568     DllGetClassObjectFunc DllGetClassObject;
1569
1570     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1571
1572     TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
1573
1574     if (pServerInfo) {
1575         FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
1576         FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
1577     }
1578
1579     /*
1580      * First, try and see if we can't match the class ID with one of the
1581      * registered classes.
1582      */
1583     if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1584     {
1585       /*
1586        * Get the required interface from the retrieved pointer.
1587        */
1588       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1589
1590       /*
1591        * Since QI got another reference on the pointer, we want to release the
1592        * one we already have. If QI was unsuccessful, this will release the object. This
1593        * is good since we are not returning it in the "out" parameter.
1594        */
1595       IUnknown_Release(regClassObject);
1596
1597       return hres;
1598     }
1599
1600     /* first try: in-process */
1601     if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) {
1602         char keyname[MAX_PATH];
1603         char dllpath[MAX_PATH+1];
1604
1605         sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid);
1606
1607         if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) {
1608             /* failure: CLSID is not found in registry */
1609            WARN("class %s not registered inproc\n", xclsid);
1610             hres = REGDB_E_CLASSNOTREG;
1611         } else {
1612           if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
1613             /* failure: DLL could not be loaded */
1614             ERR("couldn't load InprocServer32 dll %s\n", dllpath);
1615             hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
1616           } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
1617             /* failure: the dll did not export DllGetClassObject */
1618             ERR("couldn't find function DllGetClassObject in %s\n", dllpath);
1619             FreeLibrary( hLibrary );
1620             hres = CO_E_DLLNOTFOUND;
1621           } else {
1622             /* OK: get the ClassObject */
1623             COMPOBJ_DLLList_Add( hLibrary );
1624             return DllGetClassObject(rclsid, iid, ppv);
1625           }
1626         }
1627     }
1628
1629     /* Next try out of process */
1630     if (CLSCTX_LOCAL_SERVER & dwClsContext)
1631     {
1632         return create_marshalled_proxy(rclsid,iid,ppv);
1633     }
1634
1635     /* Finally try remote: this requires networked DCOM (a lot of work) */
1636     if (CLSCTX_REMOTE_SERVER & dwClsContext)
1637     {
1638         FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
1639         hres = E_NOINTERFACE;
1640     }
1641
1642     return hres;
1643 }
1644 /***********************************************************************
1645  *        CoResumeClassObjects (OLE32.@)
1646  *
1647  * Resumes all class objects registered with REGCLS_SUSPENDED.
1648  *
1649  * RETURNS
1650  *  Success: S_OK.
1651  *  Failure: HRESULT code.
1652  */
1653 HRESULT WINAPI CoResumeClassObjects(void)
1654 {
1655        FIXME("stub\n");
1656         return S_OK;
1657 }
1658
1659 /***********************************************************************
1660  *        GetClassFile (OLE32.@)
1661  *
1662  * This function supplies the CLSID associated with the given filename.
1663  */
1664 HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid)
1665 {
1666     IStorage *pstg=0;
1667     HRESULT res;
1668     int nbElm, length, i;
1669     LONG sizeProgId;
1670     LPOLESTR *pathDec=0,absFile=0,progId=0;
1671     LPWSTR extension;
1672     static const WCHAR bkslashW[] = {'\\',0};
1673     static const WCHAR dotW[] = {'.',0};
1674
1675     TRACE("%s, %p\n", debugstr_w(filePathName), pclsid);
1676
1677     /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/
1678     if((StgIsStorageFile(filePathName))==S_OK){
1679
1680         res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1681
1682         if (SUCCEEDED(res))
1683             res=ReadClassStg(pstg,pclsid);
1684
1685         IStorage_Release(pstg);
1686
1687         return res;
1688     }
1689     /* if the file is not a storage object then attemps to match various bits in the file against a
1690        pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1691        this case
1692
1693      for(i=0;i<nFileTypes;i++)
1694
1695         for(i=0;j<nPatternsForType;j++){
1696
1697             PATTERN pat;
1698             HANDLE  hFile;
1699
1700             pat=ReadPatternFromRegistry(i,j);
1701             hFile=CreateFileW(filePathName,,,,,,hFile);
1702             SetFilePosition(hFile,pat.offset);
1703             ReadFile(hFile,buf,pat.size,&r,NULL);
1704             if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1705
1706                 *pclsid=ReadCLSIDFromRegistry(i);
1707                 return S_OK;
1708             }
1709         }
1710      */
1711
1712     /* if the above strategies fail then search for the extension key in the registry */
1713
1714     /* get the last element (absolute file) in the path name */
1715     nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1716     absFile=pathDec[nbElm-1];
1717
1718     /* failed if the path represente a directory and not an absolute file name*/
1719     if (!lstrcmpW(absFile, bkslashW))
1720         return MK_E_INVALIDEXTENSION;
1721
1722     /* get the extension of the file */
1723     extension = NULL;
1724     length=lstrlenW(absFile);
1725     for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--)
1726         /* nothing */;
1727
1728     if (!extension || !lstrcmpW(extension, dotW))
1729         return MK_E_INVALIDEXTENSION;
1730
1731     res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId);
1732
1733     /* get the progId associated to the extension */
1734     progId = CoTaskMemAlloc(sizeProgId);
1735     res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId);
1736
1737     if (res==ERROR_SUCCESS)
1738         /* return the clsid associated to the progId */
1739         res= CLSIDFromProgID(progId,pclsid);
1740
1741     for(i=0; pathDec[i]!=NULL;i++)
1742         CoTaskMemFree(pathDec[i]);
1743     CoTaskMemFree(pathDec);
1744
1745     CoTaskMemFree(progId);
1746
1747     if (res==ERROR_SUCCESS)
1748         return res;
1749
1750     return MK_E_INVALIDEXTENSION;
1751 }
1752 /***********************************************************************
1753  *           CoCreateInstance [COMPOBJ.13]
1754  *           CoCreateInstance [OLE32.@]
1755  */
1756 HRESULT WINAPI CoCreateInstance(
1757         REFCLSID rclsid,
1758         LPUNKNOWN pUnkOuter,
1759         DWORD dwClsContext,
1760         REFIID iid,
1761         LPVOID *ppv)
1762 {
1763   HRESULT hres;
1764   LPCLASSFACTORY lpclf = 0;
1765
1766   if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
1767
1768   /*
1769    * Sanity check
1770    */
1771   if (ppv==0)
1772     return E_POINTER;
1773
1774   /*
1775    * Initialize the "out" parameter
1776    */
1777   *ppv = 0;
1778
1779   /*
1780    * The Standard Global Interface Table (GIT) object is a process-wide singleton.
1781    * Rather than create a class factory, we can just check for it here
1782    */
1783   if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
1784     if (StdGlobalInterfaceTableInstance == NULL)
1785       StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
1786     hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
1787     if (hres) return hres;
1788
1789     TRACE("Retrieved GIT (%p)\n", *ppv);
1790     return S_OK;
1791   }
1792
1793   /*
1794    * Get a class factory to construct the object we want.
1795    */
1796   hres = CoGetClassObject(rclsid,
1797                           dwClsContext,
1798                           NULL,
1799                           &IID_IClassFactory,
1800                           (LPVOID)&lpclf);
1801
1802   if (FAILED(hres)) {
1803     FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n",
1804           debugstr_guid(rclsid),hres);
1805     return hres;
1806   }
1807
1808   /*
1809    * Create the object and don't forget to release the factory
1810    */
1811         hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1812         IClassFactory_Release(lpclf);
1813         if(FAILED(hres))
1814           FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n",
1815                 debugstr_guid(iid), debugstr_guid(rclsid),hres);
1816
1817         return hres;
1818 }
1819
1820 /***********************************************************************
1821  *           CoCreateInstanceEx [OLE32.@]
1822  */
1823 HRESULT WINAPI CoCreateInstanceEx(
1824   REFCLSID      rclsid,
1825   LPUNKNOWN     pUnkOuter,
1826   DWORD         dwClsContext,
1827   COSERVERINFO* pServerInfo,
1828   ULONG         cmq,
1829   MULTI_QI*     pResults)
1830 {
1831   IUnknown* pUnk = NULL;
1832   HRESULT   hr;
1833   ULONG     index;
1834   ULONG     successCount = 0;
1835
1836   /*
1837    * Sanity check
1838    */
1839   if ( (cmq==0) || (pResults==NULL))
1840     return E_INVALIDARG;
1841
1842   if (pServerInfo!=NULL)
1843     FIXME("() non-NULL pServerInfo not supported!\n");
1844
1845   /*
1846    * Initialize all the "out" parameters.
1847    */
1848   for (index = 0; index < cmq; index++)
1849   {
1850     pResults[index].pItf = NULL;
1851     pResults[index].hr   = E_NOINTERFACE;
1852   }
1853
1854   /*
1855    * Get the object and get its IUnknown pointer.
1856    */
1857   hr = CoCreateInstance(rclsid,
1858                         pUnkOuter,
1859                         dwClsContext,
1860                         &IID_IUnknown,
1861                         (VOID**)&pUnk);
1862
1863   if (hr)
1864     return hr;
1865
1866   /*
1867    * Then, query for all the interfaces requested.
1868    */
1869   for (index = 0; index < cmq; index++)
1870   {
1871     pResults[index].hr = IUnknown_QueryInterface(pUnk,
1872                                                  pResults[index].pIID,
1873                                                  (VOID**)&(pResults[index].pItf));
1874
1875     if (pResults[index].hr == S_OK)
1876       successCount++;
1877   }
1878
1879   /*
1880    * Release our temporary unknown pointer.
1881    */
1882   IUnknown_Release(pUnk);
1883
1884   if (successCount == 0)
1885     return E_NOINTERFACE;
1886
1887   if (successCount!=cmq)
1888     return CO_S_NOTALLINTERFACES;
1889
1890   return S_OK;
1891 }
1892
1893 /***********************************************************************
1894  *           CoLoadLibrary (OLE32.@)
1895  *
1896  * Loads a library.
1897  *
1898  * PARAMS
1899  *  lpszLibName [I] Path to library.
1900  *  bAutoFree   [I] Whether the library should automatically be freed.
1901  *
1902  * RETURNS
1903  *  Success: Handle to loaded library.
1904  *  Failure: NULL.
1905  *
1906  * SEE ALSO
1907  *  CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1908  */
1909 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1910 {
1911     TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
1912
1913     return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1914 }
1915
1916 /***********************************************************************
1917  *           CoFreeLibrary [OLE32.@]
1918  *
1919  * Unloads a library from memory.
1920  *
1921  * PARAMS
1922  *  hLibrary [I] Handle to library to unload.
1923  *
1924  * RETURNS
1925  *  Nothing
1926  *
1927  * SEE ALSO
1928  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
1929  */
1930 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1931 {
1932     FreeLibrary(hLibrary);
1933 }
1934
1935
1936 /***********************************************************************
1937  *           CoFreeAllLibraries [OLE32.@]
1938  *
1939  * Function for backwards compatibility only. Does nothing.
1940  *
1941  * RETURNS
1942  *  Nothing.
1943  *
1944  * SEE ALSO
1945  *  CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
1946  */
1947 void WINAPI CoFreeAllLibraries(void)
1948 {
1949     /* NOP */
1950 }
1951
1952
1953 /***********************************************************************
1954  *           CoFreeUnusedLibraries [OLE32.@]
1955  *           CoFreeUnusedLibraries [COMPOBJ.17]
1956  *
1957  * Frees any unused libraries. Unused are identified as those that return
1958  * S_OK from their DllCanUnloadNow function.
1959  *
1960  * RETURNS
1961  *  Nothing.
1962  *
1963  * SEE ALSO
1964  *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
1965  */
1966 void WINAPI CoFreeUnusedLibraries(void)
1967 {
1968     /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route
1969      * through the main apartment's thread to call DllCanUnloadNow */
1970     COMPOBJ_DllList_FreeUnused(0);
1971 }
1972
1973 /***********************************************************************
1974  *           CoFileTimeNow [OLE32.@]
1975  *           CoFileTimeNow [COMPOBJ.82]
1976  *
1977  * Retrieves the current time in FILETIME format.
1978  *
1979  * PARAMS
1980  *  lpFileTime [O] The current time.
1981  *
1982  * RETURNS
1983  *      S_OK.
1984  */
1985 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
1986 {
1987     GetSystemTimeAsFileTime( lpFileTime );
1988     return S_OK;
1989 }
1990
1991 static void COM_RevokeAllClasses()
1992 {
1993   EnterCriticalSection( &csRegisteredClassList );
1994
1995   while (firstRegisteredClass!=0)
1996   {
1997     CoRevokeClassObject(firstRegisteredClass->dwCookie);
1998   }
1999
2000   LeaveCriticalSection( &csRegisteredClassList );
2001 }
2002
2003 /******************************************************************************
2004  *              CoLockObjectExternal    [OLE32.@]
2005  *
2006  * Increments or decrements the external reference count of a stub object.
2007  *
2008  * PARAMS
2009  *  pUnk                [I] Stub object.
2010  *  fLock               [I] If TRUE then increments the external ref-count,
2011  *                          otherwise decrements.
2012  *  fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
2013  *                          calling CoDisconnectObject.
2014  *
2015  * RETURNS
2016  *  Success: S_OK.
2017  *  Failure: HRESULT code.
2018  */
2019 HRESULT WINAPI CoLockObjectExternal(
2020     LPUNKNOWN pUnk,
2021     BOOL fLock,
2022     BOOL fLastUnlockReleases)
2023 {
2024     struct stub_manager *stubmgr;
2025     struct apartment *apt;
2026
2027     TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
2028           pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2029
2030     apt = COM_CurrentApt();
2031     if (!apt) return CO_E_NOTINITIALIZED;
2032
2033     stubmgr = get_stub_manager_from_object(apt, pUnk);
2034     
2035     if (stubmgr)
2036     {
2037         if (fLock)
2038             stub_manager_ext_addref(stubmgr, 1);
2039         else
2040             stub_manager_ext_release(stubmgr, 1);
2041         
2042         stub_manager_int_release(stubmgr);
2043
2044         return S_OK;
2045     }
2046     else
2047     {
2048         WARN("stub object not found %p\n", pUnk);
2049         /* Note: native is pretty broken here because it just silently
2050          * fails, without returning an appropriate error code, making apps
2051          * think that the object was disconnected, when it actually wasn't */
2052         return S_OK;
2053     }
2054 }
2055
2056 /***********************************************************************
2057  *           CoInitializeWOW (OLE32.@)
2058  *
2059  * WOW equivalent of CoInitialize?
2060  *
2061  * PARAMS
2062  *  x [I] Unknown.
2063  *  y [I] Unknown.
2064  *
2065  * RETURNS
2066  *  Unknown.
2067  */
2068 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
2069 {
2070     FIXME("(0x%08lx,0x%08lx),stub!\n",x,y);
2071     return 0;
2072 }
2073
2074 /***********************************************************************
2075  *           CoGetState [OLE32.@]
2076  *
2077  * Retrieves the thread state object previously stored by CoSetState().
2078  *
2079  * PARAMS
2080  *  ppv [I] Address where pointer to object will be stored.
2081  *
2082  * RETURNS
2083  *  Success: S_OK.
2084  *  Failure: E_OUTOFMEMORY.
2085  *
2086  * NOTES
2087  *  Crashes on all invalid ppv addresses, including NULL.
2088  *  If the function returns a non-NULL object then the caller must release its
2089  *  reference on the object when the object is no longer required.
2090  *
2091  * SEE ALSO
2092  *  CoSetState().
2093  */
2094 HRESULT WINAPI CoGetState(IUnknown ** ppv)
2095 {
2096     struct oletls *info = COM_CurrentInfo();
2097     if (!info) return E_OUTOFMEMORY;
2098
2099     *ppv = NULL;
2100
2101     if (info->state)
2102     {
2103         IUnknown_AddRef(info->state);
2104         *ppv = info->state;
2105         TRACE("apt->state=%p\n", info->state);
2106     }
2107
2108     return S_OK;
2109 }
2110
2111 /***********************************************************************
2112  *           CoSetState [OLE32.@]
2113  *
2114  * Sets the thread state object.
2115  *
2116  * PARAMS
2117  *  pv [I] Pointer to state object to be stored.
2118  *
2119  * NOTES
2120  *  The system keeps a reference on the object while the object stored.
2121  *
2122  * RETURNS
2123  *  Success: S_OK.
2124  *  Failure: E_OUTOFMEMORY.
2125  */
2126 HRESULT WINAPI CoSetState(IUnknown * pv)
2127 {
2128     struct oletls *info = COM_CurrentInfo();
2129     if (!info) return E_OUTOFMEMORY;
2130
2131     if (pv) IUnknown_AddRef(pv);
2132
2133     if (info->state)
2134     {
2135         TRACE("-- release %p now\n", info->state);
2136         IUnknown_Release(info->state);
2137     }
2138
2139     info->state = pv;
2140
2141     return S_OK;
2142 }
2143
2144
2145 /******************************************************************************
2146  *              OleGetAutoConvert        [OLE32.@]
2147  */
2148 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2149 {
2150     HKEY hkey = 0;
2151     char buf[200];
2152     WCHAR wbuf[200];
2153     DWORD len;
2154     HRESULT res = S_OK;
2155
2156     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2157     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2158     {
2159         res = REGDB_E_CLASSNOTREG;
2160         goto done;
2161     }
2162     len = 200;
2163     /* we can just query for the default value of AutoConvertTo key like that,
2164        without opening the AutoConvertTo key and querying for NULL (default) */
2165     if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
2166     {
2167         res = REGDB_E_KEYMISSING;
2168         goto done;
2169     }
2170     MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2171     CLSIDFromString(wbuf,pClsidNew);
2172 done:
2173     if (hkey) RegCloseKey(hkey);
2174     return res;
2175 }
2176
2177 /******************************************************************************
2178  *              CoTreatAsClass        [OLE32.@]
2179  *
2180  * Sets the TreatAs value of a class.
2181  *
2182  * PARAMS
2183  *  clsidOld [I] Class to set TreatAs value on.
2184  *  clsidNew [I] The class the clsidOld should be treated as.
2185  *
2186  * RETURNS
2187  *  Success: S_OK.
2188  *  Failure: HRESULT code.
2189  *
2190  * SEE ALSO
2191  *  CoGetTreatAsClass
2192  */
2193 HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
2194 {
2195     HKEY hkey = 0;
2196     char buf[47];
2197     char szClsidNew[39];
2198     HRESULT res = S_OK;
2199     char auto_treat_as[39];
2200     LONG auto_treat_as_size = sizeof(auto_treat_as);
2201     CLSID id;
2202
2203     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2204     WINE_StringFromCLSID(clsidNew, szClsidNew);
2205     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2206     {
2207         res = REGDB_E_CLASSNOTREG;
2208         goto done;
2209     }
2210     if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2211     {
2212        if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) &&
2213            !__CLSIDFromStringA(auto_treat_as, &id))
2214        {
2215            if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1))
2216            {
2217                res = REGDB_E_WRITEREGDB;
2218                goto done;
2219            }
2220        }
2221        else
2222        {
2223            RegDeleteKeyA(hkey, "TreatAs");
2224            goto done;
2225        }
2226     }
2227     else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
2228     {
2229        res = REGDB_E_WRITEREGDB;
2230         goto done;
2231     }
2232
2233 done:
2234     if (hkey) RegCloseKey(hkey);
2235     return res;
2236 }
2237
2238 /******************************************************************************
2239  *              CoGetTreatAsClass        [OLE32.@]
2240  *
2241  * Gets the TreatAs value of a class.
2242  *
2243  * PARAMS
2244  *  clsidOld [I] Class to get the TreatAs value of.
2245  *  clsidNew [I] The class the clsidOld should be treated as.
2246  *
2247  * RETURNS
2248  *  Success: S_OK.
2249  *  Failure: HRESULT code.
2250  *
2251  * SEE ALSO
2252  *  CoSetTreatAsClass
2253  */
2254 HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
2255 {
2256     HKEY hkey = 0;
2257     char buf[200], szClsidNew[200];
2258     HRESULT res = S_OK;
2259     LONG len = sizeof(szClsidNew);
2260
2261     FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2262     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2263     memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */
2264
2265     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2266     {
2267         res = REGDB_E_CLASSNOTREG;
2268         goto done;
2269     }
2270     if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len))
2271     {
2272         res = S_FALSE;
2273         goto done;
2274     }
2275     res = __CLSIDFromStringA(szClsidNew,clsidNew);
2276     if (FAILED(res))
2277         FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res);
2278 done:
2279     if (hkey) RegCloseKey(hkey);
2280     return res;
2281
2282 }
2283
2284 /******************************************************************************
2285  *              CoGetCurrentProcess     [OLE32.@]
2286  *              CoGetCurrentProcess     [COMPOBJ.34]
2287  *
2288  * Gets the current process ID.
2289  *
2290  * RETURNS
2291  *  The current process ID.
2292  *
2293  * NOTES
2294  *   Is DWORD really the correct return type for this function?
2295  */
2296 DWORD WINAPI CoGetCurrentProcess(void)
2297 {
2298         return GetCurrentProcessId();
2299 }
2300
2301 /******************************************************************************
2302  *              CoRegisterMessageFilter [OLE32.@]
2303  *
2304  * Registers a message filter.
2305  *
2306  * PARAMS
2307  *  lpMessageFilter [I] Pointer to interface.
2308  *  lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
2309  *
2310  * RETURNS
2311  *  Success: S_OK.
2312  *  Failure: HRESULT code.
2313  */
2314 HRESULT WINAPI CoRegisterMessageFilter(
2315     LPMESSAGEFILTER lpMessageFilter,
2316     LPMESSAGEFILTER *lplpMessageFilter)
2317 {
2318     FIXME("stub\n");
2319     if (lplpMessageFilter) {
2320         *lplpMessageFilter = NULL;
2321     }
2322     return S_OK;
2323 }
2324
2325 /***********************************************************************
2326  *           CoIsOle1Class [OLE32.@]
2327  *
2328  * Determines whether the specified class an OLE v1 class.
2329  *
2330  * PARAMS
2331  *  clsid [I] Class to test.
2332  *
2333  * RETURNS
2334  *  TRUE if the class is an OLE v1 class, or FALSE otherwise.
2335  */
2336 BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
2337 {
2338   FIXME("%s\n", debugstr_guid(clsid));
2339   return FALSE;
2340 }
2341
2342 /***********************************************************************
2343  *           IsEqualGUID [OLE32.@]
2344  *
2345  * Compares two Unique Identifiers.
2346  *
2347  * PARAMS
2348  *  rguid1 [I] The first GUID to compare.
2349  *  rguid2 [I] The other GUID to compare.
2350  *
2351  * RETURNS
2352  *      TRUE if equal
2353  */
2354 #undef IsEqualGUID
2355 BOOL WINAPI IsEqualGUID(
2356      REFGUID rguid1,
2357      REFGUID rguid2)
2358 {
2359     return !memcmp(rguid1,rguid2,sizeof(GUID));
2360 }
2361
2362 /***********************************************************************
2363  *           CoInitializeSecurity [OLE32.@]
2364  */
2365 HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
2366                                     SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
2367                                     void* pReserved1, DWORD dwAuthnLevel,
2368                                     DWORD dwImpLevel, void* pReserved2,
2369                                     DWORD dwCapabilities, void* pReserved3)
2370 {
2371   FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc,
2372         asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
2373         dwCapabilities, pReserved3);
2374   return S_OK;
2375 }
2376
2377 /***********************************************************************
2378  *           CoSuspendClassObjects [OLE32.@]
2379  *
2380  * Suspends all registered class objects to prevent further requests coming in
2381  * for those objects.
2382  *
2383  * RETURNS
2384  *  Success: S_OK.
2385  *  Failure: HRESULT code.
2386  */
2387 HRESULT WINAPI CoSuspendClassObjects(void)
2388 {
2389     FIXME("\n");
2390     return S_OK;
2391 }
2392
2393 /***********************************************************************
2394  *           CoAddRefServerProcess [OLE32.@]
2395  *
2396  * Helper function for incrementing the reference count of a local-server
2397  * process.
2398  *
2399  * RETURNS
2400  *  New reference count.
2401  */
2402 ULONG WINAPI CoAddRefServerProcess(void)
2403 {
2404     FIXME("\n");
2405     return 2;
2406 }
2407
2408 /***********************************************************************
2409  *           CoReleaseServerProcess [OLE32.@]
2410  *
2411  * Helper function for decrementing the reference count of a local-server
2412  * process.
2413  *
2414  * RETURNS
2415  *  New reference count.
2416  */
2417 ULONG WINAPI CoReleaseServerProcess(void)
2418 {
2419     FIXME("\n");
2420     return 1;
2421 }
2422
2423 /***********************************************************************
2424  *           CoQueryProxyBlanket [OLE32.@]
2425  *
2426  * Retrieves the security settings being used by a proxy.
2427  *
2428  * PARAMS
2429  *  pProxy        [I] Pointer to the proxy object.
2430  *  pAuthnSvc     [O] The type of authentication service.
2431  *  pAuthzSvc     [O] The type of authorization service.
2432  *  ppServerPrincName [O] Optional. The server prinicple name.
2433  *  pAuthnLevel   [O] The authentication level.
2434  *  pImpLevel     [O] The impersonation level.
2435  *  ppAuthInfo    [O] Information specific to the authorization/authentication service.
2436  *  pCapabilities [O] Flags affecting the security behaviour.
2437  *
2438  * RETURNS
2439  *  Success: S_OK.
2440  *  Failure: HRESULT code.
2441  *
2442  * SEE ALSO
2443  *  CoCopyProxy, CoSetProxyBlanket.
2444  */
2445 HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
2446     DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
2447     DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
2448 {
2449     IClientSecurity *pCliSec;
2450     HRESULT hr;
2451
2452     TRACE("%p\n", pProxy);
2453
2454     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2455     if (SUCCEEDED(hr))
2456     {
2457         hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
2458                                           pAuthzSvc, ppServerPrincName,
2459                                           pAuthnLevel, pImpLevel, ppAuthInfo,
2460                                           pCapabilities);
2461         IClientSecurity_Release(pCliSec);
2462     }
2463
2464     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2465     return hr;
2466 }
2467
2468 /***********************************************************************
2469  *           CoSetProxyBlanket [OLE32.@]
2470  *
2471  * Sets the security settings for a proxy.
2472  *
2473  * PARAMS
2474  *  pProxy       [I] Pointer to the proxy object.
2475  *  AuthnSvc     [I] The type of authentication service.
2476  *  AuthzSvc     [I] The type of authorization service.
2477  *  pServerPrincName [I] The server prinicple name.
2478  *  AuthnLevel   [I] The authentication level.
2479  *  ImpLevel     [I] The impersonation level.
2480  *  pAuthInfo    [I] Information specific to the authorization/authentication service.
2481  *  Capabilities [I] Flags affecting the security behaviour.
2482  *
2483  * RETURNS
2484  *  Success: S_OK.
2485  *  Failure: HRESULT code.
2486  *
2487  * SEE ALSO
2488  *  CoQueryProxyBlanket, CoCopyProxy.
2489  */
2490 HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
2491     DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
2492     DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
2493 {
2494     IClientSecurity *pCliSec;
2495     HRESULT hr;
2496
2497     TRACE("%p\n", pProxy);
2498
2499     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2500     if (SUCCEEDED(hr))
2501     {
2502         hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
2503                                         AuthzSvc, pServerPrincName,
2504                                         AuthnLevel, ImpLevel, pAuthInfo,
2505                                         Capabilities);
2506         IClientSecurity_Release(pCliSec);
2507     }
2508
2509     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2510     return hr;
2511 }
2512
2513 /***********************************************************************
2514  *           CoCopyProxy [OLE32.@]
2515  *
2516  * Copies a proxy.
2517  *
2518  * PARAMS
2519  *  pProxy [I] Pointer to the proxy object.
2520  *  ppCopy [O] Copy of the proxy.
2521  *
2522  * RETURNS
2523  *  Success: S_OK.
2524  *  Failure: HRESULT code.
2525  *
2526  * SEE ALSO
2527  *  CoQueryProxyBlanket, CoSetProxyBlanket.
2528  */
2529 HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
2530 {
2531     IClientSecurity *pCliSec;
2532     HRESULT hr;
2533
2534     TRACE("%p\n", pProxy);
2535
2536     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
2537     if (SUCCEEDED(hr))
2538     {
2539         hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
2540         IClientSecurity_Release(pCliSec);
2541     }
2542
2543     if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr);
2544     return hr;
2545 }