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