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