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