Converted comcat.h to IDL.
[wine/multimedia.git] / dlls / setupapi / setupcab.c
blobf49e594f153918e32ad3e47c4076aeb566dab438
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Many useful traces are commented in code, uncomment them if you have
22 * trouble and run with --debugmsg +setupapi
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"
33 #include "msvcrt/fcntl.h"
34 #include "msvcrt/share.h"
36 #include "wine/debug.h"
38 static HINSTANCE CABINET_hInstance = 0;
40 static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN,
41 PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF);
43 static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int,
44 PFNFDINOTIFY, PFNFDIDECRYPT, void *);
46 static BOOL (__cdecl *sc_FDIDestroy)(HFDI);
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;
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;
66 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
68 static BOOL LoadCABINETDll(void)
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;
81 } else
82 return TRUE;
85 static void UnloadCABINETDll(void)
87 if (CABINET_hInstance) {
88 FreeLibrary(CABINET_hInstance);
89 CABINET_hInstance = 0;
93 /* FDICreate callbacks */
95 static void *sc_cb_alloc(ULONG cb)
97 return malloc(cb);
100 static void sc_cb_free(void *pv)
102 free(pv);
105 static INT_PTR sc_cb_open(char *pszFile, int oflag, int pmode)
107 DWORD creation = 0, sharing = 0;
108 int ioflag = 0;
109 INT_PTR ret = 0;
110 SECURITY_ATTRIBUTES sa;
112 /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
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;
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;
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;
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);
165 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
166 sa.lpSecurityDescriptor = NULL;
167 sa.bInheritHandle = (ioflag & _O_NOINHERIT) ? FALSE : TRUE;
169 ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
171 /* TRACE("<-- %d\n", ret); */
173 return ret;
176 static UINT sc_cb_read(INT_PTR hf, void *pv, UINT cb)
178 DWORD num_read;
179 BOOL rslt;
181 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
183 rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
186 /* eof and failure both give "-1" return */
187 if ((! rslt) || ((cb > 0) && (num_read == 0))) {
188 /* TRACE("<-- -1\n"); */
189 return -1;
192 /* TRACE("<-- %lu\n", num_read); */
193 return num_read;
196 static UINT sc_cb_write(INT_PTR hf, void *pv, UINT cb)
198 DWORD num_written;
199 /* BOOL rv; */
201 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
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;
214 static int sc_cb_close(INT_PTR hf)
216 /* TRACE("(hf == %d)\n", hf); */
218 if (CloseHandle((HANDLE) hf))
219 return 0;
220 else
221 return -1;
224 static long sc_cb_lseek(INT_PTR hf, long dist, int seektype)
226 DWORD ret;
228 /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
230 if (seektype < 0 || seektype > 2)
231 return -1;
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;
242 #define SIZEOF_MYSTERIO (MAX_PATH*3)
244 /* FDICopy callbacks */
246 static INT_PTR sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
248 FILE_IN_CABINET_INFOA fici;
249 PSC_HSC_A phsc;
250 CABINET_INFOA ci;
251 FILEPATHS_A fp;
252 UINT err;
254 CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
256 memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO);
258 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
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;
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;
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;
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';
359 return 0;
361 default:
362 FIXME("Unknown notification type %d.\n", fdint);
363 return 0;
367 static INT_PTR sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
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;
376 WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
377 WCHAR buf[MAX_PATH], buf2[MAX_PATH];
378 CHAR charbuf[MAX_PATH];
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);
385 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
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;
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;
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;
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;
513 return 0;
515 default:
516 FIXME("Unknown notification type %d.\n", fdint);
517 return 0;
521 /***********************************************************************
522 * SetupIterateCabinetA (SETUPAPI.@)
524 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
525 PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
528 SC_HSC_A my_hsc;
529 ERF erf;
530 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p;
531 DWORD fpnsize;
532 BOOL ret;
535 TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n",
536 debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
538 if (! LoadCABINETDll())
539 return FALSE;
541 memset(&my_hsc, 0, sizeof(SC_HSC_A));
542 pszCabinet[0] = '\0';
543 pszCabPath[0] = '\0';
545 fpnsize = strlen(CabinetFile);
546 if (fpnsize >= MAX_PATH) {
547 SetLastError(ERROR_BAD_PATHNAME);
548 return FALSE;
551 fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p);
552 if (fpnsize > MAX_PATH) {
553 SetLastError(ERROR_BAD_PATHNAME);
554 return FALSE;
557 if (p) {
558 strcpy(pszCabinet, p);
559 *p = '\0';
560 } else {
561 strcpy(pszCabinet, CabinetFile);
562 pszCabPath[0] = '\0';
565 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
567 /* remember the cabinet name */
568 strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet);
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 );
576 if (!my_hsc.hfdi) return FALSE;
578 ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
579 0, sc_FNNOTIFY_A, NULL, &my_hsc) ) ? TRUE : FALSE;
581 sc_FDIDestroy(my_hsc.hfdi);
582 return ret;
585 /***********************************************************************
586 * SetupIterateCabinetW (SETUPAPI.@)
588 BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
589 PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
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;
599 TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n",
600 debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
602 if (!LoadCABINETDll())
603 return FALSE;
605 if (!CabinetFile) return FALSE;
606 if (!WideCharToMultiByte(CP_ACP, 0, CabinetFile, -1, CabinetFile_A, MAX_PATH, 0, 0))
607 return FALSE;
609 memset(&my_hsc, 0, sizeof(SC_HSC_W));
610 pszCabinet[0] = '\0';
611 pszCabPath[0] = '\0';
613 fpnsize = GetFullPathNameA(CabinetFile_A, MAX_PATH, &(pszCabPath[0]), &p);
614 if (fpnsize > MAX_PATH) {
615 SetLastError(ERROR_BAD_PATHNAME);
616 return FALSE;
619 if (p) {
620 strcpy(pszCabinet, p);
621 *p = '\0';
622 } else {
623 strcpy(pszCabinet, CabinetFile_A);
624 pszCabPath[0] = '\0';
627 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
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 );
642 if (!my_hsc.hfdi) return FALSE;
644 ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
645 0, sc_FNNOTIFY_W, NULL, &my_hsc) ) ? TRUE : FALSE;
647 sc_FDIDestroy(my_hsc.hfdi);
648 return ret;
652 /***********************************************************************
653 * DllMain
655 * PARAMS
656 * hinstDLL [I] handle to the DLL's instance
657 * fdwReason [I]
658 * lpvReserved [I] reserved, must be NULL
660 * RETURNS
661 * Success: TRUE
662 * Failure: FALSE
665 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
667 switch (fdwReason) {
668 case DLL_PROCESS_ATTACH:
669 DisableThreadLibraryCalls(hinstDLL);
670 break;
671 case DLL_PROCESS_DETACH:
672 UnloadCABINETDll();
673 break;
676 return TRUE;