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
37 #include "setupapi_private.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
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
82 PSP_FILE_CALLBACK_A msghandler
;
84 CHAR most_recent_cabinet_name
[MAX_PATH
];
85 } SC_HSC_A
, *PSC_HSC_A
;
87 #define SC_HSC_W_MAGIC 0x0CABFEED
91 PSP_FILE_CALLBACK_W msghandler
;
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");
108 ERR("load cabinet dll failed.\n");
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;
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
)) {
146 ioflag
|= GENERIC_READ
;
149 ioflag
|= GENERIC_WRITE
;
152 ioflag
|= GENERIC_READ
& GENERIC_WRITE
;
154 case _O_WRONLY
| _O_RDWR
: /* hmmm.. */
155 ERR("_O_WRONLY & _O_RDWR in oflag?\n");
159 if (oflag
& _O_CREAT
) {
161 creation
= CREATE_NEW
;
162 else if (oflag
& _O_TRUNC
)
163 creation
= CREATE_ALWAYS
;
165 creation
= OPEN_ALWAYS
;
166 } else /* no _O_CREAT */ {
167 if (oflag
& _O_TRUNC
)
168 creation
= TRUNCATE_EXISTING
;
170 creation
= OPEN_EXISTING
;
173 switch( pmode
& 0x70 ) {
178 sharing
= FILE_SHARE_READ
;
181 sharing
= FILE_SHARE_WRITE
;
185 sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
188 ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode
);
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); */
206 static UINT CDECL
sc_cb_read(INT_PTR hf
, void *pv
, UINT cb
)
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"); */
222 /* TRACE("<-- %lu\n", num_read); */
226 static UINT CDECL
sc_cb_write(INT_PTR hf
, void *pv
, UINT cb
)
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); */
238 /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
239 /* TRACE("<-- -1\n"); */
244 static int CDECL
sc_cb_close(INT_PTR hf
)
246 /* TRACE("(hf == %d)\n", hf); */
248 if (CloseHandle((HANDLE
) hf
))
254 static LONG CDECL
sc_cb_lseek(INT_PTR hf
, LONG dist
, int seektype
)
258 /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
260 if (seektype
< 0 || seektype
> 2)
263 if (((ret
= SetFilePointer((HANDLE
) hf
, dist
, NULL
, seektype
)) != INVALID_SET_FILE_POINTER
) || !GetLastError()) {
264 /* TRACE("<-- %lu\n", ret); */
267 /* TRACE("<-- -1\n"); */
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
;
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
&& (*((void **) pfdin
->pv
) == (void *)SC_HSC_A_MAGIC
))
293 ERR("pv %p is not an SC_HSC_A.\n", (pfdin
) ? pfdin
->pv
: NULL
);
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);
313 case fdintPARTIAL_FILE
:
314 TRACE("Partial file notification\n");
315 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
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
;
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
);
340 return sc_cb_open(&(fici
.FullTargetName
[0]), _O_BINARY
| _O_CREAT
| _O_WRONLY
, _S_IREAD
| _S_IWRITE
);
342 TRACE(" Callback skipped file.\n");
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
;
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");
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
);
384 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
385 lstrcpynA(pfdin
->psz3
, &(mysterio
[0]), SIZEOF_MYSTERIO
);
390 FIXME("Unknown notification type %d.\n", fdint
);
395 static INT_PTR CDECL
sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
397 FILE_IN_CABINET_INFO_W fici
;
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
&& (*((void **) pfdin
->pv
) == (void *)SC_HSC_W_MAGIC
))
418 ERR("pv %p is not an SC_HSC_W.\n", (pfdin
) ? pfdin
->pv
: NULL
);
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))
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))
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);
444 case fdintPARTIAL_FILE
:
445 TRACE("Partial file notification\n");
446 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
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))
458 fici
.NameInCabinet
= &(buf2
[0]);
459 fici
.FileSize
= pfdin
->cb
;
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))
473 if (!WideCharToMultiByte(CP_ACP
, 0, &(fici
.FullTargetName
[0]), len
, &(charbuf
[0]), MAX_PATH
, 0, 0))
476 WARN("Empty buffer string caused abort.\n");
477 SetLastError(ERROR_PATH_NOT_FOUND
);
480 return sc_cb_open(&(charbuf
[0]), _O_BINARY
| _O_CREAT
| _O_WRONLY
, _S_IREAD
| _S_IWRITE
);
482 TRACE(" Callback skipped file.\n");
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))
494 fp
.Target
= &(buf
[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");
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))
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))
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
);
535 len
= strlenW(&(mysterio
[0])) + 1;
536 if ((len
> 255) || (len
<= 1))
538 if (!WideCharToMultiByte(CP_ACP
, 0, &(mysterio
[0]), len
, pfdin
->psz3
, 255, 0, 0))
544 FIXME("Unknown notification type %d.\n", fdint
);
549 /***********************************************************************
550 * SetupIterateCabinetA (SETUPAPI.@)
552 BOOL WINAPI
SetupIterateCabinetA(PCSTR CabinetFile
, DWORD Reserved
,
553 PSP_FILE_CALLBACK_A MsgHandler
, PVOID Context
)
558 CHAR pszCabinet
[MAX_PATH
], pszCabPath
[MAX_PATH
], *p
= NULL
;
562 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
563 debugstr_a(CabinetFile
), Reserved
, MsgHandler
, Context
);
565 if (!LoadCABINETDll())
570 SetLastError(ERROR_INVALID_PARAMETER
);
574 fpnsize
= strlen(CabinetFile
);
575 if (fpnsize
>= MAX_PATH
) {
576 SetLastError(ERROR_BAD_PATHNAME
);
580 fpnsize
= GetFullPathNameA(CabinetFile
, MAX_PATH
, &(pszCabPath
[0]), &p
);
581 if (fpnsize
> MAX_PATH
) {
582 SetLastError(ERROR_BAD_PATHNAME
);
587 strcpy(pszCabinet
, p
);
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
);
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
];
625 WCHAR pszCabPathW
[MAX_PATH
], *p
= NULL
;
629 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
630 debugstr_w(CabinetFile
), Reserved
, MsgHandler
, Context
);
632 if (!LoadCABINETDll())
637 SetLastError(ERROR_INVALID_PARAMETER
);
641 fpnsize
= GetFullPathNameW(CabinetFile
, MAX_PATH
, pszCabPathW
, &p
);
642 if (fpnsize
> MAX_PATH
) {
643 SetLastError(ERROR_BAD_PATHNAME
);
648 strcpyW(my_hsc
.most_recent_cabinet_name
, p
);
650 len
= WideCharToMultiByte(CP_ACP
, 0, pszCabPathW
, -1, pszCabPath
,
652 if (!len
) return FALSE
;
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
);
681 /***********************************************************************
685 * hinstDLL [I] handle to the DLL's instance
687 * lpvReserved [I] reserved, must be NULL
694 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
697 case DLL_PROCESS_ATTACH
:
698 DisableThreadLibraryCalls(hinstDLL
);
699 OsVersionInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
700 if (!GetVersionExW(&OsVersionInfo
))
702 SETUPAPI_hInstance
= hinstDLL
;
704 case DLL_PROCESS_DETACH
: