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