d3dxof: Small cleanup.
[wine/wine64.git] / dlls / setupapi / setupcab.c
blobf01c3d5b6cd054383bcc5f4a68d7d871eead18d5
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;
69 static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN,
70 PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF);
72 static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int,
73 PFNFDINOTIFY, PFNFDIDECRYPT, void *);
75 static BOOL (__cdecl *sc_FDIDestroy)(HFDI);
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;
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;
95 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
97 static BOOL LoadCABINETDll(void)
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;
110 } else
111 return TRUE;
114 static void UnloadCABINETDll(void)
116 if (CABINET_hInstance) {
117 FreeLibrary(CABINET_hInstance);
118 CABINET_hInstance = 0;
122 /* FDICreate callbacks */
124 static void *sc_cb_alloc(ULONG cb)
126 return HeapAlloc(GetProcessHeap(), 0, cb);
129 static void sc_cb_free(void *pv)
131 HeapFree(GetProcessHeap(), 0, pv);
134 static INT_PTR sc_cb_open(char *pszFile, int oflag, int pmode)
136 DWORD creation = 0, sharing = 0;
137 int ioflag = 0;
138 INT_PTR ret = 0;
139 SECURITY_ATTRIBUTES sa;
141 /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
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;
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;
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;
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);
194 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
195 sa.lpSecurityDescriptor = NULL;
196 sa.bInheritHandle = (ioflag & _O_NOINHERIT) ? FALSE : TRUE;
198 ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
200 /* TRACE("<-- %d\n", ret); */
202 return ret;
205 static UINT sc_cb_read(INT_PTR hf, void *pv, UINT cb)
207 DWORD num_read;
208 BOOL rslt;
210 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
212 rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
215 /* eof and failure both give "-1" return */
216 if ((! rslt) || ((cb > 0) && (num_read == 0))) {
217 /* TRACE("<-- -1\n"); */
218 return -1;
221 /* TRACE("<-- %lu\n", num_read); */
222 return num_read;
225 static UINT sc_cb_write(INT_PTR hf, void *pv, UINT cb)
227 DWORD num_written;
228 /* BOOL rv; */
230 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
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;
243 static int sc_cb_close(INT_PTR hf)
245 /* TRACE("(hf == %d)\n", hf); */
247 if (CloseHandle((HANDLE) hf))
248 return 0;
249 else
250 return -1;
253 static long sc_cb_lseek(INT_PTR hf, long dist, int seektype)
255 DWORD ret;
257 /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
259 if (seektype < 0 || seektype > 2)
260 return -1;
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;
271 #define SIZEOF_MYSTERIO (MAX_PATH*3)
273 /* FDICopy callbacks */
275 static INT_PTR sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
277 FILE_IN_CABINET_INFO_A fici;
278 PSC_HSC_A phsc;
279 CABINET_INFO_A ci;
280 FILEPATHS_A fp;
281 UINT err;
283 CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
285 memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO);
287 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
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;
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;
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;
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);
386 return 0;
388 default:
389 FIXME("Unknown notification type %d.\n", fdint);
390 return 0;
394 static INT_PTR sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
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;
403 WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
404 WCHAR buf[MAX_PATH], buf2[MAX_PATH];
405 CHAR charbuf[MAX_PATH];
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);
412 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
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;
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;
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;
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;
540 return 0;
542 default:
543 FIXME("Unknown notification type %d.\n", fdint);
544 return 0;
548 /***********************************************************************
549 * SetupIterateCabinetA (SETUPAPI.@)
551 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
552 PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
555 SC_HSC_A my_hsc;
556 ERF erf;
557 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p;
558 DWORD fpnsize;
559 BOOL ret;
562 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
563 debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
565 if (! LoadCABINETDll())
566 return FALSE;
568 memset(&my_hsc, 0, sizeof(SC_HSC_A));
569 pszCabinet[0] = '\0';
570 pszCabPath[0] = '\0';
572 fpnsize = strlen(CabinetFile);
573 if (fpnsize >= MAX_PATH) {
574 SetLastError(ERROR_BAD_PATHNAME);
575 return FALSE;
578 fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p);
579 if (fpnsize > MAX_PATH) {
580 SetLastError(ERROR_BAD_PATHNAME);
581 return FALSE;
584 if (p) {
585 strcpy(pszCabinet, p);
586 *p = '\0';
587 } else {
588 strcpy(pszCabinet, CabinetFile);
589 pszCabPath[0] = '\0';
592 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
594 /* remember the cabinet name */
595 strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet);
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 );
603 if (!my_hsc.hfdi) return FALSE;
605 ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
606 0, sc_FNNOTIFY_A, NULL, &my_hsc) ) ? TRUE : FALSE;
608 sc_FDIDestroy(my_hsc.hfdi);
609 return ret;
613 /***********************************************************************
614 * SetupIterateCabinetW (SETUPAPI.@)
616 BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
617 PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
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;
627 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
628 debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
630 if (!LoadCABINETDll())
631 return FALSE;
633 if (!CabinetFile) return FALSE;
635 memset(&my_hsc, 0, sizeof(SC_HSC_W));
637 fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p);
638 if (fpnsize > MAX_PATH) {
639 SetLastError(ERROR_BAD_PATHNAME);
640 return FALSE;
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';
654 len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1,
655 pszCabinet, MAX_PATH, 0, 0);
656 if (!len) return FALSE;
658 TRACE("path: %s, cabfile: %s\n",
659 debugstr_a(pszCabPath), debugstr_a(pszCabinet));
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 );
667 if (!my_hsc.hfdi) return FALSE;
669 ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
670 0, sc_FNNOTIFY_W, NULL, &my_hsc) ) ? TRUE : FALSE;
672 sc_FDIDestroy(my_hsc.hfdi);
673 return ret;
677 /***********************************************************************
678 * DllMain
680 * PARAMS
681 * hinstDLL [I] handle to the DLL's instance
682 * fdwReason [I]
683 * lpvReserved [I] reserved, must be NULL
685 * RETURNS
686 * Success: TRUE
687 * Failure: FALSE
690 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
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;
704 return TRUE;