Implementation of CoLoadLibrary, CoFreeAllLibraries,
[wine] / ole / compobj.c
1 /*
2  *      COMPOBJ library
3  *
4  *      Copyright 1995  Martin von Loewis
5  */
6
7 #define INITGUID
8
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include "ole.h"
14 #include "ole2.h"
15 #include "winerror.h"
16 #include "debug.h"
17 #include "file.h"
18 #include "compobj.h"
19 #include "heap.h"
20 #include "ldt.h"
21 #include "interfaces.h"
22 #include "shlobj.h"
23 #include "ddraw.h"
24 #include "dsound.h"
25 #include "dinput.h"
26 #include "d3d.h"
27 #include "dplay.h"
28 #include "windows.h"
29
30
31 LPMALLOC16 currentMalloc16=NULL;
32 LPMALLOC32 currentMalloc32=NULL;
33
34 HTASK16 hETask = 0;
35 WORD Table_ETask[62];
36
37
38 /* this open DLL table belongs in a per process table, but my guess is that
39  * it shouldn't live in the kernel, so I'll put them out here in DLL
40  * space assuming that there is one OLE32 per process.
41  */
42 typedef struct tagOpenDll {
43   char *DllName;                /* really only needed for debugging */
44     HINSTANCE32 hLibrary;       
45     struct tagOpenDll *next;
46 } OpenDll;
47
48 static OpenDll *openDllList = NULL; /* linked list of open dlls */
49
50
51 /******************************************************************************
52  *           CoBuildVersion [COMPOBJ.1]
53  *
54  * RETURNS
55  *      Current built version, hiword is majornumber, loword is minornumber
56  */
57 DWORD WINAPI CoBuildVersion(void)
58 {
59     TRACE(ole,"(void)\n");
60     return (rmm<<16)+rup;
61 }
62
63 /******************************************************************************
64  *              CoInitialize16  [COMPOBJ.2]
65  * Set the win16 IMalloc used for memory management
66  */
67 HRESULT WINAPI CoInitialize16(
68         LPMALLOC16 lpReserved   /* [in] pointer to win16 malloc interface */
69 ) {
70     currentMalloc16 = lpReserved;
71     return S_OK;
72 }
73
74 /******************************************************************************
75  *              CoInitialize32  [OLE32.26]
76  * Set the win32 IMalloc used for memorymanagement
77  */
78 HRESULT WINAPI CoInitialize32(
79         LPMALLOC32 lpReserved   /* [in] pointer to win32 malloc interface */
80 ) {
81     /* FIXME: there really should be something here that incrememts a refcount
82      * but I'm supposing that it is a real COM object, so I won't bother
83      * creating one here.  (Decrement done in CoUnitialize()) */
84     currentMalloc32 = lpReserved;
85     return S_OK;
86 }
87
88 /***********************************************************************
89  *           CoUnitialize   [COMPOBJ.3]
90  * Don't know what it does. 
91  * 3-Nov-98 -- this was originally misspelled, I changed it to what I
92  *   believe is the correct spelling
93  */
94 void WINAPI CoUninitialize(void)
95 {
96     TRACE(ole,"(void)\n");
97     CoFreeAllLibraries();
98 }
99
100 /***********************************************************************
101  *           CoGetMalloc16    [COMPOBJ.4]
102  * RETURNS
103  *      The current win16 IMalloc
104  */
105 HRESULT WINAPI CoGetMalloc16(
106         DWORD dwMemContext,     /* [in] unknown */
107         LPMALLOC16 * lpMalloc   /* [out] current win16 malloc interface */
108 ) {
109     if(!currentMalloc16)
110         currentMalloc16 = IMalloc16_Constructor();
111     *lpMalloc = currentMalloc16;
112     return S_OK;
113 }
114
115 /******************************************************************************
116  *              CoGetMalloc32   [OLE32.20]
117  *
118  * RETURNS
119  *      The current win32 IMalloc
120  */
121 HRESULT WINAPI CoGetMalloc32(
122         DWORD dwMemContext,     /* [in] unknown */
123         LPMALLOC32 *lpMalloc    /* [out] current win32 malloc interface */
124 ) {
125     if(!currentMalloc32)
126         currentMalloc32 = IMalloc32_Constructor();
127     *lpMalloc = currentMalloc32;
128     return S_OK;
129 }
130
131 /***********************************************************************
132  *           CoCreateStandardMalloc16 [COMPOBJ.71]
133  */
134 OLESTATUS WINAPI CoCreateStandardMalloc16(DWORD dwMemContext,
135                                           LPMALLOC16 *lpMalloc)
136 {
137     /* FIXME: docu says we shouldn't return the same allocator as in
138      * CoGetMalloc16 */
139     *lpMalloc = IMalloc16_Constructor();
140     return S_OK;
141 }
142
143 /******************************************************************************
144  *              CoDisconnectObject      [COMPOBJ.15]
145  */
146 OLESTATUS WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
147 {
148     TRACE(ole,"%p %lx\n",lpUnk,reserved);
149     return S_OK;
150 }
151
152 /***********************************************************************
153  *           IsEqualGUID [COMPOBJ.18]
154  * Compares two Unique Identifiers
155  * RETURNS
156  *      TRUE if equal
157  */
158 BOOL16 WINAPI IsEqualGUID(
159         GUID* g1,       /* [in] unique id 1 */
160         GUID* g2        /* [in] unique id 2 */
161 ) {
162     return !memcmp( g1, g2, sizeof(GUID) );
163 }
164
165 /******************************************************************************
166  *              CLSIDFromString16       [COMPOBJ.20]
167  * Converts a unique identifier from it's string representation into 
168  * the GUID struct.
169  *
170  * Class id: DWORD-WORD-WORD-BYTES[2]-BYTES[6] 
171  *
172  * RETURNS
173  *      the converted GUID
174  */
175 OLESTATUS WINAPI CLSIDFromString16(
176         LPCOLESTR16 idstr,      /* [in] string representation of guid */
177         CLSID *id               /* [out] GUID converted from string */
178 ) {
179   BYTE *s = (BYTE *) idstr;
180   BYTE *p;
181   int   i;
182   BYTE table[256];
183
184   TRACE(ole,"%s -> %p\n", idstr, id);
185
186   /* quick lookup table */
187   memset(table, 0, 256);
188
189   for (i = 0; i < 10; i++) {
190     table['0' + i] = i;
191   }
192   for (i = 0; i < 6; i++) {
193     table['A' + i] = i+10;
194     table['a' + i] = i+10;
195   }
196
197   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
198
199   if (strlen(idstr) != 38)
200     return OLE_ERROR_OBJECT;
201
202   p = (BYTE *) id;
203
204   s++;  /* skip leading brace  */
205   for (i = 0; i < 4; i++) {
206     p[3 - i] = table[*s]<<4 | table[*(s+1)];
207     s += 2;
208   }
209   p += 4;
210   s++;  /* skip - */
211
212   for (i = 0; i < 2; i++) {
213     p[1-i] = table[*s]<<4 | table[*(s+1)];
214     s += 2;
215   }
216   p += 2;
217   s++;  /* skip - */
218
219   for (i = 0; i < 2; i++) {
220     p[1-i] = table[*s]<<4 | table[*(s+1)];
221     s += 2;
222   }
223   p += 2;
224   s++;  /* skip - */
225
226   /* these are just sequential bytes */
227   for (i = 0; i < 2; i++) {
228     *p++ = table[*s]<<4 | table[*(s+1)];
229     s += 2;
230   }
231   s++;  /* skip - */
232
233   for (i = 0; i < 6; i++) {
234     *p++ = table[*s]<<4 | table[*(s+1)];
235     s += 2;
236   }
237
238   return S_OK;
239 }
240
241 /******************************************************************************
242  *              CoCreateGuid[OLE32.6]
243  * Just a random 128-bit number?
244  */
245 HRESULT WINAPI CoCreateGuid(GUID *pguid) {
246         FIXME(ole,"stub!\n");
247         return S_OK;
248 }
249
250 /******************************************************************************
251  *              CLSIDFromString32       [OLE32.3]
252  * Converts a unique identifier from it's string representation into 
253  * the GUID struct.
254  * RETURNS
255  *      the converted GUID
256  */
257 OLESTATUS WINAPI CLSIDFromString32(
258         LPCOLESTR32 idstr,      /* [in] string representation of GUID */
259         CLSID *id               /* [out] GUID represented by above string */
260 ) {
261     LPOLESTR16      xid = HEAP_strdupWtoA(GetProcessHeap(),0,idstr);
262     OLESTATUS       ret = CLSIDFromString16(xid,id);
263
264     HeapFree(GetProcessHeap(),0,xid);
265     return ret;
266 }
267
268 /******************************************************************************
269  *              WINE_StringFromCLSID    [???]
270  * Converts a GUID into the respective string representation.
271  *
272  * NOTES
273  *    Why is this WINAPI?
274  *
275  * RETURNS
276  *      the string representation and OLESTATUS
277  */
278 OLESTATUS WINAPI WINE_StringFromCLSID(
279         const CLSID *id,        /* [in] GUID to be converted */
280         LPSTR idstr             /* [out] pointer to buffer to contain converted guid */
281 ) {
282   static const char *hex = "0123456789ABCDEF";
283   char *s;
284   int   i;
285
286   if (!id)
287         { ERR(ole,"called with id=Null\n");
288           *idstr = 0x00;
289           return E_FAIL;
290         }
291         
292   sprintf(idstr, "{%08lx-%04x-%04x-%02x%02x-",
293           id->Data1, id->Data2, id->Data3,
294           id->Data4[0], id->Data4[1]);
295   s = &idstr[25];
296
297   /* 6 hex bytes */
298   for (i = 2; i < 8; i++) {
299     *s++ = hex[id->Data4[i]>>4];
300     *s++ = hex[id->Data4[i] & 0xf];
301   }
302
303   *s++ = '}';
304   *s++ = '\0';
305
306   for (i = strlen(idstr)-1; i >= 0; i--) {
307     idstr[i] = toupper(idstr[i]);
308   }
309
310   TRACE(ole,"%p->%s\n", id, idstr);
311
312   return OLE_OK;
313 }
314
315 /******************************************************************************
316  *              StringFromCLSID16       [COMPOBJ.19]
317  * Converts a GUID into the respective string representation.
318  * The target string is allocated using the OLE IMalloc.
319  * RETURNS
320  *      the string representation and OLESTATUS
321  */
322 OLESTATUS WINAPI StringFromCLSID16(
323         const CLSID *id,        /* [in] the GUID to be converted */
324         LPOLESTR16 *idstr       /* [out] a pointer to a to-be-allocated segmented pointer pointing to the resulting string */
325
326 ) {
327     LPMALLOC16  mllc;
328     OLESTATUS   ret;
329     DWORD       args[2];
330
331     ret = CoGetMalloc16(0,&mllc);
332     if (ret) return ret;
333
334     args[0] = (DWORD)mllc;
335     args[1] = 40;
336
337     /* No need for a Callback entry, we have WOWCallback16Ex which does
338      * everything we need.
339      */
340     if (!WOWCallback16Ex(
341         (FARPROC16)((LPMALLOC16_VTABLE)PTR_SEG_TO_LIN(
342                 ((LPMALLOC16)PTR_SEG_TO_LIN(mllc))->lpvtbl)
343         )->fnAlloc,
344         WCB16_CDECL,
345         2,
346         (LPVOID)args,
347         (LPDWORD)idstr
348     )) {
349         WARN(ole,"CallTo16 IMalloc16 failed\n");
350         return E_FAIL;
351     }
352     return WINE_StringFromCLSID(id,PTR_SEG_TO_LIN(*idstr));
353 }
354
355 /******************************************************************************
356  *              StringFromCLSID32       [OLE32.151]
357  * Converts a GUID into the respective string representation.
358  * The target string is allocated using the OLE IMalloc.
359  * RETURNS
360  *      the string representation and OLESTATUS
361  */
362 OLESTATUS WINAPI StringFromCLSID32(
363         const CLSID *id,        /* [in] the GUID to be converted */
364         LPOLESTR32 *idstr       /* [out] a pointer to a to-be-allocated pointer pointing to the resulting string */
365 ) {
366         char            buf[80];
367         OLESTATUS       ret;
368         LPMALLOC32      mllc;
369
370         if ((ret=CoGetMalloc32(0,&mllc)))
371                 return ret;
372
373         ret=WINE_StringFromCLSID(id,buf);
374         if (!ret) {
375                 *idstr = mllc->lpvtbl->fnAlloc(mllc,strlen(buf)*2+2);
376                 lstrcpyAtoW(*idstr,buf);
377         }
378         return ret;
379 }
380
381 /******************************************************************************
382  *              StringFromGUID2 [COMPOBJ.76] [OLE32.152]
383  *
384  * Converts a global unique identifier into a string of an API-
385  * specified fixed format. (The usual {.....} stuff.)
386  *
387  * RETURNS
388  *      The (UNICODE) string representation of the GUID in 'str'
389  *      The length of the resulting string, 0 if there was any problem.
390  */
391 INT32 WINAPI
392 StringFromGUID2(REFGUID id, LPOLESTR32 str, INT32 cmax)
393 {
394   char          xguid[80];
395
396   if (WINE_StringFromCLSID(id,xguid))
397         return 0;
398   if (strlen(xguid)>=cmax)
399         return 0;
400   lstrcpyAtoW(str,xguid);
401   return strlen(xguid);
402 }
403
404 /******************************************************************************
405  *              CLSIDFromProgID16       [COMPOBJ.61]
406  * Converts a program id into the respective GUID. (By using a registry lookup)
407  * RETURNS
408  *      riid associated with the progid
409  */
410 OLESTATUS WINAPI CLSIDFromProgID16(
411         LPCOLESTR16 progid,     /* [in] program id as found in registry */
412         LPCLSID riid            /* [out] associated CLSID */
413 ) {
414         char    *buf,buf2[80];
415         DWORD   buf2len;
416         HRESULT err;
417         HKEY    xhkey;
418
419         buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8);
420         sprintf(buf,"%s\\CLSID",progid);
421         if ((err=RegOpenKey32A(HKEY_CLASSES_ROOT,buf,&xhkey))) {
422                 HeapFree(GetProcessHeap(),0,buf);
423                 return OLE_ERROR_GENERIC;
424         }
425         HeapFree(GetProcessHeap(),0,buf);
426         buf2len = sizeof(buf2);
427         if ((err=RegQueryValue32A(xhkey,NULL,buf2,&buf2len))) {
428                 RegCloseKey(xhkey);
429                 return OLE_ERROR_GENERIC;
430         }
431         RegCloseKey(xhkey);
432         return CLSIDFromString16(buf2,riid);
433 }
434
435 /******************************************************************************
436  *              CLSIDFromProgID32       [OLE32.2]
437  * Converts a program id into the respective GUID. (By using a registry lookup)
438  * RETURNS
439  *      riid associated with the progid
440  */
441 OLESTATUS WINAPI CLSIDFromProgID32(
442         LPCOLESTR32 progid,     /* [in] program id as found in registry */
443         LPCLSID riid            /* [out] associated CLSID */
444 ) {
445         LPOLESTR16 pid = HEAP_strdupWtoA(GetProcessHeap(),0,progid);
446         OLESTATUS       ret = CLSIDFromProgID16(pid,riid);
447
448         HeapFree(GetProcessHeap(),0,pid);
449         return ret;
450 }
451
452 /***********************************************************************
453  *           LookupETask (COMPOBJ.94)
454  */
455 OLESTATUS WINAPI LookupETask(HTASK16 *hTask,LPVOID p) {
456         FIXME(ole,"(%p,%p),stub!\n",hTask,p);
457         if ((*hTask = GetCurrentTask()) == hETask) {
458                 memcpy(p, Table_ETask, sizeof(Table_ETask));
459         }
460         return 0;
461 }
462
463 /***********************************************************************
464  *           SetETask (COMPOBJ.95)
465  */
466 OLESTATUS WINAPI SetETask(HTASK16 hTask, LPVOID p) {
467         FIXME(ole,"(%04x,%p),stub!\n",hTask,p);
468         hETask = hTask;
469         return 0;
470 }
471
472 /***********************************************************************
473  *           CallObjectInWOW (COMPOBJ.201)
474  */
475 OLESTATUS WINAPI CallObjectInWOW(LPVOID p1,LPVOID p2) {
476         FIXME(ole,"(%p,%p),stub!\n",p1,p2);
477         return 0;
478 }
479
480 /******************************************************************************
481  *              CoRegisterClassObject16 [COMPOBJ.5]
482  *
483  * Don't know where it registers it ...
484  */
485 OLESTATUS WINAPI CoRegisterClassObject16(
486         REFCLSID rclsid,
487         LPUNKNOWN pUnk,
488         DWORD dwClsContext,
489         DWORD flags,
490         LPDWORD lpdwRegister
491 ) {
492         char    buf[80];
493
494         WINE_StringFromCLSID(rclsid,buf);
495
496         FIXME(ole,"(%s,%p,0x%08lx,0x%08lx,%p),stub\n",
497                 buf,pUnk,dwClsContext,flags,lpdwRegister
498         );
499         return 0;
500 }
501
502 /******************************************************************************
503  *              CoRegisterClassObject32 [OLE32.36]
504  *
505  * Don't know where it registers it ...
506  */
507 OLESTATUS WINAPI CoRegisterClassObject32(
508         REFCLSID rclsid,
509         LPUNKNOWN pUnk,
510         DWORD dwClsContext,
511         DWORD flags,
512         LPDWORD lpdwRegister
513 ) {
514     char buf[80];
515
516     WINE_StringFromCLSID(rclsid,buf);
517
518     FIXME(ole,"(%s,%p,0x%08lx,0x%08lx,%p),stub\n",
519             buf,pUnk,dwClsContext,flags,lpdwRegister
520     );
521     return 0;
522 }
523
524 /***********************************************************************
525  *           CoGetClassObject [COMPOBJ.7]
526  */
527 HRESULT WINAPI CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext,
528                         LPVOID pvReserved, REFIID iid, LPVOID *ppv)
529 {
530     char xclsid[50],xiid[50];
531     HRESULT hres = E_UNEXPECTED;
532     char dllName[MAX_PATH+1];
533     LONG dllNameLen = MAX_PATH+1;
534     HINSTANCE32 hLibrary;
535     typedef HRESULT (*DllGetClassObjectFunc)(REFCLSID clsid, 
536                              REFIID iid, LPVOID *ppv);
537     DllGetClassObjectFunc DllGetClassObject;
538
539     HKEY CLSIDkey;
540     char buf[MAX_PATH + 1];
541     int i;
542     int found;
543
544     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
545     WINE_StringFromCLSID((LPCLSID)iid,xiid);
546     TRACE(ole,"\n\tCLSID:\t%s,\n\tIID:\t%s\n",xclsid,xiid);
547
548     /* out of process and remote servers not supported yet */
549     if ((CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER) & dwClsContext) {
550         FIXME(ole, "CLSCTX_LOCAL_SERVER and CLSCTX_REMOTE_SERVER not supported!\n");
551         return E_ACCESSDENIED;
552     }
553
554     if ((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext) {
555
556         /* lookup CLSID in registry key HKCR/CLSID */
557         hres = RegOpenKeyEx32A(HKEY_CLASSES_ROOT, "CLSID", 0, 
558                                KEY_ENUMERATE_SUB_KEYS, &CLSIDkey);
559
560         if (hres != ERROR_SUCCESS) {
561             return REGDB_E_READREGDB;
562         }
563
564         /* search all the subkeys for a match to xclsid */
565         found=FALSE;
566         for (i=0; i<100000; i++) {
567       
568             char clsidKeyPath[MAX_PATH + 1];
569             HKEY key;
570             LONG res;
571
572             res = RegEnumKey32A(CLSIDkey, i, buf, MAX_PATH);
573             if (res == ERROR_NO_MORE_ITEMS)
574                 break;
575             if (res != ERROR_SUCCESS)
576                 continue;
577
578             sprintf(clsidKeyPath, "CLSID\\%s", buf);
579             
580             if (lstrcmpi32A(buf, xclsid) != 0)
581                 continue;
582
583             res = RegOpenKeyEx32A(HKEY_CLASSES_ROOT, clsidKeyPath, 0, 
584                                   KEY_QUERY_VALUE, &key);
585             if (res != ERROR_SUCCESS) {
586                 return REGDB_E_READREGDB;
587             }
588             hres = RegQueryValue32A(key, "InprocServer32", dllName, &dllNameLen);
589             if (res != ERROR_SUCCESS) {
590                 return REGDB_E_READREGDB;
591             }
592             TRACE(ole,"found InprocServer32 dll %s\n", dllName);
593             found = TRUE;
594             break;
595         }
596
597         if (!found) {
598             return REGDB_E_CLASSNOTREG;
599         }
600
601         
602         /* open dll, call DllGetClassFactory */
603         hLibrary = CoLoadLibrary(dllName, TRUE);
604         
605         
606         if (hLibrary == 0) {
607             TRACE(ole,"couldn't load InprocServer32 dll %s\n", dllName);
608             return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
609         }
610
611         DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress32(hLibrary, "DllGetClassObject");
612         if (DllGetClassObject == NULL) {
613             /* not sure if this should be called here CoFreeLibrary(hLibrary);*/
614             TRACE(ole,"couldn't find function DllGetClassObject in %s\n", dllName);
615             return E_ACCESSDENIED;
616         }
617         
618         return DllGetClassObject(rclsid, iid, ppv);
619     }
620
621     return hres;
622 }
623
624 /******************************************************************************
625  *              CoRegisterMessageFilter16       [COMPOBJ.27]
626  */
627 OLESTATUS WINAPI CoRegisterMessageFilter16(
628         LPMESSAGEFILTER lpMessageFilter,
629         LPMESSAGEFILTER *lplpMessageFilter
630 ) {
631         FIXME(ole,"(%p,%p),stub!\n",lpMessageFilter,lplpMessageFilter);
632         return 0;
633 }
634
635 /***********************************************************************
636  *           CoCreateInstance [COMPOBJ.13, OLE32.7]
637  */
638 HRESULT WINAPI CoCreateInstance(
639         REFCLSID rclsid,
640         LPUNKNOWN pUnkOuter,
641         DWORD dwClsContext,
642         REFIID iid,
643         LPVOID *ppv
644 ) {
645 #if 0
646         char buf[80],xbuf[80];
647
648         if (rclsid)
649                 WINE_StringFromCLSID(rclsid,buf);
650         else
651                 sprintf(buf,"<rclsid-0x%08lx>",(DWORD)rclsid);
652         if (iid)
653                 WINE_StringFromCLSID(iid,xbuf);
654         else
655                 sprintf(xbuf,"<iid-0x%08lx>",(DWORD)iid);
656
657         FIXME(ole,"(%s,%p,0x%08lx,%s,%p): stub !\n",buf,pUnkOuter,dwClsContext,xbuf,ppv);
658         *ppv = NULL;
659 #else   
660         HRESULT hres;
661         LPCLASSFACTORY lpclf = 0;
662
663         hres = CoGetClassObject(rclsid, dwClsContext, NULL, &IID_IClassFactory, (LPVOID)&lpclf);
664         if (!SUCCEEDED(hres)) return hres;
665         hres = lpclf->lpvtbl->fnCreateInstance(lpclf, pUnkOuter, iid, ppv);
666         lpclf->lpvtbl->fnRelease(lpclf);
667         return hres;
668 #endif
669 }
670
671
672
673 /***********************************************************************
674  *           CoFreeLibrary [COMPOBJ.13]
675  */
676 void WINAPI CoFreeLibrary(HINSTANCE32 hLibrary)
677 {
678     OpenDll *ptr, *prev;
679     OpenDll *tmp;
680
681     /* lookup library in linked list */
682     prev = NULL;
683     for (ptr = openDllList; ptr != NULL; ptr=ptr->next) {
684         if (ptr->hLibrary == hLibrary) {
685             break;
686         }
687         prev = ptr;
688     }
689
690     if (ptr == NULL) {
691         /* shouldn't happen if user passed in a valid hLibrary */
692         return;
693     }
694     /* assert: ptr points to the library entry to free */
695
696     /* free library and remove node from list */
697     FreeLibrary32(hLibrary);
698     if (ptr == openDllList) {
699         tmp = openDllList->next;
700         HeapFree(GetProcessHeap(), 0, openDllList->DllName);
701         HeapFree(GetProcessHeap(), 0, openDllList);
702         openDllList = tmp;
703     } else {
704         tmp = ptr->next;
705         HeapFree(GetProcessHeap(), 0, ptr->DllName);
706         HeapFree(GetProcessHeap(), 0, ptr);
707         prev->next = tmp;
708     }
709
710 }
711
712
713 /***********************************************************************
714  *           CoFreeAllLibraries [COMPOBJ.12]
715  */
716 void WINAPI CoFreeAllLibraries(void)
717 {
718     OpenDll *ptr, *tmp;
719
720     for (ptr = openDllList; ptr != NULL; ) {
721         tmp=ptr->next;
722         CoFreeLibrary(ptr->hLibrary);
723         ptr = tmp;
724     }
725 }
726
727
728
729 /***********************************************************************
730  *           CoFreeUnusedLibraries [COMPOBJ.17]
731  */
732 void WINAPI CoFreeUnusedLibraries(void)
733 {
734     OpenDll *ptr, *tmp;
735     typedef HRESULT(*DllCanUnloadNowFunc)(void);
736     DllCanUnloadNowFunc DllCanUnloadNow;
737
738     for (ptr = openDllList; ptr != NULL; ) {
739         DllCanUnloadNow = (DllCanUnloadNowFunc)
740             GetProcAddress32(ptr->hLibrary, "DllCanUnloadNow");
741         
742         if (DllCanUnloadNow() == S_OK) {
743             tmp=ptr->next;
744             CoFreeLibrary(ptr->hLibrary);
745             ptr = tmp;
746         } else {
747             ptr=ptr->next;
748         }
749     }
750 }
751
752 /***********************************************************************
753  *           CoFileTimeNow [COMPOBJ.82, OLE32.10]
754  * RETURNS
755  *      the current system time in lpFileTime
756  */
757 HRESULT WINAPI CoFileTimeNow(
758         FILETIME *lpFileTime    /* [out] the current time */
759 ) {
760         DOSFS_UnixTimeToFileTime(time(NULL), lpFileTime, 0);
761         return S_OK;
762 }
763
764 /***********************************************************************
765  *           CoTaskMemAlloc (OLE32.43)
766  * RETURNS
767  *      pointer to newly allocated block
768  */
769 LPVOID WINAPI CoTaskMemAlloc(
770         ULONG size      /* [in] size of memoryblock to be allocated */
771 ) {
772     LPMALLOC32  lpmalloc;
773     HRESULT     ret = CoGetMalloc32(0,&lpmalloc);
774
775     if (ret) 
776         return NULL;
777     return lpmalloc->lpvtbl->fnAlloc(lpmalloc,size);
778 }
779
780 /***********************************************************************
781  *           CoTaskMemFree (OLE32.44)
782  */
783 VOID WINAPI CoTaskMemFree(
784         LPVOID ptr      /* [in] pointer to be freed */
785 ) {
786     LPMALLOC32  lpmalloc;
787     HRESULT     ret = CoGetMalloc32(0,&lpmalloc);
788
789     if (ret) return;
790     return lpmalloc->lpvtbl->fnFree(lpmalloc,ptr);
791 }
792
793 /***********************************************************************
794  *           CoLoadLibrary (OLE32.30)
795  */
796 HINSTANCE32 WINAPI CoLoadLibrary(LPSTR lpszLibName, BOOL32 bAutoFree)
797 {
798     HINSTANCE32 hLibrary;
799     OpenDll *ptr;
800     OpenDll *tmp;
801   
802     TRACE(ole,"CoLoadLibrary(%p, %d\n", lpszLibName, bAutoFree);
803
804     hLibrary = LoadLibrary32A(lpszLibName);
805
806     if (!bAutoFree)
807         return hLibrary;
808
809     if (openDllList == NULL) {
810         /* empty list -- add first node */
811         openDllList = (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
812         openDllList->DllName = HEAP_strdupA(GetProcessHeap(), 0, lpszLibName);
813         openDllList->hLibrary = hLibrary;
814         openDllList->next = NULL;
815     } else {
816         /* search for this dll */
817         int found = FALSE;
818         for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) {
819             if (ptr->hLibrary == hLibrary) {
820                 found = TRUE;
821                 break;
822             }
823         }
824         if (!found) {
825             /* dll not found, add it */
826             tmp = openDllList;
827             openDllList->next = 
828                 (OpenDll*)HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
829             openDllList->DllName = HEAP_strdupA(GetProcessHeap(), 0, lpszLibName);
830             openDllList->hLibrary = hLibrary;
831             openDllList->next = tmp;
832         }
833     }
834      
835     return hLibrary;
836 }
837
838 /***********************************************************************
839  *           CoInitializeWOW (OLE32.27)
840  */
841 HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
842     FIXME(ole,"(0x%08lx,0x%08lx),stub!\n",x,y);
843     return 0;
844 }
845
846 /******************************************************************************
847  *              CoLockObjectExternal16  [COMPOBJ.63]
848  */
849 HRESULT WINAPI CoLockObjectExternal16(
850     LPUNKNOWN pUnk,             /* [in] object to be locked */
851     BOOL16 fLock,               /* [in] do lock */
852     BOOL16 fLastUnlockReleases  /* [in] ? */
853 ) {
854     FIXME(ole,"(%p,%d,%d),stub!\n",pUnk,fLock,fLastUnlockReleases);
855     return S_OK;
856 }
857
858 /******************************************************************************
859  *              CoLockObjectExternal32  [OLE32.31]
860  */
861 HRESULT WINAPI CoLockObjectExternal32(
862     LPUNKNOWN pUnk,             /* [in] object to be locked */
863     BOOL32 fLock,               /* [in] do lock */
864     BOOL32 fLastUnlockReleases  /* [in] ? */
865 ) {
866     FIXME(ole,"(%p,%d,%d),stub!\n",pUnk,fLock,fLastUnlockReleases);
867     return S_OK;
868 }
869
870 /***********************************************************************
871  *           CoGetState16 [COMPOBJ.115]
872  */
873 HRESULT WINAPI CoGetState16(LPDWORD state)
874 {
875     FIXME(ole, "(%p),stub!\n", state);
876     *state = 0;
877     return S_OK;
878 }
879 /***********************************************************************
880  *           CoSetState32 [COM32.42]
881  */
882 HRESULT WINAPI CoSetState32(LPDWORD state)
883 {
884     FIXME(ole, "(%p),stub!\n", state);
885     *state = 0;
886     return S_OK;
887 }