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/debug.h"
45 #define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
46 #define _O_APPEND 0x0008
47 #define _O_RANDOM 0x0010
48 #define _O_SEQUENTIAL 0x0020
49 #define _O_TEMPORARY 0x0040
50 #define _O_NOINHERIT 0x0080
51 #define _O_CREAT 0x0100
52 #define _O_TRUNC 0x0200
53 #define _O_EXCL 0x0400
54 #define _O_SHORT_LIVED 0x1000
55 #define _O_TEXT 0x4000
56 #define _O_BINARY 0x8000
58 #define _SH_COMPAT 0x00
59 #define _SH_DENYRW 0x10
60 #define _SH_DENYWR 0x20
61 #define _SH_DENYRD 0x30
62 #define _SH_DENYNO 0x40
64 OSVERSIONINFOW OsVersionInfo
;
66 static HINSTANCE CABINET_hInstance
= 0;
67 HINSTANCE SETUPAPI_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
81 PSP_FILE_CALLBACK_A msghandler
;
83 CHAR most_recent_cabinet_name
[MAX_PATH
];
84 CHAR most_recent_target
[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 WCHAR most_recent_target
[MAX_PATH
];
95 } SC_HSC_W
, *PSC_HSC_W
;
97 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
99 static BOOL
LoadCABINETDll(void)
101 if (!CABINET_hInstance
) {
102 CABINET_hInstance
= LoadLibraryA("cabinet.dll");
103 if (CABINET_hInstance
) {
104 sc_FDICreate
= (void *)GetProcAddress(CABINET_hInstance
, "FDICreate");
105 sc_FDICopy
= (void *)GetProcAddress(CABINET_hInstance
, "FDICopy");
106 sc_FDIDestroy
= (void *)GetProcAddress(CABINET_hInstance
, "FDIDestroy");
109 ERR("load cabinet dll failed.\n");
116 /* FDICreate callbacks */
118 static void * CDECL
sc_cb_alloc(ULONG cb
)
120 return HeapAlloc(GetProcessHeap(), 0, cb
);
123 static void CDECL
sc_cb_free(void *pv
)
125 HeapFree(GetProcessHeap(), 0, pv
);
128 static INT_PTR CDECL
sc_cb_open(char *pszFile
, int oflag
, int pmode
)
130 DWORD creation
= 0, sharing
= 0;
133 SECURITY_ATTRIBUTES sa
;
135 /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
137 switch(oflag
& (_O_RDONLY
| _O_WRONLY
| _O_RDWR
)) {
139 ioflag
|= GENERIC_READ
;
142 ioflag
|= GENERIC_WRITE
;
145 ioflag
|= GENERIC_READ
| GENERIC_WRITE
;
147 case _O_WRONLY
| _O_RDWR
: /* hmmm.. */
148 ERR("_O_WRONLY & _O_RDWR in oflag?\n");
152 if (oflag
& _O_CREAT
) {
154 creation
= CREATE_NEW
;
155 else if (oflag
& _O_TRUNC
)
156 creation
= CREATE_ALWAYS
;
158 creation
= OPEN_ALWAYS
;
159 } else /* no _O_CREAT */ {
160 if (oflag
& _O_TRUNC
)
161 creation
= TRUNCATE_EXISTING
;
163 creation
= OPEN_EXISTING
;
166 switch( pmode
& 0x70 ) {
171 sharing
= FILE_SHARE_READ
;
174 sharing
= FILE_SHARE_WRITE
;
178 sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
181 ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode
);
185 if (oflag
& ~(_O_BINARY
| _O_TRUNC
| _O_EXCL
| _O_CREAT
| _O_RDWR
| _O_WRONLY
| _O_NOINHERIT
))
186 WARN("unsupported oflag 0x%04x\n",oflag
);
188 sa
.nLength
= sizeof( SECURITY_ATTRIBUTES
);
189 sa
.lpSecurityDescriptor
= NULL
;
190 sa
.bInheritHandle
= !(ioflag
& _O_NOINHERIT
);
192 ret
= (INT_PTR
) CreateFileA(pszFile
, ioflag
, sharing
, &sa
, creation
, FILE_ATTRIBUTE_NORMAL
, NULL
);
194 /* TRACE("<-- %d\n", ret); */
199 static UINT CDECL
sc_cb_read(INT_PTR hf
, void *pv
, UINT cb
)
204 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
206 rslt
= ReadFile((HANDLE
) hf
, pv
, cb
, &num_read
, NULL
);
209 /* eof and failure both give "-1" return */
210 if ((! rslt
) || ((cb
> 0) && (num_read
== 0))) {
211 /* TRACE("<-- -1\n"); */
215 /* TRACE("<-- %lu\n", num_read); */
219 static UINT CDECL
sc_cb_write(INT_PTR hf
, void *pv
, UINT cb
)
224 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
226 if ( /* (rv = */ WriteFile((HANDLE
) hf
, pv
, cb
, &num_written
, NULL
) /* ) */
227 && (num_written
== cb
)) {
228 /* TRACE("<-- %lu\n", num_written); */
231 /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
232 /* TRACE("<-- -1\n"); */
237 static int CDECL
sc_cb_close(INT_PTR hf
)
239 /* TRACE("(hf == %d)\n", hf); */
241 if (CloseHandle((HANDLE
) hf
))
247 static LONG CDECL
sc_cb_lseek(INT_PTR hf
, LONG dist
, int seektype
)
251 /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
253 if (seektype
< 0 || seektype
> 2)
256 if (((ret
= SetFilePointer((HANDLE
) hf
, dist
, NULL
, seektype
)) != INVALID_SET_FILE_POINTER
) || !GetLastError()) {
257 /* TRACE("<-- %lu\n", ret); */
260 /* TRACE("<-- -1\n"); */
265 #define SIZEOF_MYSTERIO (MAX_PATH*3)
267 /* FDICopy callbacks */
269 static INT_PTR CDECL
sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
271 FILE_IN_CABINET_INFO_A fici
;
277 CHAR mysterio
[SIZEOF_MYSTERIO
]; /* how big? undocumented! probably 256... */
279 memset(mysterio
, 0, SIZEOF_MYSTERIO
);
281 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint
, pfdin
);
283 if (pfdin
&& pfdin
->pv
&& (((PSC_HSC_A
) pfdin
->pv
)->magic
== SC_HSC_A_MAGIC
))
286 ERR("pv %p is not an SC_HSC_A.\n", (pfdin
) ? pfdin
->pv
: NULL
);
291 case fdintCABINET_INFO
:
292 TRACE("Cabinet info notification\n");
293 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
294 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
295 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
296 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
297 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
298 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
299 ci
.CabinetFile
= phsc
->most_recent_cabinet_name
;
300 ci
.CabinetPath
= pfdin
->psz3
;
301 ci
.DiskName
= pfdin
->psz2
;
302 ci
.SetId
= pfdin
->setID
;
303 ci
.CabinetNumber
= pfdin
->iCabinet
;
304 phsc
->msghandler(phsc
->context
, SPFILENOTIFY_CABINETINFO
, (UINT_PTR
) &ci
, 0);
306 case fdintPARTIAL_FILE
:
307 TRACE("Partial file notification\n");
308 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
311 TRACE("Copy file notification\n");
312 TRACE(" File name: %s\n", debugstr_a(pfdin
->psz1
));
313 /* TRACE(" File size: %ld\n", pfdin->cb);
314 TRACE(" File date: %u\n", pfdin->date);
315 TRACE(" File time: %u\n", pfdin->time);
316 TRACE(" File attr: %u\n", pfdin->attribs); */
317 fici
.NameInCabinet
= pfdin
->psz1
;
318 fici
.FileSize
= pfdin
->cb
;
320 fici
.DosDate
= pfdin
->date
;
321 fici
.DosTime
= pfdin
->time
;
322 fici
.DosAttribs
= pfdin
->attribs
;
323 memset(fici
.FullTargetName
, 0, MAX_PATH
);
324 err
= phsc
->msghandler(phsc
->context
, SPFILENOTIFY_FILEINCABINET
,
325 (UINT_PTR
)&fici
, (UINT_PTR
)pfdin
->psz1
);
326 if (err
== FILEOP_DOIT
) {
327 TRACE(" Callback specified filename: %s\n", debugstr_a(fici
.FullTargetName
));
328 if (!fici
.FullTargetName
[0]) {
329 WARN(" Empty return string causing abort.\n");
330 SetLastError(ERROR_PATH_NOT_FOUND
);
333 strcpy( phsc
->most_recent_target
, fici
.FullTargetName
);
334 return sc_cb_open(fici
.FullTargetName
, _O_BINARY
| _O_CREAT
| _O_WRONLY
, _S_IREAD
| _S_IWRITE
);
336 TRACE(" Callback skipped file.\n");
339 case fdintCLOSE_FILE_INFO
:
340 TRACE("Close file notification\n");
341 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
342 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
343 TRACE(" File hndl: %d\n", pfdin->hf); */
344 fp
.Source
= phsc
->most_recent_cabinet_name
;
345 fp
.Target
= phsc
->most_recent_target
;
348 /* the following should be a fixme -- but it occurs too many times */
349 WARN("Should set file date/time/attribs (and execute files?)\n");
350 if (sc_cb_close(pfdin
->hf
))
351 WARN("_close failed.\n");
352 err
= phsc
->msghandler(phsc
->context
, SPFILENOTIFY_FILEEXTRACTED
, (UINT_PTR
)&fp
, 0);
358 case fdintNEXT_CABINET
:
359 TRACE("Next cabinet notification\n");
360 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
361 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
362 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
363 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
364 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
365 ci
.CabinetFile
= pfdin
->psz1
;
366 ci
.CabinetPath
= pfdin
->psz3
;
367 ci
.DiskName
= pfdin
->psz2
;
368 ci
.SetId
= pfdin
->setID
;
369 ci
.CabinetNumber
= pfdin
->iCabinet
;
370 /* remember the new cabinet name */
371 strcpy(phsc
->most_recent_cabinet_name
, pfdin
->psz1
);
372 err
= phsc
->msghandler(phsc
->context
, SPFILENOTIFY_NEEDNEWCABINET
, (UINT_PTR
)&ci
, (UINT_PTR
)mysterio
);
378 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
379 lstrcpynA(pfdin
->psz3
, mysterio
, SIZEOF_MYSTERIO
);
384 FIXME("Unknown notification type %d.\n", fdint
);
389 static INT_PTR CDECL
sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint
, PFDINOTIFICATION pfdin
)
391 FILE_IN_CABINET_INFO_W fici
;
398 WCHAR mysterio
[SIZEOF_MYSTERIO
]; /* how big? undocumented! */
399 WCHAR buf
[MAX_PATH
], buf2
[MAX_PATH
];
400 CHAR charbuf
[MAX_PATH
];
402 memset(mysterio
, 0, SIZEOF_MYSTERIO
* sizeof(WCHAR
));
403 memset(buf
, 0, MAX_PATH
* sizeof(WCHAR
));
404 memset(buf2
, 0, MAX_PATH
* sizeof(WCHAR
));
405 memset(charbuf
, 0, MAX_PATH
);
407 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint
, pfdin
);
409 if (pfdin
&& pfdin
->pv
&& (((PSC_HSC_W
) pfdin
->pv
)->magic
== SC_HSC_W_MAGIC
))
412 ERR("pv %p is not an SC_HSC_W.\n", (pfdin
) ? pfdin
->pv
: NULL
);
417 case fdintCABINET_INFO
:
418 TRACE("Cabinet info notification\n");
419 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
420 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
421 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
422 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
423 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
424 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
425 ci
.CabinetFile
= phsc
->most_recent_cabinet_name
;
426 len
= 1 + MultiByteToWideChar(CP_ACP
, 0, pfdin
->psz3
, -1, buf
, MAX_PATH
);
427 if ((len
> MAX_PATH
) || (len
<= 1))
429 ci
.CabinetPath
= buf
;
430 len
= 1 + MultiByteToWideChar(CP_ACP
, 0, pfdin
->psz2
, -1, buf2
, MAX_PATH
);
431 if ((len
> MAX_PATH
) || (len
<= 1))
434 ci
.SetId
= pfdin
->setID
;
435 ci
.CabinetNumber
= pfdin
->iCabinet
;
436 phsc
->msghandler(phsc
->context
, SPFILENOTIFY_CABINETINFO
, (UINT_PTR
)&ci
, 0);
438 case fdintPARTIAL_FILE
:
439 TRACE("Partial file notification\n");
440 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
443 TRACE("Copy file notification\n");
444 TRACE(" File name: %s\n", debugstr_a(pfdin
->psz1
));
445 /* TRACE(" File size: %ld\n", pfdin->cb);
446 TRACE(" File date: %u\n", pfdin->date);
447 TRACE(" File time: %u\n", pfdin->time);
448 TRACE(" File attr: %u\n", pfdin->attribs); */
449 len
= 1 + MultiByteToWideChar(CP_ACP
, 0, pfdin
->psz1
, -1, buf2
, MAX_PATH
);
450 if ((len
> MAX_PATH
) || (len
<= 1))
452 fici
.NameInCabinet
= buf2
;
453 fici
.FileSize
= pfdin
->cb
;
455 fici
.DosDate
= pfdin
->date
;
456 fici
.DosTime
= pfdin
->time
;
457 fici
.DosAttribs
= pfdin
->attribs
;
458 memset(fici
.FullTargetName
, 0, MAX_PATH
* sizeof(WCHAR
));
459 err
= phsc
->msghandler(phsc
->context
, SPFILENOTIFY_FILEINCABINET
,
460 (UINT_PTR
)&fici
, (UINT_PTR
)pfdin
->psz1
);
461 if (err
== FILEOP_DOIT
) {
462 TRACE(" Callback specified filename: %s\n", debugstr_w(fici
.FullTargetName
));
463 if (fici
.FullTargetName
[0]) {
464 len
= lstrlenW(fici
.FullTargetName
) + 1;
465 if ((len
> MAX_PATH
) || (len
<= 1))
467 if (!WideCharToMultiByte(CP_ACP
, 0, fici
.FullTargetName
, len
, charbuf
, MAX_PATH
, 0, 0))
470 WARN("Empty buffer string caused abort.\n");
471 SetLastError(ERROR_PATH_NOT_FOUND
);
474 lstrcpyW( phsc
->most_recent_target
, fici
.FullTargetName
);
475 return sc_cb_open(charbuf
, _O_BINARY
| _O_CREAT
| _O_WRONLY
, _S_IREAD
| _S_IWRITE
);
477 TRACE(" Callback skipped file.\n");
480 case fdintCLOSE_FILE_INFO
:
481 TRACE("Close file notification\n");
482 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
483 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
484 TRACE(" File hndl: %d\n", pfdin->hf); */
485 fp
.Source
= phsc
->most_recent_cabinet_name
;
486 fp
.Target
= phsc
->most_recent_target
;
489 /* a valid fixme -- but occurs too many times */
490 /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
491 if (sc_cb_close(pfdin
->hf
))
492 WARN("_close failed.\n");
493 err
= phsc
->msghandler(phsc
->context
, SPFILENOTIFY_FILEEXTRACTED
, (UINT_PTR
)&fp
, 0);
499 case fdintNEXT_CABINET
:
500 TRACE("Next cabinet notification\n");
501 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
502 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
503 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
504 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
505 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
506 /* remember the new cabinet name */
507 len
= 1 + MultiByteToWideChar(CP_ACP
, 0, pfdin
->psz1
, -1, phsc
->most_recent_cabinet_name
, MAX_PATH
);
508 if ((len
> MAX_PATH
) || (len
<= 1))
509 phsc
->most_recent_cabinet_name
[0] = '\0';
510 ci
.CabinetFile
= phsc
->most_recent_cabinet_name
;
511 len
= 1 + MultiByteToWideChar(CP_ACP
, 0, pfdin
->psz3
, -1, buf
, MAX_PATH
);
512 if ((len
> MAX_PATH
) || (len
<= 1))
514 ci
.CabinetPath
= buf
;
515 len
= 1 + MultiByteToWideChar(CP_ACP
, 0, pfdin
->psz2
, -1, buf2
, MAX_PATH
);
516 if ((len
> MAX_PATH
) || (len
<= 1))
519 ci
.SetId
= pfdin
->setID
;
520 ci
.CabinetNumber
= pfdin
->iCabinet
;
521 err
= phsc
->msghandler(phsc
->context
, SPFILENOTIFY_NEEDNEWCABINET
, (UINT_PTR
)&ci
, (UINT_PTR
)mysterio
);
527 len
= lstrlenW(mysterio
) + 1;
528 if ((len
> 255) || (len
<= 1))
530 if (!WideCharToMultiByte(CP_ACP
, 0, mysterio
, len
, pfdin
->psz3
, 255, 0, 0))
536 FIXME("Unknown notification type %d.\n", fdint
);
541 /***********************************************************************
542 * SetupIterateCabinetA (SETUPAPI.@)
544 BOOL WINAPI
SetupIterateCabinetA(PCSTR CabinetFile
, DWORD Reserved
,
545 PSP_FILE_CALLBACK_A MsgHandler
, PVOID Context
)
550 CHAR pszCabinet
[MAX_PATH
], pszCabPath
[MAX_PATH
], *p
= NULL
;
554 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
555 debugstr_a(CabinetFile
), Reserved
, MsgHandler
, Context
);
557 if (!LoadCABINETDll())
562 SetLastError(ERROR_INVALID_PARAMETER
);
566 fpnsize
= strlen(CabinetFile
);
567 if (fpnsize
>= MAX_PATH
) {
568 SetLastError(ERROR_BAD_PATHNAME
);
572 fpnsize
= GetFullPathNameA(CabinetFile
, MAX_PATH
, pszCabPath
, &p
);
573 if (fpnsize
> MAX_PATH
) {
574 SetLastError(ERROR_BAD_PATHNAME
);
579 strcpy(pszCabinet
, p
);
582 strcpy(pszCabinet
, CabinetFile
);
583 pszCabPath
[0] = '\0';
586 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath
), debugstr_a(pszCabinet
));
588 /* remember the cabinet name */
589 strcpy(my_hsc
.most_recent_cabinet_name
, pszCabinet
);
591 my_hsc
.magic
= SC_HSC_A_MAGIC
;
592 my_hsc
.msghandler
= MsgHandler
;
593 my_hsc
.context
= Context
;
594 my_hsc
.hfdi
= sc_FDICreate( sc_cb_alloc
, sc_cb_free
, sc_cb_open
, sc_cb_read
,
595 sc_cb_write
, sc_cb_close
, sc_cb_lseek
, cpuUNKNOWN
, &erf
);
597 if (!my_hsc
.hfdi
) return FALSE
;
599 ret
= sc_FDICopy(my_hsc
.hfdi
, pszCabinet
, pszCabPath
, 0, sc_FNNOTIFY_A
, NULL
, &my_hsc
);
601 sc_FDIDestroy(my_hsc
.hfdi
);
606 /***********************************************************************
607 * SetupIterateCabinetW (SETUPAPI.@)
609 BOOL WINAPI
SetupIterateCabinetW(PCWSTR CabinetFile
, DWORD Reserved
,
610 PSP_FILE_CALLBACK_W MsgHandler
, PVOID Context
)
612 CHAR pszCabinet
[MAX_PATH
], pszCabPath
[MAX_PATH
];
616 WCHAR pszCabPathW
[MAX_PATH
], *p
= NULL
;
620 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
621 debugstr_w(CabinetFile
), Reserved
, MsgHandler
, Context
);
623 if (!LoadCABINETDll())
628 SetLastError(ERROR_INVALID_PARAMETER
);
632 fpnsize
= GetFullPathNameW(CabinetFile
, MAX_PATH
, pszCabPathW
, &p
);
633 if (fpnsize
> MAX_PATH
) {
634 SetLastError(ERROR_BAD_PATHNAME
);
639 lstrcpyW(my_hsc
.most_recent_cabinet_name
, p
);
641 len
= WideCharToMultiByte(CP_ACP
, 0, pszCabPathW
, -1, pszCabPath
,
643 if (!len
) return FALSE
;
645 lstrcpyW(my_hsc
.most_recent_cabinet_name
, CabinetFile
);
646 pszCabPath
[0] = '\0';
649 len
= WideCharToMultiByte(CP_ACP
, 0, my_hsc
.most_recent_cabinet_name
, -1,
650 pszCabinet
, MAX_PATH
, 0, 0);
651 if (!len
) return FALSE
;
653 TRACE("path: %s, cabfile: %s\n",
654 debugstr_a(pszCabPath
), debugstr_a(pszCabinet
));
656 my_hsc
.magic
= SC_HSC_W_MAGIC
;
657 my_hsc
.msghandler
= MsgHandler
;
658 my_hsc
.context
= Context
;
659 my_hsc
.hfdi
= sc_FDICreate( sc_cb_alloc
, sc_cb_free
, sc_cb_open
, sc_cb_read
,
660 sc_cb_write
, sc_cb_close
, sc_cb_lseek
, cpuUNKNOWN
, &erf
);
662 if (!my_hsc
.hfdi
) return FALSE
;
664 ret
= sc_FDICopy(my_hsc
.hfdi
, pszCabinet
, pszCabPath
, 0, sc_FNNOTIFY_W
, NULL
, &my_hsc
);
666 sc_FDIDestroy(my_hsc
.hfdi
);
671 /***********************************************************************
675 * hinstDLL [I] handle to the DLL's instance
677 * lpvReserved [I] reserved, must be NULL
684 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
687 case DLL_PROCESS_ATTACH
:
688 DisableThreadLibraryCalls(hinstDLL
);
689 OsVersionInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOW
);
690 if (!GetVersionExW(&OsVersionInfo
))
692 SETUPAPI_hInstance
= hinstDLL
;
694 case DLL_PROCESS_DETACH
:
695 if (lpvReserved
) break;
697 if (CABINET_hInstance
) FreeLibrary(CABINET_hInstance
);