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