ddraw: Avoid LPD3DTRIANGLE.
[wine] / dlls / setupapi / setupcab.c
1 /* 
2  * Setupapi cabinet routines
3  *
4  * Copyright 2003 Gregory M. Turner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  *
21  * Many useful traces are commented in code, uncomment them if you have
22  * trouble and run with WINEDEBUG=+setupapi
23  * 
24  */
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winnls.h"
35 #include "winreg.h"
36 #include "setupapi.h"
37 #include "setupapi_private.h"
38 #include "fdi.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
41
42 /* from msvcrt */
43 #define _O_RDONLY      0
44 #define _O_WRONLY      1
45 #define _O_RDWR        2
46 #define _O_ACCMODE     (_O_RDONLY|_O_WRONLY|_O_RDWR)
47 #define _O_APPEND      0x0008
48 #define _O_RANDOM      0x0010
49 #define _O_SEQUENTIAL  0x0020
50 #define _O_TEMPORARY   0x0040
51 #define _O_NOINHERIT   0x0080
52 #define _O_CREAT       0x0100
53 #define _O_TRUNC       0x0200
54 #define _O_EXCL        0x0400
55 #define _O_SHORT_LIVED 0x1000
56 #define _O_TEXT        0x4000
57 #define _O_BINARY      0x8000
58
59 #define _SH_COMPAT     0x00
60 #define _SH_DENYRW     0x10
61 #define _SH_DENYWR     0x20
62 #define _SH_DENYRD     0x30
63 #define _SH_DENYNO     0x40
64
65 OSVERSIONINFOW OsVersionInfo;
66
67 static HINSTANCE CABINET_hInstance = 0;
68 HINSTANCE SETUPAPI_hInstance = 0;
69
70 static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN,
71                 PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF);
72
73 static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int,
74                 PFNFDINOTIFY, PFNFDIDECRYPT, void *);
75
76 static BOOL (__cdecl *sc_FDIDestroy)(HFDI);
77
78 #define SC_HSC_A_MAGIC 0xACABFEED
79 typedef struct {
80   UINT magic;
81   HFDI hfdi;
82   PSP_FILE_CALLBACK_A msghandler;
83   PVOID context;
84   CHAR most_recent_cabinet_name[MAX_PATH];
85   CHAR most_recent_target[MAX_PATH];
86 } SC_HSC_A, *PSC_HSC_A;
87
88 #define SC_HSC_W_MAGIC 0x0CABFEED
89 typedef struct {
90   UINT magic;
91   HFDI hfdi;
92   PSP_FILE_CALLBACK_W msghandler;
93   PVOID context;
94   WCHAR most_recent_cabinet_name[MAX_PATH];
95   WCHAR most_recent_target[MAX_PATH];
96 } SC_HSC_W, *PSC_HSC_W;
97
98 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
99
100 static BOOL LoadCABINETDll(void)
101 {
102   if (!CABINET_hInstance) {
103     CABINET_hInstance = LoadLibraryA("cabinet.dll");
104     if (CABINET_hInstance)  {
105       sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate");
106       sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy");
107       sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy");
108       return TRUE;
109     } else {
110       ERR("load cabinet dll failed.\n");
111       return FALSE;
112     }
113   } else
114     return TRUE;
115 }
116
117 static void UnloadCABINETDll(void)
118 {
119   if (CABINET_hInstance) {
120     FreeLibrary(CABINET_hInstance);
121     CABINET_hInstance = 0;
122   }
123 }
124
125 /* FDICreate callbacks */
126
127 static void * CDECL sc_cb_alloc(ULONG cb)
128 {
129   return HeapAlloc(GetProcessHeap(), 0, cb);
130 }
131
132 static void CDECL sc_cb_free(void *pv)
133 {
134   HeapFree(GetProcessHeap(), 0, pv);
135 }
136
137 static INT_PTR CDECL sc_cb_open(char *pszFile, int oflag, int pmode)
138 {
139   DWORD creation = 0, sharing = 0;
140   int ioflag = 0;
141   INT_PTR ret = 0;
142   SECURITY_ATTRIBUTES sa;
143
144   /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
145
146   switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
147   case _O_RDONLY:
148     ioflag |= GENERIC_READ;
149     break;
150   case _O_WRONLY:
151     ioflag |= GENERIC_WRITE;
152     break;
153   case _O_RDWR:
154     ioflag |= GENERIC_READ | GENERIC_WRITE;
155     break;
156   case _O_WRONLY | _O_RDWR: /* hmmm.. */
157     ERR("_O_WRONLY & _O_RDWR in oflag?\n");
158     return -1;
159   }
160
161   if (oflag & _O_CREAT) {
162     if (oflag & _O_EXCL)
163       creation = CREATE_NEW;
164     else if (oflag & _O_TRUNC)
165       creation = CREATE_ALWAYS;
166     else
167       creation = OPEN_ALWAYS;
168   } else  /* no _O_CREAT */ {
169     if (oflag & _O_TRUNC)
170       creation = TRUNCATE_EXISTING;
171     else
172       creation = OPEN_EXISTING;
173   }
174
175   switch( pmode & 0x70 ) {
176     case _SH_DENYRW:
177       sharing = 0L;
178       break;
179     case _SH_DENYWR:
180       sharing = FILE_SHARE_READ;
181       break;
182     case _SH_DENYRD:
183       sharing = FILE_SHARE_WRITE;
184       break;
185     case _SH_COMPAT:
186     case _SH_DENYNO:
187       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
188       break;
189     default:
190       ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode);
191       return -1;
192   }
193
194   if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT))
195     WARN("unsupported oflag 0x%04x\n",oflag);
196
197   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
198   sa.lpSecurityDescriptor = NULL;
199   sa.bInheritHandle       = !(ioflag & _O_NOINHERIT);
200
201   ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
202
203   /* TRACE("<-- %d\n", ret); */
204
205   return ret;
206 }
207
208 static UINT CDECL sc_cb_read(INT_PTR hf, void *pv, UINT cb)
209 {
210   DWORD num_read;
211   BOOL rslt;
212
213   /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
214
215   rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
216
217
218   /* eof and failure both give "-1" return */
219   if ((! rslt) || ((cb > 0) && (num_read == 0))) {
220     /* TRACE("<-- -1\n"); */
221     return -1;
222   }
223
224   /* TRACE("<-- %lu\n", num_read); */
225   return num_read;
226 }
227
228 static UINT CDECL sc_cb_write(INT_PTR hf, void *pv, UINT cb)
229 {
230   DWORD num_written;
231   /* BOOL rv; */
232
233   /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
234
235   if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */
236        && (num_written == cb)) {
237     /* TRACE("<-- %lu\n", num_written); */
238     return num_written;
239   } else {
240     /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
241     /* TRACE("<-- -1\n"); */
242     return -1;
243   }
244 }
245
246 static int CDECL sc_cb_close(INT_PTR hf)
247 {
248   /* TRACE("(hf == %d)\n", hf); */
249
250   if (CloseHandle((HANDLE) hf))
251     return 0;
252   else
253     return -1;
254 }
255
256 static LONG CDECL sc_cb_lseek(INT_PTR hf, LONG dist, int seektype)
257 {
258   DWORD ret;
259
260   /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
261
262   if (seektype < 0 || seektype > 2)
263     return -1;
264
265   if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) {
266     /* TRACE("<-- %lu\n", ret); */
267     return ret;
268   } else {
269     /* TRACE("<-- -1\n"); */
270     return -1;
271   }
272 }
273
274 #define SIZEOF_MYSTERIO (MAX_PATH*3)
275
276 /* FDICopy callbacks */
277
278 static INT_PTR CDECL sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
279 {
280   FILE_IN_CABINET_INFO_A fici;
281   PSC_HSC_A phsc;
282   CABINET_INFO_A ci;
283   FILEPATHS_A fp;
284   UINT err;
285
286   CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
287
288   memset(mysterio, 0, SIZEOF_MYSTERIO);
289
290   TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
291
292   if (pfdin && pfdin->pv && (((PSC_HSC_A) pfdin->pv)->magic == SC_HSC_A_MAGIC))
293     phsc = pfdin->pv;
294   else {
295     ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL);
296     return -1;
297   }
298
299   switch (fdint) {
300   case fdintCABINET_INFO:
301     TRACE("Cabinet info notification\n");
302     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
303     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
304     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
305     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
306     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
307     WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
308     ci.CabinetFile = phsc->most_recent_cabinet_name;
309     ci.CabinetPath = pfdin->psz3;
310     ci.DiskName = pfdin->psz2;
311     ci.SetId = pfdin->setID;
312     ci.CabinetNumber = pfdin->iCabinet;
313     phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR) &ci, 0);
314     return 0;
315   case fdintPARTIAL_FILE:
316     TRACE("Partial file notification\n");
317     /* TRACE("  Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
318     return 0;
319   case fdintCOPY_FILE:
320     TRACE("Copy file notification\n");
321     TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
322     /* TRACE("  File size: %ld\n", pfdin->cb);
323     TRACE("  File date: %u\n", pfdin->date);
324     TRACE("  File time: %u\n", pfdin->time);
325     TRACE("  File attr: %u\n", pfdin->attribs); */
326     fici.NameInCabinet = pfdin->psz1;
327     fici.FileSize = pfdin->cb;
328     fici.Win32Error = 0;
329     fici.DosDate = pfdin->date;
330     fici.DosTime = pfdin->time;
331     fici.DosAttribs = pfdin->attribs;
332     memset(fici.FullTargetName, 0, MAX_PATH);
333     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
334                            (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
335     if (err == FILEOP_DOIT) {
336       TRACE("  Callback specified filename: %s\n", debugstr_a(fici.FullTargetName));
337       if (!fici.FullTargetName[0]) {
338         WARN("  Empty return string causing abort.\n");
339         SetLastError(ERROR_PATH_NOT_FOUND);
340         return -1;
341       }
342       strcpy( phsc->most_recent_target, fici.FullTargetName );
343       return sc_cb_open(fici.FullTargetName, _O_BINARY | _O_CREAT | _O_WRONLY,  _S_IREAD | _S_IWRITE);
344     } else {
345       TRACE("  Callback skipped file.\n");
346       return 0;
347     }
348   case fdintCLOSE_FILE_INFO:
349     TRACE("Close file notification\n");
350     /* TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
351     TRACE("  Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
352     TRACE("  File hndl: %d\n", pfdin->hf); */
353     fp.Source = phsc->most_recent_cabinet_name;
354     fp.Target = phsc->most_recent_target;
355     fp.Win32Error = 0;
356     fp.Flags = 0;
357     /* the following should be a fixme -- but it occurs too many times */
358     WARN("Should set file date/time/attribs (and execute files?)\n");
359     if (sc_cb_close(pfdin->hf))
360       WARN("_close failed.\n");
361     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
362     if (err) {
363       SetLastError(err);
364       return FALSE;
365     } else
366       return TRUE;
367   case fdintNEXT_CABINET:
368     TRACE("Next cabinet notification\n");
369     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
370     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
371     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
372     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
373     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
374     ci.CabinetFile = pfdin->psz1;
375     ci.CabinetPath = pfdin->psz3;
376     ci.DiskName = pfdin->psz2;
377     ci.SetId = pfdin->setID;
378     ci.CabinetNumber = pfdin->iCabinet;
379     /* remember the new cabinet name */
380     strcpy(phsc->most_recent_cabinet_name, pfdin->psz1);
381     err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
382     if (err) {
383       SetLastError(err);
384       return -1;
385     } else {
386       if (mysterio[0]) {
387         /* some easy paranoia.  no such carefulness exists on the wide API IIRC */
388         lstrcpynA(pfdin->psz3, mysterio, SIZEOF_MYSTERIO);
389       }
390       return 0;
391     }
392   default:
393     FIXME("Unknown notification type %d.\n", fdint);
394     return 0;
395   }
396 }
397
398 static INT_PTR CDECL sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
399 {
400   FILE_IN_CABINET_INFO_W fici;
401   PSC_HSC_W phsc;
402   CABINET_INFO_W ci;
403   FILEPATHS_W fp;
404   UINT err;
405   int len;
406
407   WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
408   WCHAR buf[MAX_PATH], buf2[MAX_PATH];
409   CHAR charbuf[MAX_PATH];
410
411   memset(mysterio, 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
412   memset(buf, 0, MAX_PATH * sizeof(WCHAR));
413   memset(buf2, 0, MAX_PATH * sizeof(WCHAR));
414   memset(charbuf, 0, MAX_PATH);
415
416   TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
417
418   if (pfdin && pfdin->pv && (((PSC_HSC_W) pfdin->pv)->magic == SC_HSC_W_MAGIC))
419     phsc = pfdin->pv;
420   else {
421     ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
422     return -1;
423   }
424
425   switch (fdint) {
426   case fdintCABINET_INFO:
427     TRACE("Cabinet info notification\n");
428     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
429     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
430     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
431     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
432     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
433     WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
434     ci.CabinetFile = phsc->most_recent_cabinet_name;
435     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
436     if ((len > MAX_PATH) || (len <= 1))
437       buf[0] = '\0';
438     ci.CabinetPath = buf;
439     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
440     if ((len > MAX_PATH) || (len <= 1))
441       buf2[0] = '\0';
442     ci.DiskName = buf2;
443     ci.SetId = pfdin->setID;
444     ci.CabinetNumber = pfdin->iCabinet;
445     phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR)&ci, 0);
446     return 0;
447   case fdintPARTIAL_FILE:
448     TRACE("Partial file notification\n");
449     /* TRACE("  Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
450     return 0;
451   case fdintCOPY_FILE:
452     TRACE("Copy file notification\n");
453     TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
454     /* TRACE("  File size: %ld\n", pfdin->cb);
455     TRACE("  File date: %u\n", pfdin->date);
456     TRACE("  File time: %u\n", pfdin->time);
457     TRACE("  File attr: %u\n", pfdin->attribs); */
458     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, buf2, MAX_PATH);
459     if ((len > MAX_PATH) || (len <= 1))
460       buf2[0] = '\0';
461     fici.NameInCabinet = buf2;
462     fici.FileSize = pfdin->cb;
463     fici.Win32Error = 0;
464     fici.DosDate = pfdin->date;
465     fici.DosTime = pfdin->time;
466     fici.DosAttribs = pfdin->attribs;
467     memset(fici.FullTargetName, 0, MAX_PATH * sizeof(WCHAR));
468     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
469                            (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
470     if (err == FILEOP_DOIT) {
471       TRACE("  Callback specified filename: %s\n", debugstr_w(fici.FullTargetName));
472       if (fici.FullTargetName[0]) {
473         len = strlenW(fici.FullTargetName) + 1;
474         if ((len > MAX_PATH ) || (len <= 1))
475           return 0;
476         if (!WideCharToMultiByte(CP_ACP, 0, fici.FullTargetName, len, charbuf, MAX_PATH, 0, 0))
477           return 0;
478       } else {
479         WARN("Empty buffer string caused abort.\n");
480         SetLastError(ERROR_PATH_NOT_FOUND);
481         return -1;
482       }
483       strcpyW( phsc->most_recent_target, fici.FullTargetName );
484       return sc_cb_open(charbuf, _O_BINARY | _O_CREAT | _O_WRONLY,  _S_IREAD | _S_IWRITE);
485     } else {
486       TRACE("  Callback skipped file.\n");
487       return 0;
488     }
489   case fdintCLOSE_FILE_INFO:
490     TRACE("Close file notification\n");
491     /* TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
492     TRACE("  Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
493     TRACE("  File hndl: %d\n", pfdin->hf); */
494     fp.Source = phsc->most_recent_cabinet_name;
495     fp.Target = phsc->most_recent_target;
496     fp.Win32Error = 0;
497     fp.Flags = 0;
498     /* a valid fixme -- but occurs too many times */
499     /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
500     if (sc_cb_close(pfdin->hf))
501       WARN("_close failed.\n");
502     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
503     if (err) {
504       SetLastError(err);
505       return FALSE;
506     } else
507       return TRUE;
508   case fdintNEXT_CABINET:
509     TRACE("Next cabinet notification\n");
510     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
511     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
512     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
513     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
514     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
515     /* remember the new cabinet name */
516     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, phsc->most_recent_cabinet_name, MAX_PATH);
517     if ((len > MAX_PATH) || (len <= 1))
518       phsc->most_recent_cabinet_name[0] = '\0';
519     ci.CabinetFile = phsc->most_recent_cabinet_name;
520     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
521     if ((len > MAX_PATH) || (len <= 1))
522       buf[0] = '\0';
523     ci.CabinetPath = buf;
524     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
525     if ((len > MAX_PATH) || (len <= 1))
526       buf2[0] = '\0';
527     ci.DiskName = buf2;
528     ci.SetId = pfdin->setID;
529     ci.CabinetNumber = pfdin->iCabinet;
530     err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
531     if (err) {
532       SetLastError(err);
533       return -1;
534     } else {
535       if (mysterio[0]) {
536         len = strlenW(mysterio) + 1;
537         if ((len > 255) || (len <= 1))
538           return 0;
539         if (!WideCharToMultiByte(CP_ACP, 0, mysterio, len, pfdin->psz3, 255, 0, 0))
540           return 0;
541       }
542       return 0;
543     }
544   default:
545     FIXME("Unknown notification type %d.\n", fdint);
546     return 0;
547   }
548 }
549
550 /***********************************************************************
551  *              SetupIterateCabinetA (SETUPAPI.@)
552  */
553 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
554                                  PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
555 {
556
557   SC_HSC_A my_hsc;
558   ERF erf;
559   CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p = NULL;
560   DWORD fpnsize;
561   BOOL ret;
562
563   TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
564         debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
565
566   if (!LoadCABINETDll())
567     return FALSE;
568
569   if (!CabinetFile)
570   {
571     SetLastError(ERROR_INVALID_PARAMETER);
572     return FALSE;
573   }
574
575   fpnsize = strlen(CabinetFile);
576   if (fpnsize >= MAX_PATH) {
577     SetLastError(ERROR_BAD_PATHNAME);
578     return FALSE;
579   }
580
581   fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, pszCabPath, &p);
582   if (fpnsize > MAX_PATH) {
583     SetLastError(ERROR_BAD_PATHNAME);
584     return FALSE;
585   }
586
587   if (p) {
588     strcpy(pszCabinet, p);
589     *p = '\0';
590   } else {
591     strcpy(pszCabinet, CabinetFile);
592     pszCabPath[0] = '\0';
593   }
594
595   TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
596
597   /* remember the cabinet name */
598   strcpy(my_hsc.most_recent_cabinet_name, pszCabinet);
599
600   my_hsc.magic = SC_HSC_A_MAGIC;
601   my_hsc.msghandler = MsgHandler;
602   my_hsc.context = Context;
603   my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
604                            sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
605
606   if (!my_hsc.hfdi) return FALSE;
607
608   ret = sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_A, NULL, &my_hsc);
609
610   sc_FDIDestroy(my_hsc.hfdi);
611   return ret;
612 }
613
614
615 /***********************************************************************
616  *              SetupIterateCabinetW (SETUPAPI.@)
617  */
618 BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
619                                  PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
620 {
621   CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH];
622   UINT len;
623   SC_HSC_W my_hsc;
624   ERF erf;
625   WCHAR pszCabPathW[MAX_PATH], *p = NULL;
626   DWORD fpnsize;
627   BOOL ret;
628
629   TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
630         debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
631
632   if (!LoadCABINETDll())
633     return FALSE;
634
635   if (!CabinetFile)
636   {
637     SetLastError(ERROR_INVALID_PARAMETER);
638     return FALSE;
639   }
640
641   fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p);
642   if (fpnsize > MAX_PATH) {
643     SetLastError(ERROR_BAD_PATHNAME);
644     return FALSE;
645   }
646
647   if (p) {
648     strcpyW(my_hsc.most_recent_cabinet_name, p);
649     *p = 0;
650     len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath,
651                                 MAX_PATH, 0, 0);
652     if (!len) return FALSE;
653   } else {
654     strcpyW(my_hsc.most_recent_cabinet_name, CabinetFile);
655     pszCabPath[0] = '\0';
656   }
657
658   len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1,
659                                 pszCabinet, MAX_PATH, 0, 0);
660   if (!len) return FALSE;
661
662   TRACE("path: %s, cabfile: %s\n",
663         debugstr_a(pszCabPath), debugstr_a(pszCabinet));
664
665   my_hsc.magic = SC_HSC_W_MAGIC;
666   my_hsc.msghandler = MsgHandler;
667   my_hsc.context = Context;
668   my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
669                               sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
670
671   if (!my_hsc.hfdi) return FALSE;
672
673   ret = sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_W, NULL, &my_hsc);
674
675   sc_FDIDestroy(my_hsc.hfdi);
676   return ret;
677 }
678
679
680 /***********************************************************************
681  * DllMain
682  *
683  * PARAMS
684  *     hinstDLL    [I] handle to the DLL's instance
685  *     fdwReason   [I]
686  *     lpvReserved [I] reserved, must be NULL
687  *
688  * RETURNS
689  *     Success: TRUE
690  *     Failure: FALSE
691  */
692
693 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
694 {
695     switch (fdwReason) {
696     case DLL_PROCESS_ATTACH:
697         DisableThreadLibraryCalls(hinstDLL);
698         OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
699         if (!GetVersionExW(&OsVersionInfo))
700             return FALSE;
701         SETUPAPI_hInstance = hinstDLL;
702         break;
703     case DLL_PROCESS_DETACH:
704         UnloadCABINETDll();
705         break;
706     }
707
708     return TRUE;
709 }