Release 1.5.27.
[wine.git] / dlls / setupapi / setupcab.c
blob8fcd9891b213ccca845458ad55e21c9c68274d80
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 static void UnloadCABINETDll(void)
119 if (CABINET_hInstance) {
120 FreeLibrary(CABINET_hInstance);
121 CABINET_hInstance = 0;
125 /* FDICreate callbacks */
127 static void * CDECL sc_cb_alloc(ULONG cb)
129 return HeapAlloc(GetProcessHeap(), 0, cb);
132 static void CDECL sc_cb_free(void *pv)
134 HeapFree(GetProcessHeap(), 0, pv);
137 static INT_PTR CDECL sc_cb_open(char *pszFile, int oflag, int pmode)
139 DWORD creation = 0, sharing = 0;
140 int ioflag = 0;
141 INT_PTR ret = 0;
142 SECURITY_ATTRIBUTES sa;
144 /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
146 switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
147 case _O_RDONLY:
148 ioflag |= GENERIC_READ;
149 break;
150 case _O_WRONLY:
151 ioflag |= GENERIC_WRITE;
152 break;
153 case _O_RDWR:
154 ioflag |= GENERIC_READ | GENERIC_WRITE;
155 break;
156 case _O_WRONLY | _O_RDWR: /* hmmm.. */
157 ERR("_O_WRONLY & _O_RDWR in oflag?\n");
158 return -1;
161 if (oflag & _O_CREAT) {
162 if (oflag & _O_EXCL)
163 creation = CREATE_NEW;
164 else if (oflag & _O_TRUNC)
165 creation = CREATE_ALWAYS;
166 else
167 creation = OPEN_ALWAYS;
168 } else /* no _O_CREAT */ {
169 if (oflag & _O_TRUNC)
170 creation = TRUNCATE_EXISTING;
171 else
172 creation = OPEN_EXISTING;
175 switch( pmode & 0x70 ) {
176 case _SH_DENYRW:
177 sharing = 0L;
178 break;
179 case _SH_DENYWR:
180 sharing = FILE_SHARE_READ;
181 break;
182 case _SH_DENYRD:
183 sharing = FILE_SHARE_WRITE;
184 break;
185 case _SH_COMPAT:
186 case _SH_DENYNO:
187 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
188 break;
189 default:
190 ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode);
191 return -1;
194 if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT))
195 WARN("unsupported oflag 0x%04x\n",oflag);
197 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
198 sa.lpSecurityDescriptor = NULL;
199 sa.bInheritHandle = !(ioflag & _O_NOINHERIT);
201 ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
203 /* TRACE("<-- %d\n", ret); */
205 return ret;
208 static UINT CDECL sc_cb_read(INT_PTR hf, void *pv, UINT cb)
210 DWORD num_read;
211 BOOL rslt;
213 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
215 rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
218 /* eof and failure both give "-1" return */
219 if ((! rslt) || ((cb > 0) && (num_read == 0))) {
220 /* TRACE("<-- -1\n"); */
221 return -1;
224 /* TRACE("<-- %lu\n", num_read); */
225 return num_read;
228 static UINT CDECL sc_cb_write(INT_PTR hf, void *pv, UINT cb)
230 DWORD num_written;
231 /* BOOL rv; */
233 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
235 if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */
236 && (num_written == cb)) {
237 /* TRACE("<-- %lu\n", num_written); */
238 return num_written;
239 } else {
240 /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
241 /* TRACE("<-- -1\n"); */
242 return -1;
246 static int CDECL sc_cb_close(INT_PTR hf)
248 /* TRACE("(hf == %d)\n", hf); */
250 if (CloseHandle((HANDLE) hf))
251 return 0;
252 else
253 return -1;
256 static LONG CDECL sc_cb_lseek(INT_PTR hf, LONG dist, int seektype)
258 DWORD ret;
260 /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
262 if (seektype < 0 || seektype > 2)
263 return -1;
265 if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) {
266 /* TRACE("<-- %lu\n", ret); */
267 return ret;
268 } else {
269 /* TRACE("<-- -1\n"); */
270 return -1;
274 #define SIZEOF_MYSTERIO (MAX_PATH*3)
276 /* FDICopy callbacks */
278 static INT_PTR CDECL sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
280 FILE_IN_CABINET_INFO_A fici;
281 PSC_HSC_A phsc;
282 CABINET_INFO_A ci;
283 FILEPATHS_A fp;
284 UINT err;
286 CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
288 memset(mysterio, 0, SIZEOF_MYSTERIO);
290 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
292 if (pfdin && pfdin->pv && (((PSC_HSC_A) pfdin->pv)->magic == SC_HSC_A_MAGIC))
293 phsc = pfdin->pv;
294 else {
295 ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL);
296 return -1;
299 switch (fdint) {
300 case fdintCABINET_INFO:
301 TRACE("Cabinet info notification\n");
302 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
303 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
304 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
305 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
306 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
307 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
308 ci.CabinetFile = phsc->most_recent_cabinet_name;
309 ci.CabinetPath = pfdin->psz3;
310 ci.DiskName = pfdin->psz2;
311 ci.SetId = pfdin->setID;
312 ci.CabinetNumber = pfdin->iCabinet;
313 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR) &ci, 0);
314 return 0;
315 case fdintPARTIAL_FILE:
316 TRACE("Partial file notification\n");
317 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
318 return 0;
319 case fdintCOPY_FILE:
320 TRACE("Copy file notification\n");
321 TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
322 /* TRACE(" File size: %ld\n", pfdin->cb);
323 TRACE(" File date: %u\n", pfdin->date);
324 TRACE(" File time: %u\n", pfdin->time);
325 TRACE(" File attr: %u\n", pfdin->attribs); */
326 fici.NameInCabinet = pfdin->psz1;
327 fici.FileSize = pfdin->cb;
328 fici.Win32Error = 0;
329 fici.DosDate = pfdin->date;
330 fici.DosTime = pfdin->time;
331 fici.DosAttribs = pfdin->attribs;
332 memset(fici.FullTargetName, 0, MAX_PATH);
333 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
334 (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
335 if (err == FILEOP_DOIT) {
336 TRACE(" Callback specified filename: %s\n", debugstr_a(fici.FullTargetName));
337 if (!fici.FullTargetName[0]) {
338 WARN(" Empty return string causing abort.\n");
339 SetLastError(ERROR_PATH_NOT_FOUND);
340 return -1;
342 strcpy( phsc->most_recent_target, fici.FullTargetName );
343 return sc_cb_open(fici.FullTargetName, _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
344 } else {
345 TRACE(" Callback skipped file.\n");
346 return 0;
348 case fdintCLOSE_FILE_INFO:
349 TRACE("Close file notification\n");
350 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
351 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
352 TRACE(" File hndl: %d\n", pfdin->hf); */
353 fp.Source = phsc->most_recent_cabinet_name;
354 fp.Target = phsc->most_recent_target;
355 fp.Win32Error = 0;
356 fp.Flags = 0;
357 /* the following should be a fixme -- but it occurs too many times */
358 WARN("Should set file date/time/attribs (and execute files?)\n");
359 if (sc_cb_close(pfdin->hf))
360 WARN("_close failed.\n");
361 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
362 if (err) {
363 SetLastError(err);
364 return FALSE;
365 } else
366 return TRUE;
367 case fdintNEXT_CABINET:
368 TRACE("Next cabinet notification\n");
369 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
370 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
371 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
372 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
373 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
374 ci.CabinetFile = pfdin->psz1;
375 ci.CabinetPath = pfdin->psz3;
376 ci.DiskName = pfdin->psz2;
377 ci.SetId = pfdin->setID;
378 ci.CabinetNumber = pfdin->iCabinet;
379 /* remember the new cabinet name */
380 strcpy(phsc->most_recent_cabinet_name, pfdin->psz1);
381 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
382 if (err) {
383 SetLastError(err);
384 return -1;
385 } else {
386 if (mysterio[0]) {
387 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
388 lstrcpynA(pfdin->psz3, mysterio, SIZEOF_MYSTERIO);
390 return 0;
392 default:
393 FIXME("Unknown notification type %d.\n", fdint);
394 return 0;
398 static INT_PTR CDECL sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
400 FILE_IN_CABINET_INFO_W fici;
401 PSC_HSC_W phsc;
402 CABINET_INFO_W ci;
403 FILEPATHS_W fp;
404 UINT err;
405 int len;
407 WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
408 WCHAR buf[MAX_PATH], buf2[MAX_PATH];
409 CHAR charbuf[MAX_PATH];
411 memset(mysterio, 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
412 memset(buf, 0, MAX_PATH * sizeof(WCHAR));
413 memset(buf2, 0, MAX_PATH * sizeof(WCHAR));
414 memset(charbuf, 0, MAX_PATH);
416 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
418 if (pfdin && pfdin->pv && (((PSC_HSC_W) pfdin->pv)->magic == SC_HSC_W_MAGIC))
419 phsc = pfdin->pv;
420 else {
421 ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
422 return -1;
425 switch (fdint) {
426 case fdintCABINET_INFO:
427 TRACE("Cabinet info notification\n");
428 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
429 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
430 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
431 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
432 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
433 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
434 ci.CabinetFile = phsc->most_recent_cabinet_name;
435 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
436 if ((len > MAX_PATH) || (len <= 1))
437 buf[0] = '\0';
438 ci.CabinetPath = buf;
439 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
440 if ((len > MAX_PATH) || (len <= 1))
441 buf2[0] = '\0';
442 ci.DiskName = buf2;
443 ci.SetId = pfdin->setID;
444 ci.CabinetNumber = pfdin->iCabinet;
445 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR)&ci, 0);
446 return 0;
447 case fdintPARTIAL_FILE:
448 TRACE("Partial file notification\n");
449 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
450 return 0;
451 case fdintCOPY_FILE:
452 TRACE("Copy file notification\n");
453 TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
454 /* TRACE(" File size: %ld\n", pfdin->cb);
455 TRACE(" File date: %u\n", pfdin->date);
456 TRACE(" File time: %u\n", pfdin->time);
457 TRACE(" File attr: %u\n", pfdin->attribs); */
458 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, buf2, MAX_PATH);
459 if ((len > MAX_PATH) || (len <= 1))
460 buf2[0] = '\0';
461 fici.NameInCabinet = buf2;
462 fici.FileSize = pfdin->cb;
463 fici.Win32Error = 0;
464 fici.DosDate = pfdin->date;
465 fici.DosTime = pfdin->time;
466 fici.DosAttribs = pfdin->attribs;
467 memset(fici.FullTargetName, 0, MAX_PATH * sizeof(WCHAR));
468 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
469 (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
470 if (err == FILEOP_DOIT) {
471 TRACE(" Callback specified filename: %s\n", debugstr_w(fici.FullTargetName));
472 if (fici.FullTargetName[0]) {
473 len = strlenW(fici.FullTargetName) + 1;
474 if ((len > MAX_PATH ) || (len <= 1))
475 return 0;
476 if (!WideCharToMultiByte(CP_ACP, 0, fici.FullTargetName, len, charbuf, MAX_PATH, 0, 0))
477 return 0;
478 } else {
479 WARN("Empty buffer string caused abort.\n");
480 SetLastError(ERROR_PATH_NOT_FOUND);
481 return -1;
483 strcpyW( phsc->most_recent_target, fici.FullTargetName );
484 return sc_cb_open(charbuf, _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
485 } else {
486 TRACE(" Callback skipped file.\n");
487 return 0;
489 case fdintCLOSE_FILE_INFO:
490 TRACE("Close file notification\n");
491 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
492 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
493 TRACE(" File hndl: %d\n", pfdin->hf); */
494 fp.Source = phsc->most_recent_cabinet_name;
495 fp.Target = phsc->most_recent_target;
496 fp.Win32Error = 0;
497 fp.Flags = 0;
498 /* a valid fixme -- but occurs too many times */
499 /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
500 if (sc_cb_close(pfdin->hf))
501 WARN("_close failed.\n");
502 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
503 if (err) {
504 SetLastError(err);
505 return FALSE;
506 } else
507 return TRUE;
508 case fdintNEXT_CABINET:
509 TRACE("Next cabinet notification\n");
510 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
511 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
512 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
513 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
514 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
515 /* remember the new cabinet name */
516 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, phsc->most_recent_cabinet_name, MAX_PATH);
517 if ((len > MAX_PATH) || (len <= 1))
518 phsc->most_recent_cabinet_name[0] = '\0';
519 ci.CabinetFile = phsc->most_recent_cabinet_name;
520 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
521 if ((len > MAX_PATH) || (len <= 1))
522 buf[0] = '\0';
523 ci.CabinetPath = buf;
524 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
525 if ((len > MAX_PATH) || (len <= 1))
526 buf2[0] = '\0';
527 ci.DiskName = buf2;
528 ci.SetId = pfdin->setID;
529 ci.CabinetNumber = pfdin->iCabinet;
530 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
531 if (err) {
532 SetLastError(err);
533 return -1;
534 } else {
535 if (mysterio[0]) {
536 len = strlenW(mysterio) + 1;
537 if ((len > 255) || (len <= 1))
538 return 0;
539 if (!WideCharToMultiByte(CP_ACP, 0, mysterio, len, pfdin->psz3, 255, 0, 0))
540 return 0;
542 return 0;
544 default:
545 FIXME("Unknown notification type %d.\n", fdint);
546 return 0;
550 /***********************************************************************
551 * SetupIterateCabinetA (SETUPAPI.@)
553 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
554 PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
557 SC_HSC_A my_hsc;
558 ERF erf;
559 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p = NULL;
560 DWORD fpnsize;
561 BOOL ret;
563 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
564 debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
566 if (!LoadCABINETDll())
567 return FALSE;
569 if (!CabinetFile)
571 SetLastError(ERROR_INVALID_PARAMETER);
572 return FALSE;
575 fpnsize = strlen(CabinetFile);
576 if (fpnsize >= MAX_PATH) {
577 SetLastError(ERROR_BAD_PATHNAME);
578 return FALSE;
581 fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, pszCabPath, &p);
582 if (fpnsize > MAX_PATH) {
583 SetLastError(ERROR_BAD_PATHNAME);
584 return FALSE;
587 if (p) {
588 strcpy(pszCabinet, p);
589 *p = '\0';
590 } else {
591 strcpy(pszCabinet, CabinetFile);
592 pszCabPath[0] = '\0';
595 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
597 /* remember the cabinet name */
598 strcpy(my_hsc.most_recent_cabinet_name, pszCabinet);
600 my_hsc.magic = SC_HSC_A_MAGIC;
601 my_hsc.msghandler = MsgHandler;
602 my_hsc.context = Context;
603 my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
604 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
606 if (!my_hsc.hfdi) return FALSE;
608 ret = sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_A, NULL, &my_hsc);
610 sc_FDIDestroy(my_hsc.hfdi);
611 return ret;
615 /***********************************************************************
616 * SetupIterateCabinetW (SETUPAPI.@)
618 BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
619 PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
621 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH];
622 UINT len;
623 SC_HSC_W my_hsc;
624 ERF erf;
625 WCHAR pszCabPathW[MAX_PATH], *p = NULL;
626 DWORD fpnsize;
627 BOOL ret;
629 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
630 debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
632 if (!LoadCABINETDll())
633 return FALSE;
635 if (!CabinetFile)
637 SetLastError(ERROR_INVALID_PARAMETER);
638 return FALSE;
641 fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p);
642 if (fpnsize > MAX_PATH) {
643 SetLastError(ERROR_BAD_PATHNAME);
644 return FALSE;
647 if (p) {
648 strcpyW(my_hsc.most_recent_cabinet_name, p);
649 *p = 0;
650 len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath,
651 MAX_PATH, 0, 0);
652 if (!len) return FALSE;
653 } else {
654 strcpyW(my_hsc.most_recent_cabinet_name, CabinetFile);
655 pszCabPath[0] = '\0';
658 len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1,
659 pszCabinet, MAX_PATH, 0, 0);
660 if (!len) return FALSE;
662 TRACE("path: %s, cabfile: %s\n",
663 debugstr_a(pszCabPath), debugstr_a(pszCabinet));
665 my_hsc.magic = SC_HSC_W_MAGIC;
666 my_hsc.msghandler = MsgHandler;
667 my_hsc.context = Context;
668 my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
669 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
671 if (!my_hsc.hfdi) return FALSE;
673 ret = sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_W, NULL, &my_hsc);
675 sc_FDIDestroy(my_hsc.hfdi);
676 return ret;
680 /***********************************************************************
681 * DllMain
683 * PARAMS
684 * hinstDLL [I] handle to the DLL's instance
685 * fdwReason [I]
686 * lpvReserved [I] reserved, must be NULL
688 * RETURNS
689 * Success: TRUE
690 * Failure: FALSE
693 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
695 switch (fdwReason) {
696 case DLL_PROCESS_ATTACH:
697 DisableThreadLibraryCalls(hinstDLL);
698 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
699 if (!GetVersionExW(&OsVersionInfo))
700 return FALSE;
701 SETUPAPI_hInstance = hinstDLL;
702 break;
703 case DLL_PROCESS_DETACH:
704 UnloadCABINETDll();
705 break;
708 return TRUE;