user32: Always use the default alignment when displaying submenu popups.
[wine/multimedia.git] / dlls / setupapi / setupcab.c
blob66cf7925acae69de22ffb047b798b3366593cde6
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 } SC_HSC_A, *PSC_HSC_A;
87 #define SC_HSC_W_MAGIC 0x0CABFEED
88 typedef struct {
89 UINT magic;
90 HFDI hfdi;
91 PSP_FILE_CALLBACK_W msghandler;
92 PVOID context;
93 WCHAR most_recent_cabinet_name[MAX_PATH];
94 } SC_HSC_W, *PSC_HSC_W;
96 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
98 static BOOL LoadCABINETDll(void)
100 if (!CABINET_hInstance) {
101 CABINET_hInstance = LoadLibraryA("cabinet.dll");
102 if (CABINET_hInstance) {
103 sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate");
104 sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy");
105 sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy");
106 return TRUE;
107 } else {
108 ERR("load cabinet dll failed.\n");
109 return FALSE;
111 } else
112 return TRUE;
115 static void UnloadCABINETDll(void)
117 if (CABINET_hInstance) {
118 FreeLibrary(CABINET_hInstance);
119 CABINET_hInstance = 0;
123 /* FDICreate callbacks */
125 static void * CDECL sc_cb_alloc(ULONG cb)
127 return HeapAlloc(GetProcessHeap(), 0, cb);
130 static void CDECL sc_cb_free(void *pv)
132 HeapFree(GetProcessHeap(), 0, pv);
135 static INT_PTR CDECL sc_cb_open(char *pszFile, int oflag, int pmode)
137 DWORD creation = 0, sharing = 0;
138 int ioflag = 0;
139 INT_PTR ret = 0;
140 SECURITY_ATTRIBUTES sa;
142 /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
144 switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
145 case _O_RDONLY:
146 ioflag |= GENERIC_READ;
147 break;
148 case _O_WRONLY:
149 ioflag |= GENERIC_WRITE;
150 break;
151 case _O_RDWR:
152 ioflag |= GENERIC_READ | GENERIC_WRITE;
153 break;
154 case _O_WRONLY | _O_RDWR: /* hmmm.. */
155 ERR("_O_WRONLY & _O_RDWR in oflag?\n");
156 return -1;
159 if (oflag & _O_CREAT) {
160 if (oflag & _O_EXCL)
161 creation = CREATE_NEW;
162 else if (oflag & _O_TRUNC)
163 creation = CREATE_ALWAYS;
164 else
165 creation = OPEN_ALWAYS;
166 } else /* no _O_CREAT */ {
167 if (oflag & _O_TRUNC)
168 creation = TRUNCATE_EXISTING;
169 else
170 creation = OPEN_EXISTING;
173 switch( pmode & 0x70 ) {
174 case _SH_DENYRW:
175 sharing = 0L;
176 break;
177 case _SH_DENYWR:
178 sharing = FILE_SHARE_READ;
179 break;
180 case _SH_DENYRD:
181 sharing = FILE_SHARE_WRITE;
182 break;
183 case _SH_COMPAT:
184 case _SH_DENYNO:
185 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
186 break;
187 default:
188 ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode);
189 return -1;
192 if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT))
193 WARN("unsupported oflag 0x%04x\n",oflag);
195 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
196 sa.lpSecurityDescriptor = NULL;
197 sa.bInheritHandle = (ioflag & _O_NOINHERIT) ? FALSE : TRUE;
199 ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
201 /* TRACE("<-- %d\n", ret); */
203 return ret;
206 static UINT CDECL sc_cb_read(INT_PTR hf, void *pv, UINT cb)
208 DWORD num_read;
209 BOOL rslt;
211 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
213 rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
216 /* eof and failure both give "-1" return */
217 if ((! rslt) || ((cb > 0) && (num_read == 0))) {
218 /* TRACE("<-- -1\n"); */
219 return -1;
222 /* TRACE("<-- %lu\n", num_read); */
223 return num_read;
226 static UINT CDECL sc_cb_write(INT_PTR hf, void *pv, UINT cb)
228 DWORD num_written;
229 /* BOOL rv; */
231 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
233 if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */
234 && (num_written == cb)) {
235 /* TRACE("<-- %lu\n", num_written); */
236 return num_written;
237 } else {
238 /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
239 /* TRACE("<-- -1\n"); */
240 return -1;
244 static int CDECL sc_cb_close(INT_PTR hf)
246 /* TRACE("(hf == %d)\n", hf); */
248 if (CloseHandle((HANDLE) hf))
249 return 0;
250 else
251 return -1;
254 static LONG CDECL sc_cb_lseek(INT_PTR hf, LONG dist, int seektype)
256 DWORD ret;
258 /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
260 if (seektype < 0 || seektype > 2)
261 return -1;
263 if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) {
264 /* TRACE("<-- %lu\n", ret); */
265 return ret;
266 } else {
267 /* TRACE("<-- -1\n"); */
268 return -1;
272 #define SIZEOF_MYSTERIO (MAX_PATH*3)
274 /* FDICopy callbacks */
276 static INT_PTR CDECL sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
278 FILE_IN_CABINET_INFO_A fici;
279 PSC_HSC_A phsc;
280 CABINET_INFO_A ci;
281 FILEPATHS_A fp;
282 UINT err;
284 CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
286 memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO);
288 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
290 if (pfdin && pfdin->pv && (((PSC_HSC_A) pfdin->pv)->magic == SC_HSC_A_MAGIC))
291 phsc = pfdin->pv;
292 else {
293 ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL);
294 return -1;
297 switch (fdint) {
298 case fdintCABINET_INFO:
299 TRACE("Cabinet info notification\n");
300 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
301 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
302 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
303 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
304 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
305 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
306 ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
307 ci.CabinetPath = pfdin->psz3;
308 ci.DiskName = pfdin->psz2;
309 ci.SetId = pfdin->setID;
310 ci.CabinetNumber = pfdin->iCabinet;
311 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR) &ci, 0);
312 return 0;
313 case fdintPARTIAL_FILE:
314 TRACE("Partial file notification\n");
315 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
316 return 0;
317 case fdintCOPY_FILE:
318 TRACE("Copy file notification\n");
319 TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
320 /* TRACE(" File size: %ld\n", pfdin->cb);
321 TRACE(" File date: %u\n", pfdin->date);
322 TRACE(" File time: %u\n", pfdin->time);
323 TRACE(" File attr: %u\n", pfdin->attribs); */
324 fici.NameInCabinet = pfdin->psz1;
325 fici.FileSize = pfdin->cb;
326 fici.Win32Error = 0;
327 fici.DosDate = pfdin->date;
328 fici.DosTime = pfdin->time;
329 fici.DosAttribs = pfdin->attribs;
330 memset(&(fici.FullTargetName[0]), 0, MAX_PATH);
331 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
332 (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
333 if (err == FILEOP_DOIT) {
334 TRACE(" Callback specified filename: %s\n", debugstr_a(&(fici.FullTargetName[0])));
335 if (!fici.FullTargetName[0]) {
336 WARN(" Empty return string causing abort.\n");
337 SetLastError(ERROR_PATH_NOT_FOUND);
338 return -1;
340 return sc_cb_open(&(fici.FullTargetName[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
341 } else {
342 TRACE(" Callback skipped file.\n");
343 return 0;
345 case fdintCLOSE_FILE_INFO:
346 TRACE("Close file notification\n");
347 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
348 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
349 TRACE(" File hndl: %d\n", pfdin->hf); */
350 fp.Source = &(phsc->most_recent_cabinet_name[0]);
351 fp.Target = pfdin->psz1;
352 fp.Win32Error = 0;
353 fp.Flags = 0;
354 /* the following should be a fixme -- but it occurs too many times */
355 WARN("Should set file date/time/attribs (and execute files?)\n");
356 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
357 if (sc_cb_close(pfdin->hf))
358 WARN("_close failed.\n");
359 if (err) {
360 SetLastError(err);
361 return FALSE;
362 } else
363 return TRUE;
364 case fdintNEXT_CABINET:
365 TRACE("Next cabinet notification\n");
366 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
367 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
368 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
369 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
370 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
371 ci.CabinetFile = pfdin->psz1;
372 ci.CabinetPath = pfdin->psz3;
373 ci.DiskName = pfdin->psz2;
374 ci.SetId = pfdin->setID;
375 ci.CabinetNumber = pfdin->iCabinet;
376 /* remember the new cabinet name */
377 strcpy(&(phsc->most_recent_cabinet_name[0]), pfdin->psz1);
378 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
379 if (err) {
380 SetLastError(err);
381 return -1;
382 } else {
383 if (mysterio[0]) {
384 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
385 lstrcpynA(pfdin->psz3, &(mysterio[0]), SIZEOF_MYSTERIO);
387 return 0;
389 default:
390 FIXME("Unknown notification type %d.\n", fdint);
391 return 0;
395 static INT_PTR CDECL sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
397 FILE_IN_CABINET_INFO_W fici;
398 PSC_HSC_W phsc;
399 CABINET_INFO_W ci;
400 FILEPATHS_W fp;
401 UINT err;
402 int len;
404 WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
405 WCHAR buf[MAX_PATH], buf2[MAX_PATH];
406 CHAR charbuf[MAX_PATH];
408 memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
409 memset(&(buf[0]), 0, MAX_PATH * sizeof(WCHAR));
410 memset(&(buf2[0]), 0, MAX_PATH * sizeof(WCHAR));
411 memset(&(charbuf[0]), 0, MAX_PATH);
413 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
415 if (pfdin && pfdin->pv && (((PSC_HSC_W) pfdin->pv)->magic == SC_HSC_W_MAGIC))
416 phsc = pfdin->pv;
417 else {
418 ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
419 return -1;
422 switch (fdint) {
423 case fdintCABINET_INFO:
424 TRACE("Cabinet info notification\n");
425 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
426 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
427 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
428 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
429 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
430 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
431 ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
432 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
433 if ((len > MAX_PATH) || (len <= 1))
434 buf[0] = '\0';
435 ci.CabinetPath = &(buf[0]);
436 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
437 if ((len > MAX_PATH) || (len <= 1))
438 buf2[0] = '\0';
439 ci.DiskName = &(buf2[0]);
440 ci.SetId = pfdin->setID;
441 ci.CabinetNumber = pfdin->iCabinet;
442 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT_PTR)&ci, 0);
443 return 0;
444 case fdintPARTIAL_FILE:
445 TRACE("Partial file notification\n");
446 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
447 return 0;
448 case fdintCOPY_FILE:
449 TRACE("Copy file notification\n");
450 TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
451 /* TRACE(" File size: %ld\n", pfdin->cb);
452 TRACE(" File date: %u\n", pfdin->date);
453 TRACE(" File time: %u\n", pfdin->time);
454 TRACE(" File attr: %u\n", pfdin->attribs); */
455 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf2[0]), MAX_PATH);
456 if ((len > MAX_PATH) || (len <= 1))
457 buf2[0] = '\0';
458 fici.NameInCabinet = &(buf2[0]);
459 fici.FileSize = pfdin->cb;
460 fici.Win32Error = 0;
461 fici.DosDate = pfdin->date;
462 fici.DosTime = pfdin->time;
463 fici.DosAttribs = pfdin->attribs;
464 memset(&(fici.FullTargetName[0]), 0, MAX_PATH * sizeof(WCHAR));
465 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
466 (UINT_PTR)&fici, (UINT_PTR)pfdin->psz1);
467 if (err == FILEOP_DOIT) {
468 TRACE(" Callback specified filename: %s\n", debugstr_w(&(fici.FullTargetName[0])));
469 if (fici.FullTargetName[0]) {
470 len = strlenW(&(fici.FullTargetName[0])) + 1;
471 if ((len > MAX_PATH ) || (len <= 1))
472 return 0;
473 if (!WideCharToMultiByte(CP_ACP, 0, &(fici.FullTargetName[0]), len, &(charbuf[0]), MAX_PATH, 0, 0))
474 return 0;
475 } else {
476 WARN("Empty buffer string caused abort.\n");
477 SetLastError(ERROR_PATH_NOT_FOUND);
478 return -1;
480 return sc_cb_open(&(charbuf[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
481 } else {
482 TRACE(" Callback skipped file.\n");
483 return 0;
485 case fdintCLOSE_FILE_INFO:
486 TRACE("Close file notification\n");
487 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
488 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
489 TRACE(" File hndl: %d\n", pfdin->hf); */
490 fp.Source = &(phsc->most_recent_cabinet_name[0]);
491 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf[0]), MAX_PATH);
492 if ((len > MAX_PATH) || (len <= 1))
493 buf[0] = '\0';
494 fp.Target = &(buf[0]);
495 fp.Win32Error = 0;
496 fp.Flags = 0;
497 /* a valid fixme -- but occurs too many times */
498 /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
499 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT_PTR)&fp, 0);
500 if (sc_cb_close(pfdin->hf))
501 WARN("_close failed.\n");
502 if (err) {
503 SetLastError(err);
504 return FALSE;
505 } else
506 return TRUE;
507 case fdintNEXT_CABINET:
508 TRACE("Next cabinet notification\n");
509 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
510 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
511 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
512 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
513 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
514 /* remember the new cabinet name */
515 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(phsc->most_recent_cabinet_name[0]), MAX_PATH);
516 if ((len > MAX_PATH) || (len <= 1))
517 phsc->most_recent_cabinet_name[0] = '\0';
518 ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
519 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
520 if ((len > MAX_PATH) || (len <= 1))
521 buf[0] = '\0';
522 ci.CabinetPath = &(buf[0]);
523 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
524 if ((len > MAX_PATH) || (len <= 1))
525 buf2[0] = '\0';
526 ci.DiskName = &(buf2[0]);
527 ci.SetId = pfdin->setID;
528 ci.CabinetNumber = pfdin->iCabinet;
529 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT_PTR)&ci, (UINT_PTR)mysterio);
530 if (err) {
531 SetLastError(err);
532 return -1;
533 } else {
534 if (mysterio[0]) {
535 len = strlenW(&(mysterio[0])) + 1;
536 if ((len > 255) || (len <= 1))
537 return 0;
538 if (!WideCharToMultiByte(CP_ACP, 0, &(mysterio[0]), len, pfdin->psz3, 255, 0, 0))
539 return 0;
541 return 0;
543 default:
544 FIXME("Unknown notification type %d.\n", fdint);
545 return 0;
549 /***********************************************************************
550 * SetupIterateCabinetA (SETUPAPI.@)
552 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
553 PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
556 SC_HSC_A my_hsc;
557 ERF erf;
558 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p = NULL;
559 DWORD fpnsize;
560 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 if (!CabinetFile)
570 SetLastError(ERROR_INVALID_PARAMETER);
571 return FALSE;
574 fpnsize = strlen(CabinetFile);
575 if (fpnsize >= MAX_PATH) {
576 SetLastError(ERROR_BAD_PATHNAME);
577 return FALSE;
580 fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p);
581 if (fpnsize > MAX_PATH) {
582 SetLastError(ERROR_BAD_PATHNAME);
583 return FALSE;
586 if (p) {
587 strcpy(pszCabinet, p);
588 *p = '\0';
589 } else {
590 strcpy(pszCabinet, CabinetFile);
591 pszCabPath[0] = '\0';
594 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
596 /* remember the cabinet name */
597 strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet);
599 my_hsc.magic = SC_HSC_A_MAGIC;
600 my_hsc.msghandler = MsgHandler;
601 my_hsc.context = Context;
602 my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
603 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
605 if (!my_hsc.hfdi) return FALSE;
607 ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
608 0, sc_FNNOTIFY_A, NULL, &my_hsc) ) ? TRUE : FALSE;
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,
674 0, sc_FNNOTIFY_W, NULL, &my_hsc) ) ? TRUE : FALSE;
676 sc_FDIDestroy(my_hsc.hfdi);
677 return ret;
681 /***********************************************************************
682 * DllMain
684 * PARAMS
685 * hinstDLL [I] handle to the DLL's instance
686 * fdwReason [I]
687 * lpvReserved [I] reserved, must be NULL
689 * RETURNS
690 * Success: TRUE
691 * Failure: FALSE
694 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
696 switch (fdwReason) {
697 case DLL_PROCESS_ATTACH:
698 DisableThreadLibraryCalls(hinstDLL);
699 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
700 if (!GetVersionExW(&OsVersionInfo))
701 return FALSE;
702 SETUPAPI_hInstance = hinstDLL;
703 break;
704 case DLL_PROCESS_DETACH:
705 UnloadCABINETDll();
706 break;
709 return TRUE;