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