msxml3: Store output stream for processor.
[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 } SC_HSC_A, *PSC_HSC_A;
86
87 #define SC_HSC_W_MAGIC 0x0CABFEED
88 typedef struct {
89   UINT magic;
90   HFDI hfdi;
91   PSP_FILE_CALLBACK_W msghandler;
92   PVOID context;
93   WCHAR most_recent_cabinet_name[MAX_PATH];
94 } SC_HSC_W, *PSC_HSC_W;
95
96 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
97
98 static BOOL LoadCABINETDll(void)
99 {
100   if (!CABINET_hInstance) {
101     CABINET_hInstance = LoadLibraryA("cabinet.dll");
102     if (CABINET_hInstance)  {
103       sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate");
104       sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy");
105       sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy");
106       return TRUE;
107     } else {
108       ERR("load cabinet dll failed.\n");
109       return FALSE;
110     }
111   } else
112     return TRUE;
113 }
114
115 static void UnloadCABINETDll(void)
116 {
117   if (CABINET_hInstance) {
118     FreeLibrary(CABINET_hInstance);
119     CABINET_hInstance = 0;
120   }
121 }
122
123 /* FDICreate callbacks */
124
125 static void * CDECL sc_cb_alloc(ULONG cb)
126 {
127   return HeapAlloc(GetProcessHeap(), 0, cb);
128 }
129
130 static void CDECL sc_cb_free(void *pv)
131 {
132   HeapFree(GetProcessHeap(), 0, pv);
133 }
134
135 static INT_PTR CDECL sc_cb_open(char *pszFile, int oflag, int pmode)
136 {
137   DWORD creation = 0, sharing = 0;
138   int ioflag = 0;
139   INT_PTR ret = 0;
140   SECURITY_ATTRIBUTES sa;
141
142   /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
143
144   switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
145   case _O_RDONLY:
146     ioflag |= GENERIC_READ;
147     break;
148   case _O_WRONLY:
149     ioflag |= GENERIC_WRITE;
150     break;
151   case _O_RDWR:
152     ioflag |= GENERIC_READ | GENERIC_WRITE;
153     break;
154   case _O_WRONLY | _O_RDWR: /* hmmm.. */
155     ERR("_O_WRONLY & _O_RDWR in oflag?\n");
156     return -1;
157   }
158
159   if (oflag & _O_CREAT) {
160     if (oflag & _O_EXCL)
161       creation = CREATE_NEW;
162     else if (oflag & _O_TRUNC)
163       creation = CREATE_ALWAYS;
164     else
165       creation = OPEN_ALWAYS;
166   } else  /* no _O_CREAT */ {
167     if (oflag & _O_TRUNC)
168       creation = TRUNCATE_EXISTING;
169     else
170       creation = OPEN_EXISTING;
171   }
172
173   switch( pmode & 0x70 ) {
174     case _SH_DENYRW:
175       sharing = 0L;
176       break;
177     case _SH_DENYWR:
178       sharing = FILE_SHARE_READ;
179       break;
180     case _SH_DENYRD:
181       sharing = FILE_SHARE_WRITE;
182       break;
183     case _SH_COMPAT:
184     case _SH_DENYNO:
185       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
186       break;
187     default:
188       ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode);
189       return -1;
190   }
191
192   if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT))
193     WARN("unsupported oflag 0x%04x\n",oflag);
194
195   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
196   sa.lpSecurityDescriptor = NULL;
197   sa.bInheritHandle       = (ioflag & _O_NOINHERIT) ? FALSE : TRUE;
198
199   ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
200
201   /* TRACE("<-- %d\n", ret); */
202
203   return ret;
204 }
205
206 static UINT CDECL sc_cb_read(INT_PTR hf, void *pv, UINT cb)
207 {
208   DWORD num_read;
209   BOOL rslt;
210
211   /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
212
213   rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
214
215
216   /* eof and failure both give "-1" return */
217   if ((! rslt) || ((cb > 0) && (num_read == 0))) {
218     /* TRACE("<-- -1\n"); */
219     return -1;
220   }
221
222   /* TRACE("<-- %lu\n", num_read); */
223   return num_read;
224 }
225
226 static UINT CDECL sc_cb_write(INT_PTR hf, void *pv, UINT cb)
227 {
228   DWORD num_written;
229   /* BOOL rv; */
230
231   /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
232
233   if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */
234        && (num_written == cb)) {
235     /* TRACE("<-- %lu\n", num_written); */
236     return num_written;
237   } else {
238     /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
239     /* TRACE("<-- -1\n"); */
240     return -1;
241   }
242 }
243
244 static int CDECL sc_cb_close(INT_PTR hf)
245 {
246   /* TRACE("(hf == %d)\n", hf); */
247
248   if (CloseHandle((HANDLE) hf))
249     return 0;
250   else
251     return -1;
252 }
253
254 static LONG CDECL sc_cb_lseek(INT_PTR hf, LONG dist, int seektype)
255 {
256   DWORD ret;
257
258   /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
259
260   if (seektype < 0 || seektype > 2)
261     return -1;
262
263   if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) {
264     /* TRACE("<-- %lu\n", ret); */
265     return ret;
266   } else {
267     /* TRACE("<-- -1\n"); */
268     return -1;
269   }
270 }
271
272 #define SIZEOF_MYSTERIO (MAX_PATH*3)
273
274 /* FDICopy callbacks */
275
276 static INT_PTR CDECL sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
277 {
278   FILE_IN_CABINET_INFO_A fici;
279   PSC_HSC_A phsc;
280   CABINET_INFO_A ci;
281   FILEPATHS_A fp;
282   UINT err;
283
284   CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
285
286   memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO);
287
288   TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
289
290   if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_A_MAGIC))
291     phsc = pfdin->pv;
292   else {
293     ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL);
294     return -1;
295   }
296
297   switch (fdint) {
298   case fdintCABINET_INFO:
299     TRACE("Cabinet info notification\n");
300     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
301     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
302     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
303     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
304     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
305     WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
306     ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
307     ci.CabinetPath = pfdin->psz3;
308     ci.DiskName = pfdin->psz2;
309     ci.SetId = pfdin->setID;
310     ci.CabinetNumber = pfdin->iCabinet;
311     phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR) &ci, 0);
312     return 0;
313   case fdintPARTIAL_FILE:
314     TRACE("Partial file notification\n");
315     /* TRACE("  Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
316     return 0;
317   case fdintCOPY_FILE:
318     TRACE("Copy file notification\n");
319     TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
320     /* TRACE("  File size: %ld\n", pfdin->cb);
321     TRACE("  File date: %u\n", pfdin->date);
322     TRACE("  File time: %u\n", pfdin->time);
323     TRACE("  File attr: %u\n", pfdin->attribs); */
324     fici.NameInCabinet = pfdin->psz1;
325     fici.FileSize = pfdin->cb;
326     fici.Win32Error = 0;
327     fici.DosDate = pfdin->date;
328     fici.DosTime = pfdin->time;
329     fici.DosAttribs = pfdin->attribs;
330     memset(&(fici.FullTargetName[0]), 0, MAX_PATH);
331     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
332                            (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
333     if (err == FILEOP_DOIT) {
334       TRACE("  Callback specified filename: %s\n", debugstr_a(&(fici.FullTargetName[0])));
335       if (!fici.FullTargetName[0]) {
336         WARN("  Empty return string causing abort.\n");
337         SetLastError(ERROR_PATH_NOT_FOUND);
338         return -1;
339       }
340       return sc_cb_open(&(fici.FullTargetName[0]), _O_BINARY | _O_CREAT | _O_WRONLY,  _S_IREAD | _S_IWRITE);
341     } else {
342       TRACE("  Callback skipped file.\n");
343       return 0;
344     }
345   case fdintCLOSE_FILE_INFO:
346     TRACE("Close file notification\n");
347     /* TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
348     TRACE("  Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
349     TRACE("  File hndl: %d\n", pfdin->hf); */
350     fp.Source = &(phsc->most_recent_cabinet_name[0]);
351     fp.Target = pfdin->psz1;
352     fp.Win32Error = 0;
353     fp.Flags = 0;
354     /* the following should be a fixme -- but it occurs too many times */
355     WARN("Should set file date/time/attribs (and execute files?)\n");
356     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
357     if (sc_cb_close(pfdin->hf))
358       WARN("_close failed.\n");
359     if (err) {
360       SetLastError(err);
361       return FALSE;
362     } else
363       return TRUE;
364   case fdintNEXT_CABINET:
365     TRACE("Next cabinet notification\n");
366     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
367     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
368     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
369     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
370     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
371     ci.CabinetFile = pfdin->psz1;
372     ci.CabinetPath = pfdin->psz3;
373     ci.DiskName = pfdin->psz2;
374     ci.SetId = pfdin->setID;
375     ci.CabinetNumber = pfdin->iCabinet;
376     /* remember the new cabinet name */
377     strcpy(&(phsc->most_recent_cabinet_name[0]), pfdin->psz1);
378     err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
379     if (err) {
380       SetLastError(err);
381       return -1;
382     } else {
383       if (mysterio[0]) {
384         /* some easy paranoia.  no such carefulness exists on the wide API IIRC */
385         lstrcpynA(pfdin->psz3, &(mysterio[0]), SIZEOF_MYSTERIO);
386       }
387       return 0;
388     }
389   default:
390     FIXME("Unknown notification type %d.\n", fdint);
391     return 0;
392   }
393 }
394
395 static INT_PTR CDECL sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
396 {
397   FILE_IN_CABINET_INFO_W fici;
398   PSC_HSC_W phsc;
399   CABINET_INFO_W ci;
400   FILEPATHS_W fp;
401   UINT err;
402   int len;
403
404   WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
405   WCHAR buf[MAX_PATH], buf2[MAX_PATH];
406   CHAR charbuf[MAX_PATH];
407
408   memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
409   memset(&(buf[0]), 0, MAX_PATH * sizeof(WCHAR));
410   memset(&(buf2[0]), 0, MAX_PATH * sizeof(WCHAR));
411   memset(&(charbuf[0]), 0, MAX_PATH);
412
413   TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
414
415   if (pfdin && pfdin->pv && (((PSC_HSC_W) pfdin->pv)->magic == SC_HSC_W_MAGIC))
416     phsc = pfdin->pv;
417   else {
418     ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
419     return -1;
420   }
421
422   switch (fdint) {
423   case fdintCABINET_INFO:
424     TRACE("Cabinet info notification\n");
425     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
426     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
427     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
428     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
429     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
430     WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
431     ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
432     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
433     if ((len > MAX_PATH) || (len <= 1))
434       buf[0] = '\0';
435     ci.CabinetPath = &(buf[0]);
436     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
437     if ((len > MAX_PATH) || (len <= 1))
438       buf2[0] = '\0';
439     ci.DiskName = &(buf2[0]);
440     ci.SetId = pfdin->setID;
441     ci.CabinetNumber = pfdin->iCabinet;
442     phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR)&ci, 0);
443     return 0;
444   case fdintPARTIAL_FILE:
445     TRACE("Partial file notification\n");
446     /* TRACE("  Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
447     return 0;
448   case fdintCOPY_FILE:
449     TRACE("Copy file notification\n");
450     TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
451     /* TRACE("  File size: %ld\n", pfdin->cb);
452     TRACE("  File date: %u\n", pfdin->date);
453     TRACE("  File time: %u\n", pfdin->time);
454     TRACE("  File attr: %u\n", pfdin->attribs); */
455     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf2[0]), MAX_PATH);
456     if ((len > MAX_PATH) || (len <= 1))
457       buf2[0] = '\0';
458     fici.NameInCabinet = &(buf2[0]);
459     fici.FileSize = pfdin->cb;
460     fici.Win32Error = 0;
461     fici.DosDate = pfdin->date;
462     fici.DosTime = pfdin->time;
463     fici.DosAttribs = pfdin->attribs;
464     memset(&(fici.FullTargetName[0]), 0, MAX_PATH * sizeof(WCHAR));
465     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
466                            (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
467     if (err == FILEOP_DOIT) {
468       TRACE("  Callback specified filename: %s\n", debugstr_w(&(fici.FullTargetName[0])));
469       if (fici.FullTargetName[0]) {
470         len = strlenW(&(fici.FullTargetName[0])) + 1;
471         if ((len > MAX_PATH ) || (len <= 1))
472           return 0;
473         if (!WideCharToMultiByte(CP_ACP, 0, &(fici.FullTargetName[0]), len, &(charbuf[0]), MAX_PATH, 0, 0))
474           return 0;
475       } else {
476         WARN("Empty buffer string caused abort.\n");
477         SetLastError(ERROR_PATH_NOT_FOUND);
478         return -1;
479       }
480       return sc_cb_open(&(charbuf[0]), _O_BINARY | _O_CREAT | _O_WRONLY,  _S_IREAD | _S_IWRITE);
481     } else {
482       TRACE("  Callback skipped file.\n");
483       return 0;
484     }
485   case fdintCLOSE_FILE_INFO:
486     TRACE("Close file notification\n");
487     /* TRACE("  File name: %s\n", debugstr_a(pfdin->psz1));
488     TRACE("  Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
489     TRACE("  File hndl: %d\n", pfdin->hf); */
490     fp.Source = &(phsc->most_recent_cabinet_name[0]);
491     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf[0]), MAX_PATH);
492     if ((len > MAX_PATH) || (len <= 1))
493       buf[0] = '\0';
494     fp.Target = &(buf[0]);
495     fp.Win32Error = 0;
496     fp.Flags = 0;
497     /* a valid fixme -- but occurs too many times */
498     /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
499     err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
500     if (sc_cb_close(pfdin->hf))
501       WARN("_close failed.\n");
502     if (err) {
503       SetLastError(err);
504       return FALSE;
505     } else
506       return TRUE;
507   case fdintNEXT_CABINET:
508     TRACE("Next cabinet notification\n");
509     /* TRACE("  Cabinet name: %s\n", debugstr_a(pfdin->psz1));
510     TRACE("  Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
511     TRACE("  Cabinet path: %s\n", debugstr_a(pfdin->psz3));
512     TRACE("  Cabinet Set#: %d\n", pfdin->setID);
513     TRACE("  Cabinet Cab#: %d\n", pfdin->iCabinet); */
514     /* remember the new cabinet name */
515     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(phsc->most_recent_cabinet_name[0]), MAX_PATH);
516     if ((len > MAX_PATH) || (len <= 1))
517       phsc->most_recent_cabinet_name[0] = '\0';
518     ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
519     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
520     if ((len > MAX_PATH) || (len <= 1))
521       buf[0] = '\0';
522     ci.CabinetPath = &(buf[0]);
523     len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
524     if ((len > MAX_PATH) || (len <= 1))
525       buf2[0] = '\0';
526     ci.DiskName = &(buf2[0]);
527     ci.SetId = pfdin->setID;
528     ci.CabinetNumber = pfdin->iCabinet;
529     err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
530     if (err) {
531       SetLastError(err);
532       return -1;
533     } else {
534       if (mysterio[0]) {
535         len = strlenW(&(mysterio[0])) + 1;
536         if ((len > 255) || (len <= 1))
537           return 0;
538         if (!WideCharToMultiByte(CP_ACP, 0, &(mysterio[0]), len, pfdin->psz3, 255, 0, 0))
539           return 0;
540       }
541       return 0;
542     }
543   default:
544     FIXME("Unknown notification type %d.\n", fdint);
545     return 0;
546   }
547 }
548
549 /***********************************************************************
550  *              SetupIterateCabinetA (SETUPAPI.@)
551  */
552 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
553                                  PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
554 {
555
556   SC_HSC_A my_hsc;
557   ERF erf;
558   CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p = NULL;
559   DWORD fpnsize;
560   BOOL ret;
561
562   TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
563         debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
564
565   if (!LoadCABINETDll())
566     return FALSE;
567
568   if (!CabinetFile)
569   {
570     SetLastError(ERROR_INVALID_PARAMETER);
571     return FALSE;
572   }
573
574   fpnsize = strlen(CabinetFile);
575   if (fpnsize >= MAX_PATH) {
576     SetLastError(ERROR_BAD_PATHNAME);
577     return FALSE;
578   }
579
580   fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p);
581   if (fpnsize > MAX_PATH) {
582     SetLastError(ERROR_BAD_PATHNAME);
583     return FALSE;
584   }
585
586   if (p) {
587     strcpy(pszCabinet, p);
588     *p = '\0';
589   } else {
590     strcpy(pszCabinet, CabinetFile);
591     pszCabPath[0] = '\0';
592   }
593
594   TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
595
596   /* remember the cabinet name */
597   strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet);
598
599   my_hsc.magic = SC_HSC_A_MAGIC;
600   my_hsc.msghandler = MsgHandler;
601   my_hsc.context = Context;
602   my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
603                            sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
604
605   if (!my_hsc.hfdi) return FALSE;
606
607   ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
608                      0, sc_FNNOTIFY_A, NULL, &my_hsc)     ) ? TRUE : FALSE;
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,
674                      0, sc_FNNOTIFY_W, NULL, &my_hsc)     ) ? TRUE : FALSE;
675
676   sc_FDIDestroy(my_hsc.hfdi);
677   return ret;
678 }
679
680
681 /***********************************************************************
682  * DllMain
683  *
684  * PARAMS
685  *     hinstDLL    [I] handle to the DLL's instance
686  *     fdwReason   [I]
687  *     lpvReserved [I] reserved, must be NULL
688  *
689  * RETURNS
690  *     Success: TRUE
691  *     Failure: FALSE
692  */
693
694 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
695 {
696     switch (fdwReason) {
697     case DLL_PROCESS_ATTACH:
698         DisableThreadLibraryCalls(hinstDLL);
699         OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
700         if (!GetVersionExW(&OsVersionInfo))
701             return FALSE;
702         SETUPAPI_hInstance = hinstDLL;
703         break;
704     case DLL_PROCESS_DETACH:
705         UnloadCABINETDll();
706         break;
707     }
708
709     return TRUE;
710 }