update for HEAD-2003091401
[reactos.git] / lib / 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  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <windows.h>
15 #include <ole32/ole32.h>
16 #include <compobj.h>
17 #include <storage32.h>
18
19 #include <debug.h>
20
21 /****************************************************************************
22  *  COM External Lock structures and methods declaration
23  *
24  *  This api provides a linked list to managed external references to 
25  *  COM objects.  
26  *
27  *  The public interface consists of three calls: 
28  *      COM_ExternalLockAddRef
29  *      COM_ExternalLockRelease
30  *      COM_ExternalLockFreeList
31  */
32
33 #define EL_END_OF_LIST 0
34 #define EL_NOT_FOUND   0
35
36 /*
37  * Declaration of the static structure that manage the 
38  * external lock to COM  objects.
39  */
40 typedef struct COM_ExternalLock     COM_ExternalLock;
41 typedef struct COM_ExternalLockList COM_ExternalLockList;
42
43 struct COM_ExternalLock
44 {
45   IUnknown         *pUnk;     /* IUnknown referenced */
46   ULONG            uRefCount; /* external lock counter to IUnknown object*/
47   COM_ExternalLock *next;     /* Pointer to next element in list */
48 };
49
50 struct COM_ExternalLockList
51 {
52   COM_ExternalLock *head;     /* head of list */
53 };
54
55 /*
56  * Declaration and initialization of the static structure that manages
57  * the external lock to COM objects.
58  */
59 static COM_ExternalLockList elList = { EL_END_OF_LIST };
60
61 /*
62  * Public Interface to the external lock list   
63  */
64 static void COM_ExternalLockFreeList();
65 static void COM_ExternalLockAddRef(IUnknown *pUnk);
66 static void COM_ExternalLockRelease(IUnknown *pUnk, BOOL bRelAll);
67 void COM_ExternalLockDump(); /* testing purposes, not static to avoid warning */
68
69 /*
70  * Private methods used to managed the linked list   
71  */
72 static BOOL COM_ExternalLockInsert(
73   IUnknown *pUnk);
74
75 static void COM_ExternalLockDelete(
76   COM_ExternalLock *element);
77
78 static COM_ExternalLock* COM_ExternalLockFind(
79   IUnknown *pUnk);
80
81 static COM_ExternalLock* COM_ExternalLockLocate(
82   COM_ExternalLock *element,
83   IUnknown         *pUnk);
84
85 /****************************************************************************
86  * This section defines variables internal to the COM module.
87  *
88  * TODO: Most of these things will have to be made thread-safe.
89  */
90 HINSTANCE       COMPOBJ_hInstance32 = 0;
91 static int      COMPOBJ_Attach = 0;
92
93 LPMALLOC currentMalloc32=NULL;
94
95 WORD Table_ETask[62];
96
97 /*
98  * This lock count counts the number of times CoInitialize is called. It is
99  * decreased every time CoUninitialize is called. When it hits 0, the COM
100  * libraries are freed
101  */
102 static ULONG s_COMLockCount = 0;
103
104 /*
105  * This linked list contains the list of registered class objects. These
106  * are mostly used to register the factories for out-of-proc servers of OLE
107  * objects.
108  *
109  * TODO: Make this data structure aware of inter-process communication. This
110  *       means that parts of this will be exported to the Wine Server.
111  */
112 typedef struct tagRegisteredClass
113 {
114   CLSID     classIdentifier;
115   LPUNKNOWN classObject;
116   DWORD     runContext;
117   DWORD     connectFlags;
118   DWORD     dwCookie;
119   struct tagRegisteredClass* nextClass;
120 } RegisteredClass;
121
122 static RegisteredClass* firstRegisteredClass = NULL;
123
124 /* this open DLL table belongs in a per process table, but my guess is that
125  * it shouldn't live in the kernel, so I'll put them out here in DLL
126  * space assuming that there is one OLE32 per process.
127  */
128 typedef struct tagOpenDll {
129   HINSTANCE hLibrary;       
130   struct tagOpenDll *next;
131 } OpenDll;
132
133 static OpenDll *openDllList = NULL; /* linked list of open dlls */
134
135 /*****************************************************************************
136  * This section contains prototypes to internal methods for this
137  * module
138  */
139 static HRESULT COM_GetRegisteredClassObject(REFCLSID    rclsid,
140                                             DWORD       dwClsContext,
141                                             LPUNKNOWN*  ppUnk);
142
143 static void COM_RevokeAllClasses();
144
145
146 /******************************************************************************
147  *           CoBuildVersion [COMPOBJ.1]
148  *
149  * RETURNS
150  *      Current build version, hiword is majornumber, loword is minornumber
151  */
152 DWORD WINAPI CoBuildVersion(void)
153 {
154     Print(MAX_TRACE, ("Returning version %d, build %d.\n", 1, 0));
155     return (1<<16)+0;
156 }
157
158 /******************************************************************************
159  *              CoInitialize16  [COMPOBJ.2]
160  * Set the win16 IMalloc used for memory management
161  */
162 HRESULT WINAPI CoInitialize16(
163         LPVOID lpReserved       /* [in] pointer to win16 malloc interface */
164 ) {
165   UNIMPLEMENTED;
166   return S_OK;
167 }
168
169 /******************************************************************************
170  *              CoInitialize    [OLE32.26]
171  *
172  * Initializes the COM libraries.
173  *
174  * See CoInitializeEx
175  */
176 HRESULT WINAPI CoInitialize(
177         LPVOID lpReserved       /* [in] pointer to win32 malloc interface
178                                    (obsolete, should be NULL) */
179
180 {
181 #if 0
182   /*
183    * Just delegate to the newer method.
184    */
185   return CoInitializeEx(lpReserved, )COINIT_APARTMENTTHREADED);
186 #else
187   return E_FAIL;
188 #endif
189 }
190
191 /******************************************************************************
192  *              CoInitializeEx  [OLE32.163]
193  *
194  * Initializes the COM libraries. The behavior used to set the win32 IMalloc
195  * used for memory management is obsolete.
196  *
197  * RETURNS
198  *  S_OK               if successful,
199  *  S_FALSE            if this function was called already.
200  *  RPC_E_CHANGED_MODE if a previous call to CoInitialize specified another
201  *                      threading model.
202  *
203  * BUGS
204  * Only the single threaded model is supported. As a result RPC_E_CHANGED_MODE 
205  * is never returned.
206  *
207  * See the windows documentation for more details.
208  */
209 HRESULT WINAPI CoInitializeEx(
210         LPVOID lpReserved,      /* [in] pointer to win32 malloc interface
211                                    (obsolete, should be NULL) */
212         DWORD dwCoInit          /* [in] A value from COINIT specifies the threading model */
213
214 {
215   HRESULT hr;
216
217   Print(MAX_TRACE, ("(%p, %x)\n", lpReserved, (int)dwCoInit));
218
219   if (lpReserved!=NULL)
220   {
221     Print(MIN_TRACE, ("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved));
222   }
223
224   /*
225    * Check for unsupported features.
226    */
227   if (dwCoInit!=COINIT_APARTMENTTHREADED) 
228   {
229     Print(MAX_TRACE, (":(%p,%x): unsupported flag %x\n", lpReserved, (int)dwCoInit, (int)dwCoInit));
230     /* Hope for the best and continue anyway */
231   }
232
233   /*
234    * Check the lock count. If this is the first time going through the initialize
235    * process, we have to initialize the libraries.
236    */
237   if (s_COMLockCount==0)
238   {
239     /*
240      * Initialize the various COM libraries and data structures.
241      */
242     Print(MAX_TRACE, ("() - Initializing the COM libraries\n"));
243
244     RunningObjectTableImpl_Initialize();
245
246     hr = S_OK;
247   }
248   else
249     hr = S_FALSE;
250
251   /*
252    * Crank-up that lock count.
253    */
254   s_COMLockCount++;
255
256   return hr;
257 }
258
259 /***********************************************************************
260  *           CoUninitialize16   [COMPOBJ.3]
261  * Don't know what it does. 
262  * 3-Nov-98 -- this was originally misspelled, I changed it to what I
263  *   believe is the correct spelling
264  */
265 void WINAPI CoUninitialize16(void)
266 {
267   Print(MAX_TRACE, ("Called\n"));
268   CoFreeAllLibraries();
269 }
270
271 /***********************************************************************
272  *           CoUninitialize   [OLE32.47]
273  *
274  * This method will release the COM libraries.
275  *
276  * See the windows documentation for more details.
277  */
278 void WINAPI CoUninitialize(void)
279 {
280   Print(MAX_TRACE, ("Called\n"));
281   
282   /*
283    * Decrease the reference count.
284    */
285   s_COMLockCount--;
286   
287   /*
288    * If we are back to 0 locks on the COM library, make sure we free
289    * all the associated data structures.
290    */
291   if (s_COMLockCount==0)
292   {
293     /*
294      * Release the various COM libraries and data structures.
295      */
296     Print(MAX_TRACE, ("() - Releasing the COM libraries\n"));
297
298     RunningObjectTableImpl_UnInitialize();
299     /*
300      * Release the references to the registered class objects.
301      */
302     COM_RevokeAllClasses();
303
304     /*
305      * This will free the loaded COM Dlls.
306      */
307     CoFreeAllLibraries();
308
309     /*
310      * This will free list of external references to COM objects.
311      */
312     COM_ExternalLockFreeList();
313 }
314 }
315
316 /***********************************************************************
317  *           CoGetMalloc16    [COMPOBJ.4]
318  * RETURNS
319  *      The current win16 IMalloc
320  */
321 HRESULT WINAPI CoGetMalloc16(
322         DWORD dwMemContext,     /* [in] unknown */
323         PVOID lpMalloc  /* [out] current win16 malloc interface */
324 ) {
325   UNIMPLEMENTED;
326   return S_OK;
327 }
328
329 /******************************************************************************
330  *              CoGetMalloc     [OLE32.20]
331  *
332  * RETURNS
333  *      The current win32 IMalloc
334  */
335 HRESULT WINAPI CoGetMalloc(
336         DWORD dwMemContext,     /* [in] unknown */
337         LPMALLOC *lpMalloc      /* [out] current win32 malloc interface */
338 ) {
339 #if 0
340     if(!currentMalloc32)
341         currentMalloc32 = IMalloc_Constructor();
342     *lpMalloc = currentMalloc32;
343     return S_OK;
344 #else
345   UNIMPLEMENTED;
346   return S_OK;
347 #endif
348 }
349
350 /***********************************************************************
351  *           CoCreateStandardMalloc16 [COMPOBJ.71]
352  */
353 HRESULT WINAPI CoCreateStandardMalloc16(DWORD dwMemContext,
354                                           PVOID lpMalloc)
355 {
356   UNIMPLEMENTED;
357   return S_OK;
358 }
359
360 /******************************************************************************
361  *              CoDisconnectObject      [COMPOBJ.15]
362  */
363 HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
364 {
365     Print(MAX_TRACE, ("(%p, %lx)\n",lpUnk,reserved));
366     return S_OK;
367 }
368
369 /***********************************************************************
370  *           IsEqualGUID16 [COMPOBJ.18]
371  *
372  * Compares two Unique Identifiers.
373  *
374  * RETURNS
375  *      TRUE if equal
376  */
377 BOOL WINAPI IsEqualGUID16(
378         GUID* g1,       /* [in] unique id 1 */
379         GUID* g2        /* [in] unique id 2 */
380 ) {
381     return !memcmp( g1, g2, sizeof(GUID) );
382 }
383
384 /******************************************************************************
385  *              CLSIDFromString16       [COMPOBJ.20]
386  * Converts a unique identifier from its string representation into 
387  * the GUID struct.
388  *
389  * Class id: DWORD-WORD-WORD-BYTES[2]-BYTES[6] 
390  *
391  * RETURNS
392  *      the converted GUID
393  */
394 HRESULT WINAPI CLSIDFromString16(
395         LPCOLESTR16 idstr,      /* [in] string representation of guid */
396         CLSID *id               /* [out] GUID converted from string */
397 ) {
398   BYTE *s = (BYTE *) idstr;
399   BYTE *p;
400   int   i;
401   BYTE table[256];
402
403   if (!s)
404           s = "{00000000-0000-0000-0000-000000000000}";
405   else {  /* validate the CLSID string */
406
407       if (strlen(s) != 38)
408           return CO_E_CLASSSTRING;
409
410       if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
411           return CO_E_CLASSSTRING;
412
413       for (i=1; i<37; i++)
414       {
415           if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
416           if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
417                 ((s[i] >= 'a') && (s[i] <= 'f'))  ||
418                 ((s[i] >= 'A') && (s[i] <= 'F')))
419              )
420               return CO_E_CLASSSTRING;
421       }
422   }
423
424   Print(MAX_TRACE, ("%s -> %p\n", s, id));
425
426   /* quick lookup table */
427   memset(table, 0, 256);
428
429   for (i = 0; i < 10; i++) {
430     table['0' + i] = i;
431   }
432   for (i = 0; i < 6; i++) {
433     table['A' + i] = i+10;
434     table['a' + i] = i+10;
435   }
436
437   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
438
439   p = (BYTE *) id;
440
441   s++;  /* skip leading brace  */
442   for (i = 0; i < 4; i++) {
443     p[3 - i] = table[*s]<<4 | table[*(s+1)];
444     s += 2;
445   }
446   p += 4;
447   s++;  /* skip - */
448
449   for (i = 0; i < 2; i++) {
450     p[1-i] = table[*s]<<4 | table[*(s+1)];
451     s += 2;
452   }
453   p += 2;
454   s++;  /* skip - */
455
456   for (i = 0; i < 2; i++) {
457     p[1-i] = table[*s]<<4 | table[*(s+1)];
458     s += 2;
459   }
460   p += 2;
461   s++;  /* skip - */
462
463   /* these are just sequential bytes */
464   for (i = 0; i < 2; i++) {
465     *p++ = table[*s]<<4 | table[*(s+1)];
466     s += 2;
467   }
468   s++;  /* skip - */
469
470   for (i = 0; i < 6; i++) {
471     *p++ = table[*s]<<4 | table[*(s+1)];
472     s += 2;
473   }
474
475   return S_OK;
476 }
477
478 /******************************************************************************
479  *              CoCreateGuid[OLE32.6]
480  *
481  */
482 HRESULT WINAPI CoCreateGuid(
483         GUID *pguid /* [out] points to the GUID to initialize */
484 ) {
485     return UuidCreate(pguid);
486 }
487
488 /******************************************************************************
489  *              CLSIDFromString [OLE32.3]
490  * Converts a unique identifier from its string representation into 
491  * the GUID struct.
492  *
493  * UNDOCUMENTED
494  *      If idstr is not a valid CLSID string then it gets treated as a ProgID
495  *
496  * RETURNS
497  *      the converted GUID
498  */
499 HRESULT WINAPI CLSIDFromString(
500         LPCOLESTR idstr,        /* [in] string representation of GUID */
501         CLSID *id               /* [out] GUID represented by above string */
502 ) {
503 #if 0
504     LPOLESTR16      xid = HEAP_strdupWtoA(GetProcessHeap(),0,idstr);
505     HRESULT       ret = CLSIDFromString16(xid,id);
506
507     HeapFree(GetProcessHeap(),0,xid);
508     if(ret != S_OK) { /* It appears a ProgID is also valid */
509         ret = CLSIDFromProgID(idstr, id);
510     }
511     return ret;
512 #else
513   UNIMPLEMENTED;
514   return (HRESULT)0;
515 #endif
516 }
517
518 /******************************************************************************
519  *              WINE_StringFromCLSID    [Internal]
520  * Converts a GUID into the respective string representation.
521  *
522  * NOTES
523  *
524  * RETURNS
525  *      the string representation and HRESULT
526  */
527 static HRESULT WINE_StringFromCLSID(
528         const CLSID *id,        /* [in] GUID to be converted */
529         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
530 ) {
531   static const char *hex = "0123456789ABCDEF";
532   char *s;
533   int   i;
534
535   if (!id)
536         { Print(MIN_TRACE, ("called with id=Null\n"));
537           *idstr = 0x00;
538           return E_FAIL;
539         }
540         
541   sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-",
542           id->Data1, id->Data2, id->Data3,
543           id->Data4[0], id->Data4[1]);
544   s = &idstr[25];
545
546   /* 6 hex bytes */
547   for (i = 2; i < 8; i++) {
548     *s++ = hex[id->Data4[i]>>4];
549     *s++ = hex[id->Data4[i] & 0xf];
550   }
551
552   *s++ = '}';
553   *s++ = '\0';
554
555   Print(MAX_TRACE, ("%p->%s\n", id, idstr));
556
557   return S_OK;
558 }
559
560 /******************************************************************************
561  *              StringFromCLSID16       [COMPOBJ.19]
562  * Converts a GUID into the respective string representation.
563  * The target string is allocated using the OLE IMalloc.
564  * RETURNS
565  *      the string representation and HRESULT
566  */
567 HRESULT WINAPI StringFromCLSID16(
568         REFCLSID id,            /* [in] the GUID to be converted */
569         LPOLESTR16 *idstr       /* [out] a pointer to a to-be-allocated segmented pointer pointing to the resulting string */
570
571 ) {
572 #if 0
573     extern BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
574                                            DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode );
575     LPMALLOC16  mllc;
576     HRESULT     ret;
577     DWORD       args[2];
578
579     ret = CoGetMalloc16(0,&mllc);
580     if (ret) return ret;
581
582     args[0] = (DWORD)mllc;
583     args[1] = 40;
584
585     /* No need for a Callback entry, we have WOWCallback16Ex which does
586      * everything we need.
587      */
588     if (!K32WOWCallback16Ex(
589         (DWORD)((ICOM_VTABLE(IMalloc16)*)MapSL(
590             (SEGPTR)ICOM_VTBL(((LPMALLOC16)MapSL((SEGPTR)mllc))))
591         )->Alloc,
592         WCB16_CDECL,
593         2*sizeof(DWORD),
594         (LPVOID)args,
595         (LPDWORD)idstr
596     )) {
597         WARN("CallTo16 IMalloc16 failed\n");
598         return E_FAIL;
599     }
600     return WINE_StringFromCLSID(id,MapSL((SEGPTR)*idstr));
601 #else
602   UNIMPLEMENTED;
603   return (HRESULT)0;
604 #endif
605 }
606
607 /******************************************************************************
608  *              StringFromCLSID [OLE32.151]
609  * Converts a GUID into the respective string representation.
610  * The target string is allocated using the OLE IMalloc.
611  * RETURNS
612  *      the string representation and HRESULT
613  */
614 HRESULT WINAPI StringFromCLSID(
615         REFCLSID id,            /* [in] the GUID to be converted */
616         LPOLESTR *idstr /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
617 ) {
618         char            buf[80];
619         HRESULT       ret;
620         LPMALLOC        mllc;
621
622         if ((ret=CoGetMalloc(0,&mllc)))
623                 return ret;
624
625         ret=WINE_StringFromCLSID(id,buf);
626         if (!ret) {
627             DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
628             *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
629             MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
630         }
631         IMalloc_Release ( mllc );
632         return ret;
633 }
634
635 /******************************************************************************
636  *              StringFromGUID2 [COMPOBJ.76] [OLE32.152]
637  *
638  * Converts a global unique identifier into a string of an API-
639  * specified fixed format. (The usual {.....} stuff.)
640  *
641  * RETURNS
642  *      The (UNICODE) string representation of the GUID in 'str'
643  *      The length of the resulting string, 0 if there was any problem.
644  */
645 INT WINAPI
646 StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
647 {
648   char          xguid[80];
649
650   if (WINE_StringFromCLSID(id,xguid))
651         return 0;
652   return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
653 }
654
655 /******************************************************************************
656  * ProgIDFromCLSID [OLE32.133]
657  * Converts a class id into the respective Program ID. (By using a registry lookup)
658  * RETURNS S_OK on success
659  * riid associated with the progid
660  */
661
662 HRESULT WINAPI ProgIDFromCLSID(
663   REFCLSID clsid, /* [in] class id as found in registry */
664   LPOLESTR *lplpszProgID/* [out] associated Prog ID */
665 )
666 {
667   char     strCLSID[50], *buf, *buf2;
668   DWORD    buf2len;
669   HKEY     xhkey;
670   LPMALLOC mllc;
671   HRESULT  ret = S_OK;
672
673   WINE_StringFromCLSID(clsid, strCLSID);
674
675   buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14);
676   sprintf(buf,"CLSID\\%s\\ProgID", strCLSID);
677   if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
678     ret = REGDB_E_CLASSNOTREG;
679
680   HeapFree(GetProcessHeap(), 0, buf);
681
682   if (ret == S_OK)
683   {
684     buf2 = HeapAlloc(GetProcessHeap(), 0, 255);
685     buf2len = 255;
686     if (RegQueryValueA(xhkey, NULL, buf2, &buf2len))
687       ret = REGDB_E_CLASSNOTREG;
688
689     if (ret == S_OK)
690     {
691       if (CoGetMalloc(0,&mllc))
692         ret = E_OUTOFMEMORY;
693       else
694       {
695           DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 );
696           *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) );
697           MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len );
698       }
699     }
700     HeapFree(GetProcessHeap(), 0, buf2);
701   }
702
703   RegCloseKey(xhkey);
704   return ret;
705 }
706
707 /******************************************************************************
708  *              CLSIDFromProgID16       [COMPOBJ.61]
709  * Converts a program id into the respective GUID. (By using a registry lookup)
710  * RETURNS
711  *      riid associated with the progid
712  */
713 HRESULT WINAPI CLSIDFromProgID16(
714         LPCOLESTR16 progid,     /* [in] program id as found in registry */
715         LPCLSID riid            /* [out] associated CLSID */
716 ) {
717         char    *buf,buf2[80];
718         DWORD   buf2len;
719         HRESULT err;
720         HKEY    xhkey;
721
722         buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
723         sprintf(buf,"%s\\CLSID",progid);
724         if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) {
725                 HeapFree(GetProcessHeap(),0,buf);
726                 return CO_E_CLASSSTRING;
727         }
728         HeapFree(GetProcessHeap(),0,buf);
729         buf2len = sizeof(buf2);
730         if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) {
731                 RegCloseKey(xhkey);
732                 return CO_E_CLASSSTRING;
733         }
734         RegCloseKey(xhkey);
735         return CLSIDFromString16(buf2,riid);
736 }
737
738 /******************************************************************************
739  *              CLSIDFromProgID [OLE32.2]
740  * Converts a program id into the respective GUID. (By using a registry lookup)
741  * RETURNS
742  *      riid associated with the progid
743  */
744 HRESULT WINAPI CLSIDFromProgID(
745         LPCOLESTR progid,       /* [in] program id as found in registry */
746         LPCLSID riid            /* [out] associated CLSID */
747 ) {
748 #if 0
749         LPOLESTR16 pid = HEAP_strdupWtoA(GetProcessHeap(),0,progid);
750         HRESULT       ret = CLSIDFromProgID16(pid,riid);
751
752         HeapFree(GetProcessHeap(),0,pid);
753         return ret;
754 #else
755   UNIMPLEMENTED;
756   return (HRESULT)0;
757 #endif
758 }
759
760
761
762 /*****************************************************************************
763  *             CoGetPSClsid [OLE32.22]
764  *
765  * This function returns the CLSID of the DLL that implements the proxy and stub
766  * for the specified interface. 
767  *
768  * It determines this by searching the 
769  * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 in the registry
770  * and any interface id registered by CoRegisterPSClsid within the current process.
771  * 
772  * FIXME: We only search the registry, not ids registered with CoRegisterPSClsid.
773  */
774 HRESULT WINAPI CoGetPSClsid(
775           REFIID riid,     /* [in]  Interface whose proxy/stub CLSID is to be returned */
776           CLSID *pclsid )    /* [out] Where to store returned proxy/stub CLSID */
777 {
778     char *buf, buf2[40];
779     DWORD buf2len;
780     HKEY xhkey;
781
782     Print(MAX_TRACE, ("() riid=%s, pclsid=%p\n", PRINT_GUID(riid), pclsid));
783
784     /* Get the input iid as a string */
785     WINE_StringFromCLSID(riid, buf2);
786     /* Allocate memory for the registry key we will construct.
787        (length of iid string plus constant length of static text */
788     buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27);
789     if (buf == NULL)
790     {
791        return (E_OUTOFMEMORY);
792     }
793
794     /* Construct the registry key we want */
795     sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2);
796
797     /* Open the key.. */
798     if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey))
799     {
800        HeapFree(GetProcessHeap(),0,buf);
801        return (E_INVALIDARG);
802     }
803     HeapFree(GetProcessHeap(),0,buf);
804
805     /* ... Once we have the key, query the registry to get the
806        value of CLSID as a string, and convert it into a 
807        proper CLSID structure to be passed back to the app */
808     buf2len = sizeof(buf2);
809     if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) )
810     {
811        RegCloseKey(xhkey);
812        return E_INVALIDARG;
813     }
814     RegCloseKey(xhkey);
815
816     /* We have the CLSid we want back from the registry as a string, so
817        lets convert it into a CLSID structure */
818     if ( (CLSIDFromString16(buf2,pclsid)) != NOERROR)
819     {
820        return E_INVALIDARG;
821     }
822
823     Print(MAX_TRACE, ("() Returning CLSID=%s\n", PRINT_GUID(pclsid)));
824     return (S_OK);
825 }
826
827
828
829 /***********************************************************************
830  *              WriteClassStm
831  *
832  * This function write a CLSID on stream
833  */
834 HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid)
835 {
836     Print(MAX_TRACE, ("(%p,%p)\n",pStm,rclsid));
837
838     if (rclsid==NULL)
839         return E_INVALIDARG;
840
841     return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL);
842 }
843
844 /***********************************************************************
845  *              ReadClassStm
846  *
847  * This function read a CLSID from a stream
848  */
849 HRESULT WINAPI ReadClassStm(IStream *pStm,REFCLSID rclsid)
850 {
851     ULONG nbByte;
852     HRESULT res;
853     
854     Print(MAX_TRACE, ("(%p,%p)\n",pStm,rclsid));
855
856     if (rclsid==NULL)
857         return E_INVALIDARG;
858     
859     res = IStream_Read(pStm,(void*)rclsid,sizeof(CLSID),&nbByte);
860
861     if (FAILED(res))
862         return res;
863     
864     if (nbByte != sizeof(CLSID))
865         return S_FALSE;
866     else
867         return S_OK;
868 }
869
870 /* FIXME: this function is not declared in the WINELIB headers. But where should it go ? */
871 /***********************************************************************
872  *           LookupETask (COMPOBJ.94)
873  */
874 HRESULT WINAPI LookupETask16(PVOID hTask,LPVOID p) {
875         UNIMPLEMENTED;
876   return S_OK;
877 }
878
879 /* FIXME: this function is not declared in the WINELIB headers. But where should it go ? */
880 /***********************************************************************
881  *           SetETask (COMPOBJ.95)
882  */
883 HRESULT WINAPI SetETask16(DWORD hTask, LPVOID p) {
884   UNIMPLEMENTED;
885         return S_OK;
886 }
887
888 /* FIXME: this function is not declared in the WINELIB headers. But where should it go ? */
889 /***********************************************************************
890  *           CallObjectInWOW (COMPOBJ.201)
891  */
892 HRESULT WINAPI CallObjectInWOW(LPVOID p1,LPVOID p2) {
893         UNIMPLEMENTED;
894         return 0;
895 }
896
897 /******************************************************************************
898  *              CoRegisterClassObject16 [COMPOBJ.5]
899  *
900  * Don't know where it registers it ...
901  */
902 HRESULT WINAPI CoRegisterClassObject16(
903         REFCLSID rclsid,
904         LPUNKNOWN pUnk,
905         DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
906         DWORD flags,        /* [in] REGCLS flags indicating how connections are made */
907         LPDWORD lpdwRegister
908 ) {
909         UNIMPLEMENTED;
910         return S_OK;
911 }
912
913
914 /******************************************************************************
915  *      CoRevokeClassObject16 [COMPOBJ.6]
916  *
917  */
918 HRESULT WINAPI CoRevokeClassObject16(DWORD dwRegister) /* [in] token on class obj */
919 {
920     UNIMPLEMENTED;
921     return S_OK;
922 }
923
924
925 /***
926  * COM_GetRegisteredClassObject
927  *
928  * This internal method is used to scan the registered class list to 
929  * find a class object.
930  *
931  * Params: 
932  *   rclsid        Class ID of the class to find.
933  *   dwClsContext  Class context to match.
934  *   ppv           [out] returns a pointer to the class object. Complying
935  *                 to normal COM usage, this method will increase the
936  *                 reference count on this object.
937  */
938 static HRESULT COM_GetRegisteredClassObject(
939         REFCLSID    rclsid,
940         DWORD       dwClsContext,
941         LPUNKNOWN*  ppUnk)
942 {
943   RegisteredClass* curClass;
944
945   /*
946    * Sanity check
947    */
948   assert(ppUnk!=0);
949
950   /*
951    * Iterate through the whole list and try to match the class ID.
952    */
953   curClass = firstRegisteredClass;
954
955   while (curClass != 0)
956   {
957     /*
958      * Check if we have a match on the class ID.
959      */
960     if (IsEqualGUID(&(curClass->classIdentifier), rclsid))
961     {
962       /*
963        * Since we don't do out-of process or DCOM just right away, let's ignore the
964        * class context.
965        */
966
967       /*
968        * We have a match, return the pointer to the class object.
969        */
970       *ppUnk = curClass->classObject;
971
972       IUnknown_AddRef(curClass->classObject);
973
974       return S_OK;
975     }
976
977     /*
978      * Step to the next class in the list.
979      */
980     curClass = curClass->nextClass;
981   }
982
983   /*
984    * If we get to here, we haven't found our class.
985    */
986   return S_FALSE;
987 }
988
989 /******************************************************************************
990  *              CoRegisterClassObject   [OLE32.36]
991  *
992  * This method will register the class object for a given class ID.
993  *
994  * See the Windows documentation for more details.
995  */
996 HRESULT WINAPI CoRegisterClassObject(
997         REFCLSID rclsid,
998         LPUNKNOWN pUnk,
999         DWORD dwClsContext, /* [in] CLSCTX flags indicating the context in which to run the executable */
1000         DWORD flags,        /* [in] REGCLS flags indicating how connections are made */
1001         LPDWORD lpdwRegister
1002
1003 {
1004   RegisteredClass* newClass;
1005   LPUNKNOWN        foundObject;
1006   HRESULT          hr;
1007     char buf[80];
1008
1009     WINE_StringFromCLSID(rclsid,buf);
1010
1011   Print(MAX_TRACE, ("(%s,%p,0x%08lx,0x%08lx,%p)\n",
1012         buf,pUnk,dwClsContext,flags,lpdwRegister));
1013
1014   /*
1015    * Perform a sanity check on the parameters
1016    */
1017   if ( (lpdwRegister==0) || (pUnk==0) )
1018   {
1019     return E_INVALIDARG;
1020 }
1021
1022   /*
1023    * Initialize the cookie (out parameter)
1024    */
1025   *lpdwRegister = 0;
1026
1027   /*
1028    * First, check if the class is already registered.
1029    * If it is, this should cause an error.
1030    */
1031   hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
1032
1033   if (hr == S_OK)
1034   {
1035     /*
1036      * The COM_GetRegisteredClassObject increased the reference count on the
1037      * object so it has to be released.
1038      */
1039     IUnknown_Release(foundObject);
1040
1041     return CO_E_OBJISREG;
1042   }
1043     
1044   /*
1045    * If it is not registered, we must create a new entry for this class and
1046    * append it to the registered class list.
1047    * We use the address of the chain node as the cookie since we are sure it's
1048    * unique.
1049    */
1050   newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1051
1052   /*
1053    * Initialize the node.
1054    */
1055   newClass->classIdentifier = *rclsid;
1056   newClass->runContext      = dwClsContext;
1057   newClass->connectFlags    = flags;
1058   newClass->dwCookie        = (DWORD)newClass;
1059   newClass->nextClass       = firstRegisteredClass;
1060
1061   /*
1062    * Since we're making a copy of the object pointer, we have to increase its
1063    * reference count.
1064    */
1065   newClass->classObject     = pUnk;
1066   IUnknown_AddRef(newClass->classObject);
1067
1068   firstRegisteredClass = newClass;
1069
1070   /*
1071    * Assign the out parameter (cookie)
1072    */
1073   *lpdwRegister = newClass->dwCookie;
1074     
1075   /*
1076    * We're successful Yippee!
1077    */
1078   return S_OK;
1079 }
1080
1081 /***********************************************************************
1082  *           CoRevokeClassObject [OLE32.40]
1083  *
1084  * This method will remove a class object from the class registry
1085  *
1086  * See the Windows documentation for more details.
1087  */
1088 HRESULT WINAPI CoRevokeClassObject(
1089         DWORD dwRegister) 
1090 {
1091   RegisteredClass** prevClassLink;
1092   RegisteredClass*  curClass;
1093
1094   Print(MAX_TRACE, ("(%08lx)\n",dwRegister));
1095
1096   /*
1097    * Iterate through the whole list and try to match the cookie.
1098    */
1099   curClass      = firstRegisteredClass;
1100   prevClassLink = &firstRegisteredClass;
1101
1102   while (curClass != 0)
1103   {
1104     /*
1105      * Check if we have a match on the cookie.
1106      */
1107     if (curClass->dwCookie == dwRegister)
1108     {
1109       /*
1110        * Remove the class from the chain.
1111        */
1112       *prevClassLink = curClass->nextClass;
1113
1114       /*
1115        * Release the reference to the class object.
1116        */
1117       IUnknown_Release(curClass->classObject);
1118
1119       /*
1120        * Free the memory used by the chain node.
1121  */
1122       HeapFree(GetProcessHeap(), 0, curClass);
1123
1124     return S_OK;
1125 }
1126
1127     /*
1128      * Step to the next class in the list.
1129      */
1130     prevClassLink = &(curClass->nextClass);
1131     curClass      = curClass->nextClass;
1132   }
1133
1134   /*
1135    * If we get to here, we haven't found our class.
1136    */
1137   return E_INVALIDARG;
1138 }
1139
1140 /***********************************************************************
1141  *           CoGetClassObject [COMPOBJ.7]
1142  */
1143 HRESULT WINAPI CoGetClassObject(
1144     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
1145     REFIID iid, LPVOID *ppv
1146 ) {
1147     LPUNKNOWN   regClassObject;
1148     HRESULT     hres = E_UNEXPECTED;
1149     char        xclsid[80];
1150     WCHAR dllName[MAX_PATH+1];
1151     DWORD dllNameLen = sizeof(dllName);
1152     HINSTANCE hLibrary;
1153     typedef HRESULT CALLBACK (*DllGetClassObjectFunc)(REFCLSID clsid, 
1154                              REFIID iid, LPVOID *ppv);
1155     DllGetClassObjectFunc DllGetClassObject;
1156
1157     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1158
1159     Print(MIN_TRACE, ("\n\tCLSID:\t%s,\n\tIID:\t%s\n",
1160         PRINT_GUID(rclsid),
1161         PRINT_GUID(iid)
1162     ));
1163
1164     if (pServerInfo) {
1165         Print(MIN_TRACE, ("\tpServerInfo: name=%S\n",pServerInfo->pwszName));
1166         Print(MIN_TRACE, ("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo));
1167     }
1168
1169     /*
1170      * First, try and see if we can't match the class ID with one of the 
1171      * registered classes.
1172      */
1173     if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
1174     {
1175       /*
1176        * Get the required interface from the retrieved pointer.
1177        */
1178       hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
1179
1180       /*
1181        * Since QI got another reference on the pointer, we want to release the
1182        * one we already have. If QI was unsuccessful, this will release the object. This
1183        * is good since we are not returning it in the "out" parameter.
1184        */
1185       IUnknown_Release(regClassObject);
1186
1187       return hres;
1188     }
1189
1190     /* out of process and remote servers not supported yet */
1191     if (     ((CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER) & dwClsContext)
1192         && !((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext)
1193     ){
1194         Print(MIN_TRACE, ("%s %s not supported!\n",
1195                 (dwClsContext&CLSCTX_LOCAL_SERVER)?"CLSCTX_LOCAL_SERVER":"",
1196                 (dwClsContext&CLSCTX_REMOTE_SERVER)?"CLSCTX_REMOTE_SERVER":""
1197         ));
1198         return E_ACCESSDENIED;
1199     }
1200
1201     if ((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext) {
1202         HKEY key;
1203         char buf[200];
1204
1205         sprintf(buf,"CLSID\\%s\\InprocServer32",xclsid);
1206         hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key);
1207
1208         if (hres != ERROR_SUCCESS) {
1209             return REGDB_E_CLASSNOTREG;
1210         }
1211
1212         memset(dllName,0,sizeof(dllName));
1213         hres= RegQueryValueExW(key,NULL,NULL,NULL,(LPBYTE)dllName,&dllNameLen);
1214         if (hres)
1215                 return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
1216         RegCloseKey(key);
1217         Print(MAX_TRACE, ("found InprocServer32 dll %S\n", dllName));
1218
1219         /* open dll, call DllGetClassObject */
1220         hLibrary = CoLoadLibrary(dllName, TRUE);
1221         if (hLibrary == 0) {
1222             Print(MIN_TRACE, ("couldn't load InprocServer32 dll %S\n", dllName));
1223             return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
1224         }
1225         DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject");
1226         if (!DllGetClassObject) {
1227             /* not sure if this should be called here CoFreeLibrary(hLibrary);*/
1228             Print(MIN_TRACE, ("couldn't find function DllGetClassObject in %S\n", dllName));
1229             return E_ACCESSDENIED;
1230         }
1231
1232         /*
1233          * Ask the DLL for its class object. (there was a note here about class
1234          * factories but this is good.
1235          */
1236         return DllGetClassObject(rclsid, iid, ppv);
1237     }
1238     return hres;
1239 }
1240
1241 /***********************************************************************
1242  *        CoResumeClassObjects
1243  *
1244  * Resumes classobjects registered with REGCLS suspended
1245  */
1246 HRESULT WINAPI CoResumeClassObjects(void)
1247 {
1248         UNIMPLEMENTED;
1249         return S_OK;
1250 }
1251
1252 /***********************************************************************
1253  *        GetClassFile
1254  *
1255  * This function supplies the CLSID associated with the given filename.
1256  */
1257 HRESULT WINAPI GetClassFile(LPOLESTR filePathName,CLSID *pclsid)
1258 {
1259     IStorage *pstg=0;
1260     HRESULT res;
1261     int nbElm=0,length=0,i=0;
1262     LONG sizeProgId=20;
1263     LPOLESTR *pathDec=0,absFile=0,progId=0;
1264     WCHAR extention[100]={0};
1265
1266     Print(MAX_TRACE, ("()\n"));
1267
1268     /* if the file contain a storage object the return the CLSID writen by IStorage_SetClass method*/
1269     if((StgIsStorageFile(filePathName))==S_OK){
1270
1271         res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
1272
1273         if (SUCCEEDED(res))
1274             res=ReadClassStg(pstg,pclsid);
1275
1276         IStorage_Release(pstg);
1277
1278         return res;
1279     }
1280     /* if the file is not a storage object then attemps to match various bits in the file against a
1281        pattern in the registry. this case is not frequently used ! so I present only the psodocode for
1282        this case
1283        
1284      for(i=0;i<nFileTypes;i++)
1285
1286         for(i=0;j<nPatternsForType;j++){
1287
1288             PATTERN pat;
1289             HANDLE  hFile;
1290
1291             pat=ReadPatternFromRegistry(i,j);
1292             hFile=CreateFileW(filePathName,,,,,,hFile);
1293             SetFilePosition(hFile,pat.offset);
1294             ReadFile(hFile,buf,pat.size,NULL,NULL);
1295             if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){
1296
1297                 *pclsid=ReadCLSIDFromRegistry(i);
1298                 return S_OK;
1299             }
1300         }
1301      */
1302
1303     /* if the obove strategies fail then search for the extension key in the registry */
1304
1305     /* get the last element (absolute file) in the path name */
1306     nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
1307     absFile=pathDec[nbElm-1];
1308
1309     /* failed if the path represente a directory and not an absolute file name*/
1310     if (lstrcmpW(absFile,(LPOLESTR)"\\"))
1311         return MK_E_INVALIDEXTENSION;
1312
1313     /* get the extension of the file */
1314     length=lstrlenW(absFile);
1315     for(i=length-1; ( (i>=0) && (extention[i]=absFile[i]) );i--);
1316         
1317     /* get the progId associated to the extension */
1318     progId=CoTaskMemAlloc(sizeProgId);
1319
1320     res=RegQueryValueW(HKEY_CLASSES_ROOT,extention,progId,&sizeProgId);
1321
1322     if (res==ERROR_MORE_DATA){
1323
1324         progId = CoTaskMemRealloc(progId,sizeProgId);
1325         res=RegQueryValueW(HKEY_CLASSES_ROOT,extention,progId,&sizeProgId);
1326     }
1327     if (res==ERROR_SUCCESS)
1328         /* return the clsid associated to the progId */
1329         res= CLSIDFromProgID(progId,pclsid);
1330
1331     for(i=0; pathDec[i]!=NULL;i++)
1332         CoTaskMemFree(pathDec[i]);
1333     CoTaskMemFree(pathDec);
1334
1335     CoTaskMemFree(progId);
1336
1337     if (res==ERROR_SUCCESS)
1338         return res;
1339
1340     return MK_E_INVALIDEXTENSION;
1341 }
1342 /******************************************************************************
1343  *              CoRegisterMessageFilter16       [COMPOBJ.27]
1344  */
1345 HRESULT WINAPI CoRegisterMessageFilter16(
1346         DWORD lpMessageFilter,
1347         DWORD *lplpMessageFilter
1348 ) {
1349         UNIMPLEMENTED;
1350         return 0;
1351 }
1352
1353 /***********************************************************************
1354  *           CoCreateInstance [COMPOBJ.13, OLE32.7]
1355  */
1356 HRESULT WINAPI CoCreateInstance(
1357         REFCLSID rclsid,
1358         LPUNKNOWN pUnkOuter,
1359         DWORD dwClsContext,
1360         REFIID iid,
1361         LPVOID *ppv) 
1362 {
1363         HRESULT hres;
1364         LPCLASSFACTORY lpclf = 0;
1365
1366   /*
1367    * Sanity check
1368    */
1369   if (ppv==0)
1370     return E_POINTER;
1371
1372   /*
1373    * Initialize the "out" parameter
1374    */
1375   *ppv = 0;
1376   
1377   /*
1378    * Get a class factory to construct the object we want.
1379    */
1380   hres = CoGetClassObject(rclsid,
1381                           dwClsContext,
1382                           NULL,
1383                           &IID_IClassFactory,
1384                           (LPVOID)&lpclf);
1385
1386   if (FAILED(hres)) {
1387     Print(MIN_TRACE, ("no instance created for %s, hres is 0x%08lx\n",PRINT_GUID(iid),hres));
1388     return hres;
1389   }
1390
1391   /*
1392    * Create the object and don't forget to release the factory
1393    */
1394         hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
1395         IClassFactory_Release(lpclf);
1396
1397         return hres;
1398 }
1399
1400 /***********************************************************************
1401  *           CoCreateInstanceEx [OLE32.165]
1402  */
1403 HRESULT WINAPI CoCreateInstanceEx(
1404   REFCLSID      rclsid, 
1405   LPUNKNOWN     pUnkOuter,
1406   DWORD         dwClsContext, 
1407   COSERVERINFO* pServerInfo,
1408   ULONG         cmq,
1409   MULTI_QI*     pResults)
1410 {
1411   IUnknown* pUnk = NULL;
1412   HRESULT   hr;
1413   ULONG     index;
1414   int       successCount = 0;
1415
1416   /*
1417    * Sanity check
1418    */
1419   if ( (cmq==0) || (pResults==NULL))
1420     return E_INVALIDARG;
1421
1422   if (pServerInfo!=NULL)
1423     Print(MIN_TRACE, ("() non-NULL pServerInfo not supported!\n"));
1424
1425   /*
1426    * Initialize all the "out" parameters.
1427    */
1428   for (index = 0; index < cmq; index++)
1429   {
1430     pResults[index].pItf = NULL;
1431     pResults[index].hr   = E_NOINTERFACE;
1432   }
1433
1434   /*
1435    * Get the object and get its IUnknown pointer.
1436    */
1437   hr = CoCreateInstance(rclsid, 
1438                         pUnkOuter,
1439                         dwClsContext,
1440                         &IID_IUnknown,
1441                         (VOID**)&pUnk);
1442
1443   if (hr)
1444     return hr;
1445
1446   /*
1447    * Then, query for all the interfaces requested.
1448    */
1449   for (index = 0; index < cmq; index++)
1450   {
1451     pResults[index].hr = IUnknown_QueryInterface(pUnk,
1452                                                  pResults[index].pIID,
1453                                                  (VOID**)&(pResults[index].pItf));
1454
1455     if (pResults[index].hr == S_OK)
1456       successCount++;
1457   }
1458
1459   /*
1460    * Release our temporary unknown pointer.
1461    */
1462   IUnknown_Release(pUnk);
1463
1464   if (successCount == 0)
1465     return E_NOINTERFACE;
1466
1467   if (successCount!=cmq)
1468     return CO_S_NOTALLINTERFACES;
1469
1470   return S_OK;
1471 }
1472
1473 /***********************************************************************
1474  *           CoFreeLibrary [COMPOBJ.13]
1475  */
1476 void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
1477 {
1478     OpenDll *ptr, *prev;
1479     OpenDll *tmp;
1480
1481     /* lookup library in linked list */
1482     prev = NULL;
1483     for (ptr = openDllList; ptr != NULL; ptr=ptr->next) {
1484         if (ptr->hLibrary == hLibrary) {
1485             break;
1486         }
1487         prev = ptr;
1488     }
1489
1490     if (ptr == NULL) {
1491         /* shouldn't happen if user passed in a valid hLibrary */
1492         return;
1493     }
1494     /* assert: ptr points to the library entry to free */
1495
1496     /* free library and remove node from list */
1497     FreeLibrary(hLibrary);
1498     if (ptr == openDllList) {
1499         tmp = openDllList->next;
1500         HeapFree(GetProcessHeap(), 0, openDllList);
1501         openDllList = tmp;
1502     } else {
1503         tmp = ptr->next;
1504         HeapFree(GetProcessHeap(), 0, ptr);
1505         prev->next = tmp;
1506     }
1507
1508 }
1509
1510
1511 /***********************************************************************
1512  *           CoFreeAllLibraries [COMPOBJ.12]
1513  */
1514 void WINAPI CoFreeAllLibraries(void)
1515 {
1516     OpenDll *ptr, *tmp;
1517
1518     for (ptr = openDllList; ptr != NULL; ) {
1519         tmp=ptr->next;
1520         CoFreeLibrary(ptr->hLibrary);
1521         ptr = tmp;
1522     }
1523 }
1524
1525
1526
1527 /***********************************************************************
1528  *           CoFreeUnusedLibraries [COMPOBJ.17]
1529  */
1530 void WINAPI CoFreeUnusedLibraries(void)
1531 {
1532     OpenDll *ptr, *tmp;
1533     typedef HRESULT(*DllCanUnloadNowFunc)(void);
1534     DllCanUnloadNowFunc DllCanUnloadNow;
1535
1536     for (ptr = openDllList; ptr != NULL; ) {
1537         DllCanUnloadNow = (DllCanUnloadNowFunc)
1538             GetProcAddress(ptr->hLibrary, "DllCanUnloadNow");
1539         
1540         if ( (DllCanUnloadNow != NULL) &&
1541              (DllCanUnloadNow() == S_OK) ) {
1542             tmp=ptr->next;
1543             CoFreeLibrary(ptr->hLibrary);
1544             ptr = tmp;
1545         } else {
1546             ptr=ptr->next;
1547         }
1548     }
1549 }
1550
1551 /***********************************************************************
1552  *           CoFileTimeNow [COMPOBJ.82, OLE32.10]
1553  * RETURNS
1554  *      the current system time in lpFileTime
1555  */
1556 HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) /* [out] the current time */
1557 {
1558     GetSystemTimeAsFileTime( lpFileTime );
1559     return S_OK;
1560 }
1561
1562 /***********************************************************************
1563  *           CoTaskMemAlloc (OLE32.43)
1564  * RETURNS
1565  *      pointer to newly allocated block
1566  */
1567 LPVOID WINAPI CoTaskMemAlloc(
1568         ULONG size      /* [in] size of memoryblock to be allocated */
1569 ) {
1570     LPMALLOC    lpmalloc;
1571     HRESULT     ret = CoGetMalloc(0,&lpmalloc);
1572
1573     if (FAILED(ret)) 
1574         return NULL;
1575
1576     return IMalloc_Alloc(lpmalloc,size);
1577 }
1578 /***********************************************************************
1579  *           CoTaskMemFree (OLE32.44)
1580  */
1581 VOID WINAPI CoTaskMemFree(
1582         LPVOID ptr      /* [in] pointer to be freed */
1583 ) {
1584     LPMALLOC    lpmalloc;
1585     HRESULT     ret = CoGetMalloc(0,&lpmalloc);
1586
1587     if (FAILED(ret)) 
1588       return;
1589
1590     IMalloc_Free(lpmalloc, ptr);
1591 }
1592
1593 /***********************************************************************
1594  *           CoTaskMemRealloc (OLE32.45)
1595  * RETURNS
1596  *      pointer to newly allocated block
1597  */
1598 LPVOID WINAPI CoTaskMemRealloc(
1599   LPVOID pvOld,
1600   ULONG  size)  /* [in] size of memoryblock to be allocated */
1601 {
1602   LPMALLOC lpmalloc;
1603   HRESULT  ret = CoGetMalloc(0,&lpmalloc);
1604   
1605   if (FAILED(ret)) 
1606     return NULL;
1607
1608   return IMalloc_Realloc(lpmalloc, pvOld, size);
1609 }
1610
1611 /***********************************************************************
1612  *           CoLoadLibrary (OLE32.30)
1613  */
1614 HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
1615 {
1616     HINSTANCE hLibrary;
1617     OpenDll *ptr;
1618     OpenDll *tmp;
1619   
1620     Print(MAX_TRACE, ("(%S, %d)\n", lpszLibName, bAutoFree));
1621
1622     hLibrary = LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
1623
1624     if (!bAutoFree)
1625         return hLibrary;
1626
1627     if (openDllList == NULL) {
1628         /* empty list -- add first node */
1629         openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
1630         openDllList->hLibrary=hLibrary;
1631         openDllList->next = NULL;
1632     } else {
1633         /* search for this dll */
1634         int found = FALSE;
1635         for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
1636             if (ptr->hLibrary == hLibrary) {
1637                 found = TRUE;
1638                 break;
1639             }
1640         }
1641         if (!found) {
1642             /* dll not found, add it */
1643             tmp = openDllList;
1644             openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
1645             openDllList->hLibrary = hLibrary;
1646             openDllList->next = tmp;
1647         }
1648     }
1649      
1650     return hLibrary;
1651 }
1652
1653 /***********************************************************************
1654  *           CoInitializeWOW (OLE32.27)
1655  */
1656 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
1657     UNIMPLEMENTED;
1658     return 0;
1659 }
1660
1661 /******************************************************************************
1662  *              CoLockObjectExternal16  [COMPOBJ.63]
1663  */
1664 HRESULT WINAPI CoLockObjectExternal16(
1665     LPUNKNOWN pUnk,             /* [in] object to be locked */
1666     BOOL fLock,         /* [in] do lock */
1667     BOOL fLastUnlockReleases    /* [in] ? */
1668 ) {
1669     UNIMPLEMENTED;
1670     return S_OK;
1671 }
1672
1673 /******************************************************************************
1674  *              CoLockObjectExternal    [OLE32.31]
1675  */
1676 HRESULT WINAPI CoLockObjectExternal(
1677     LPUNKNOWN pUnk,             /* [in] object to be locked */
1678     BOOL fLock,         /* [in] do lock */
1679     BOOL fLastUnlockReleases) /* [in] unlock all */
1680 {
1681
1682   if (fLock) 
1683   {
1684     /* 
1685      * Increment the external lock coutner, COM_ExternalLockAddRef also
1686      * increment the object's internal lock counter.
1687      */
1688     COM_ExternalLockAddRef( pUnk); 
1689   }
1690   else
1691   {
1692     /* 
1693      * Decrement the external lock coutner, COM_ExternalLockRelease also
1694      * decrement the object's internal lock counter.
1695      */
1696     COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
1697   }
1698
1699     return S_OK;
1700 }
1701
1702 /***********************************************************************
1703  *           CoGetState16 [COMPOBJ.115]
1704  */
1705 HRESULT WINAPI CoGetState16(LPDWORD state)
1706 {
1707     UNIMPLEMENTED
1708     return S_OK;
1709 }
1710 /***********************************************************************
1711  *           CoSetState [COM32.42]
1712  */
1713 HRESULT WINAPI CoSetState(LPDWORD state)
1714 {
1715     UNIMPLEMENTED;
1716     return S_OK;
1717 }
1718 /***********************************************************************
1719  *          CoCreateFreeThreadedMarshaler [OLE32.5]
1720  */
1721 HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN* ppunkMarshal)
1722 {
1723    UNIMPLEMENTED;
1724    return S_OK;
1725 }
1726
1727
1728 /***********************************************************************
1729  *           DllGetClassObject [OLE32.63]
1730  */
1731 HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1732 {       
1733   UNIMPLEMENTED;
1734         *ppv = NULL;
1735         return CLASS_E_CLASSNOTAVAILABLE;
1736 }
1737
1738
1739 /***
1740  * COM_RevokeAllClasses
1741  *
1742  * This method is called when the COM libraries are uninitialized to 
1743  * release all the references to the class objects registered with
1744  * the library
1745  */
1746 static void COM_RevokeAllClasses()
1747 {
1748   while (firstRegisteredClass!=0)
1749   {
1750     CoRevokeClassObject(firstRegisteredClass->dwCookie);
1751   }
1752 }
1753
1754 /****************************************************************************
1755  *  COM External Lock methods implementation
1756  */
1757
1758 /****************************************************************************
1759  * Public - Method that increments the count for a IUnknown* in the linked 
1760  * list.  The item is inserted if not already in the list.
1761  */
1762 static void COM_ExternalLockAddRef(
1763   IUnknown *pUnk)
1764 {
1765   COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
1766
1767   /*
1768    * Add an external lock to the object. If it was already externally
1769    * locked, just increase the reference count. If it was not.
1770    * add the item to the list.
1771    */
1772   if ( externalLock == EL_NOT_FOUND )
1773     COM_ExternalLockInsert(pUnk);
1774   else
1775     externalLock->uRefCount++;
1776
1777   /*
1778    * Add an internal lock to the object
1779    */
1780   IUnknown_AddRef(pUnk); 
1781 }
1782
1783 /****************************************************************************
1784  * Public - Method that decrements the count for a IUnknown* in the linked 
1785  * list.  The item is removed from the list if its count end up at zero or if
1786  * bRelAll is TRUE.
1787  */
1788 static void COM_ExternalLockRelease(
1789   IUnknown *pUnk,
1790   BOOL   bRelAll)
1791 {
1792   COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
1793
1794   if ( externalLock != EL_NOT_FOUND )
1795   {
1796     do
1797     {
1798       externalLock->uRefCount--;  /* release external locks      */
1799       IUnknown_Release(pUnk);     /* release local locks as well */
1800
1801       if ( bRelAll == FALSE ) 
1802         break;  /* perform single release */
1803
1804     } while ( externalLock->uRefCount > 0 );  
1805
1806     if ( externalLock->uRefCount == 0 )  /* get rid of the list entry */
1807       COM_ExternalLockDelete(externalLock);
1808   }
1809 }
1810 /****************************************************************************
1811  * Public - Method that frees the content of the list.
1812  */
1813 static void COM_ExternalLockFreeList()
1814 {
1815   COM_ExternalLock *head;
1816
1817   head = elList.head;                 /* grab it by the head             */
1818   while ( head != EL_END_OF_LIST )
1819   {
1820     COM_ExternalLockDelete(head);     /* get rid of the head stuff       */
1821
1822     head = elList.head;               /* get the new head...             */ 
1823   }
1824 }
1825
1826 /****************************************************************************
1827  * Public - Method that dump the content of the list.
1828  */
1829 void COM_ExternalLockDump()
1830 {
1831   COM_ExternalLock *current = elList.head;
1832
1833   Print(MAX_TRACE, ("\nExternal lock list contains:\n"));
1834
1835   while ( current != EL_END_OF_LIST )
1836   {
1837       Print(MAX_TRACE, ("\t%p with %lu references count.\n", current->pUnk, current->uRefCount));
1838  
1839     /* Skip to the next item */ 
1840     current = current->next;
1841   } 
1842
1843 }
1844
1845 /****************************************************************************
1846  * Internal - Find a IUnknown* in the linked list
1847  */
1848 static COM_ExternalLock* COM_ExternalLockFind(
1849   IUnknown *pUnk)
1850 {
1851   return COM_ExternalLockLocate(elList.head, pUnk);
1852 }
1853
1854 /****************************************************************************
1855  * Internal - Recursivity agent for IUnknownExternalLockList_Find
1856  */
1857 static COM_ExternalLock* COM_ExternalLockLocate(
1858   COM_ExternalLock *element,
1859   IUnknown         *pUnk)
1860 {
1861   if ( element == EL_END_OF_LIST )  
1862     return EL_NOT_FOUND;
1863
1864   else if ( element->pUnk == pUnk )    /* We found it */
1865     return element;
1866
1867   else                                 /* Not the right guy, keep on looking */ 
1868     return COM_ExternalLockLocate( element->next, pUnk);
1869 }
1870
1871 /****************************************************************************
1872  * Internal - Insert a new IUnknown* to the linked list
1873  */
1874 static BOOL COM_ExternalLockInsert(
1875   IUnknown *pUnk)
1876 {
1877   COM_ExternalLock *newLock      = NULL;
1878   COM_ExternalLock *previousHead = NULL;
1879
1880   /*
1881    * Allocate space for the new storage object
1882    */
1883   newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
1884
1885   if (newLock!=NULL)
1886   {
1887     if ( elList.head == EL_END_OF_LIST ) 
1888     {
1889       elList.head = newLock;    /* The list is empty */
1890     }
1891     else 
1892     {
1893       /* 
1894        * insert does it at the head
1895        */
1896       previousHead  = elList.head;
1897       elList.head = newLock;
1898     }
1899
1900     /*
1901      * Set new list item data member 
1902      */
1903     newLock->pUnk      = pUnk;
1904     newLock->uRefCount = 1;
1905     newLock->next      = previousHead;
1906     
1907     return TRUE;
1908   }
1909   else
1910     return FALSE;
1911 }
1912
1913 /****************************************************************************
1914  * Internal - Method that removes an item from the linked list.
1915  */
1916 static void COM_ExternalLockDelete(
1917   COM_ExternalLock *itemList)
1918 {
1919   COM_ExternalLock *current = elList.head;
1920
1921   if ( current == itemList )
1922   {
1923     /* 
1924      * this section handles the deletion of the first node 
1925      */
1926     elList.head = itemList->next;
1927     HeapFree( GetProcessHeap(), 0, itemList);  
1928   }
1929   else
1930   {
1931     do 
1932     {
1933       if ( current->next == itemList )   /* We found the item to free  */
1934       {
1935         current->next = itemList->next;  /* readjust the list pointers */
1936   
1937         HeapFree( GetProcessHeap(), 0, itemList);  
1938         break; 
1939       }
1940  
1941       /* Skip to the next item */ 
1942       current = current->next;
1943   
1944     } while ( current != EL_END_OF_LIST );
1945   }
1946 }
1947
1948 /***********************************************************************
1949  *      COMPOBJ_DllEntryPoint                   [COMPOBJ.entry]
1950  *
1951  *    Initialization code for the COMPOBJ DLL
1952  *
1953  * RETURNS:
1954  */
1955 BOOL WINAPI COMPOBJ_DllEntryPoint(DWORD Reason, DWORD hInst, WORD ds, WORD HeapSize, DWORD res1, WORD res2)
1956 {
1957         Print(MAX_TRACE, ("(%08lx, %04x, %04x, %04x, %08lx, %04x)\n", Reason, hInst, ds, HeapSize,
1958  res1, res2));
1959         switch(Reason)
1960         {
1961         case DLL_PROCESS_ATTACH:
1962 #if 0
1963                 if (!COMPOBJ_Attach++) COMPOBJ_hInstance = hInst;
1964 #endif
1965                 break;
1966
1967         case DLL_PROCESS_DETACH:
1968 #if 0
1969                 if(!--COMPOBJ_Attach)
1970                         COMPOBJ_hInstance = 0;
1971 #endif
1972                 break;
1973         }
1974         return TRUE;
1975 }
1976
1977 /******************************************************************************
1978  *              OleGetAutoConvert        [OLE32.104]
1979  */
1980 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
1981 {
1982     HKEY hkey = 0;
1983     char buf[200];
1984     WCHAR wbuf[200];
1985     DWORD len;
1986     HRESULT res = S_OK;
1987
1988     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
1989     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
1990     {
1991         res = REGDB_E_CLASSNOTREG;
1992         goto done;
1993     }
1994     len = 200;
1995     /* we can just query for the default value of AutoConvertTo key like that,
1996        without opening the AutoConvertTo key and querying for NULL (default) */
1997     if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len))
1998     {
1999         res = REGDB_E_KEYMISSING;
2000         goto done;
2001     }
2002     MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) );
2003     CLSIDFromString(wbuf,pClsidNew);
2004 done:
2005   if (hkey) RegCloseKey(hkey);
2006
2007   return res;
2008 }
2009
2010 /******************************************************************************
2011  *              OleSetAutoConvert        [OLE32.126]
2012  */
2013 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2014 {
2015     HKEY hkey = 0, hkeyConvert = 0;
2016     char buf[200], szClsidNew[200];
2017     HRESULT res = S_OK;
2018
2019     Print(MAX_TRACE, ("(%p,%p);\n", clsidOld, clsidNew));
2020     sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
2021     WINE_StringFromCLSID(clsidNew, szClsidNew);
2022     if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
2023     {
2024         res = REGDB_E_CLASSNOTREG;
2025         goto done;
2026     }
2027     if (RegCreateKeyA(hkey, "AutoConvertTo", &hkeyConvert))
2028     {
2029         res = REGDB_E_WRITEREGDB;
2030         goto done;
2031     }
2032     if (RegSetValueExA(hkeyConvert, NULL, 0,
2033                             REG_SZ, (LPBYTE)szClsidNew, strlen(szClsidNew)+1))
2034     {
2035         res = REGDB_E_WRITEREGDB;
2036         goto done;
2037     }
2038
2039 done:
2040     if (hkeyConvert) RegCloseKey(hkeyConvert);
2041     if (hkey) RegCloseKey(hkey);
2042
2043     return res;
2044 }
2045
2046 /***********************************************************************
2047  *           IsEqualGUID [OLE32.76]
2048  *
2049  * Compares two Unique Identifiers.
2050  *
2051  * RETURNS
2052  *      TRUE if equal
2053  */
2054 #undef IsEqualGUID
2055 BOOL WINAPI IsEqualGUID(
2056      REFGUID rguid1, /* [in] unique id 1 */
2057      REFGUID rguid2  /* [in] unique id 2 */
2058      )
2059 {
2060     return !memcmp(rguid1,rguid2,sizeof(GUID));
2061 }