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