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