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