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