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