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