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);
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, 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))
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;
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, 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));
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, _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;
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, 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, 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, SIZEOF_MYSTERIO * sizeof(WCHAR));
409 memset(buf, 0, MAX_PATH * sizeof(WCHAR));
410 memset(buf2, 0, MAX_PATH * sizeof(WCHAR));
411 memset(charbuf, 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))
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;
432 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
433 if ((len > MAX_PATH) || (len <= 1))
435 ci.CabinetPath = buf;
436 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
437 if ((len > MAX_PATH) || (len <= 1))
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, MAX_PATH);
456 if ((len > MAX_PATH) || (len <= 1))
458 fici.NameInCabinet = buf2;
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, 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));
469 if (fici.FullTargetName[0]) {
470 len = strlenW(fici.FullTargetName) + 1;
471 if ((len > MAX_PATH ) || (len <= 1))
473 if (!WideCharToMultiByte(CP_ACP, 0, fici.FullTargetName, len, charbuf, MAX_PATH, 0, 0))
476 WARN("Empty buffer string caused abort.\n");
477 SetLastError(ERROR_PATH_NOT_FOUND);
480 return sc_cb_open(charbuf, _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;
491 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, buf, MAX_PATH);
492 if ((len > MAX_PATH) || (len <= 1))
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, 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;
519 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, buf, MAX_PATH);
520 if ((len > MAX_PATH) || (len <= 1))
522 ci.CabinetPath = buf;
523 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, buf2, MAX_PATH);
524 if ((len > MAX_PATH) || (len <= 1))
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) + 1;
536 if ((len > 255) || (len <= 1))
538 if (!WideCharToMultiByte(CP_ACP, 0, mysterio, 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, &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, 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, 0, sc_FNNOTIFY_A, NULL, &my_hsc);
609 sc_FDIDestroy(my_hsc.hfdi);
614 /***********************************************************************
615 * SetupIterateCabinetW (SETUPAPI.@)
617 BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
618 PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
620 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH];
624 WCHAR pszCabPathW[MAX_PATH], *p = NULL;
628 TRACE("(CabinetFile == %s, Reserved == %u, MsgHandler == ^%p, Context == ^%p)\n",
629 debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
631 if (!LoadCABINETDll())
636 SetLastError(ERROR_INVALID_PARAMETER);
640 fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p);
641 if (fpnsize > MAX_PATH) {
642 SetLastError(ERROR_BAD_PATHNAME);
647 strcpyW(my_hsc.most_recent_cabinet_name, p);
649 len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath,
651 if (!len) return FALSE;
653 strcpyW(my_hsc.most_recent_cabinet_name, CabinetFile);
654 pszCabPath[0] = '\0';
657 len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1,
658 pszCabinet, MAX_PATH, 0, 0);
659 if (!len) return FALSE;
661 TRACE("path: %s, cabfile: %s\n",
662 debugstr_a(pszCabPath), debugstr_a(pszCabinet));
664 my_hsc.magic = SC_HSC_W_MAGIC;
665 my_hsc.msghandler = MsgHandler;
666 my_hsc.context = Context;
667 my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
668 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
670 if (!my_hsc.hfdi) return FALSE;
672 ret = sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, 0, sc_FNNOTIFY_W, NULL, &my_hsc);
674 sc_FDIDestroy(my_hsc.hfdi);
679 /***********************************************************************
683 * hinstDLL [I] handle to the DLL's instance
685 * lpvReserved [I] reserved, must be NULL
692 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
695 case DLL_PROCESS_ATTACH:
696 DisableThreadLibraryCalls(hinstDLL);
697 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
698 if (!GetVersionExW(&OsVersionInfo))
700 SETUPAPI_hInstance = hinstDLL;
702 case DLL_PROCESS_DETACH: