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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Many useful traces are commented in code, uncomment them if you have
22 * trouble and run with WINEDEBUG=+setupapi
30 #include "wine/debug.h"
38 #include "setupapi_private.h"
40 #include "wine/unicode.h"
42 #include "msvcrt/fcntl.h"
43 #include "msvcrt/share.h"
45 #include "wine/debug.h"
47 OSVERSIONINFOW OsVersionInfo;
49 static HINSTANCE CABINET_hInstance = 0;
51 static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN,
52 PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF);
54 static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int,
55 PFNFDINOTIFY, PFNFDIDECRYPT, void *);
57 static BOOL (__cdecl *sc_FDIDestroy)(HFDI);
59 #define SC_HSC_A_MAGIC 0xACABFEED
63 PSP_FILE_CALLBACK_A msghandler;
65 CHAR most_recent_cabinet_name[MAX_PATH];
66 } SC_HSC_A, *PSC_HSC_A;
68 #define SC_HSC_W_MAGIC 0x0CABFEED
72 PSP_FILE_CALLBACK_W msghandler;
74 WCHAR most_recent_cabinet_name[MAX_PATH];
75 } SC_HSC_W, *PSC_HSC_W;
77 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
79 static BOOL LoadCABINETDll(void)
81 if (!CABINET_hInstance) {
82 CABINET_hInstance = LoadLibraryA("cabinet.dll");
83 if (CABINET_hInstance) {
84 sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate");
85 sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy");
86 sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy");
89 ERR("load cabinet dll failed.\n");
96 static void UnloadCABINETDll(void)
98 if (CABINET_hInstance) {
99 FreeLibrary(CABINET_hInstance);
100 CABINET_hInstance = 0;
104 /* FDICreate callbacks */
106 static void *sc_cb_alloc(ULONG cb)
111 static void sc_cb_free(void *pv)
116 static INT_PTR sc_cb_open(char *pszFile, int oflag, int pmode)
118 DWORD creation = 0, sharing = 0;
121 SECURITY_ATTRIBUTES sa;
123 /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */
125 switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
127 ioflag |= GENERIC_READ;
130 ioflag |= GENERIC_WRITE;
133 ioflag |= GENERIC_READ & GENERIC_WRITE;
135 case _O_WRONLY | _O_RDWR: /* hmmm.. */
136 ERR("_O_WRONLY & _O_RDWR in oflag?\n");
140 if (oflag & _O_CREAT) {
142 creation = CREATE_NEW;
143 else if (oflag & _O_TRUNC)
144 creation = CREATE_ALWAYS;
146 creation = OPEN_ALWAYS;
147 } else /* no _O_CREAT */ {
148 if (oflag & _O_TRUNC)
149 creation = TRUNCATE_EXISTING;
151 creation = OPEN_EXISTING;
154 switch( pmode & 0x70 ) {
159 sharing = FILE_SHARE_READ;
162 sharing = FILE_SHARE_WRITE;
166 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
169 ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode);
173 if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT))
174 WARN("unsupported oflag 0x%04x\n",oflag);
176 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
177 sa.lpSecurityDescriptor = NULL;
178 sa.bInheritHandle = (ioflag & _O_NOINHERIT) ? FALSE : TRUE;
180 ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL);
182 /* TRACE("<-- %d\n", ret); */
187 static UINT sc_cb_read(INT_PTR hf, void *pv, UINT cb)
192 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
194 rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL);
197 /* eof and failure both give "-1" return */
198 if ((! rslt) || ((cb > 0) && (num_read == 0))) {
199 /* TRACE("<-- -1\n"); */
203 /* TRACE("<-- %lu\n", num_read); */
207 static UINT sc_cb_write(INT_PTR hf, void *pv, UINT cb)
212 /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */
214 if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */
215 && (num_written == cb)) {
216 /* TRACE("<-- %lu\n", num_written); */
219 /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */
220 /* TRACE("<-- -1\n"); */
225 static int sc_cb_close(INT_PTR hf)
227 /* TRACE("(hf == %d)\n", hf); */
229 if (CloseHandle((HANDLE) hf))
235 static long sc_cb_lseek(INT_PTR hf, long dist, int seektype)
239 /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */
241 if (seektype < 0 || seektype > 2)
244 if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) {
245 /* TRACE("<-- %lu\n", ret); */
248 /* TRACE("<-- -1\n"); */
253 #define SIZEOF_MYSTERIO (MAX_PATH*3)
255 /* FDICopy callbacks */
257 static INT_PTR sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
259 FILE_IN_CABINET_INFO_A fici;
265 CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */
267 memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO);
269 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
271 if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_A_MAGIC))
272 phsc = (PSC_HSC_A) pfdin->pv;
274 ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL);
279 case fdintCABINET_INFO:
280 TRACE("Cabinet info notification\n");
281 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
282 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
283 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
284 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
285 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
286 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
287 ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
288 ci.CabinetPath = pfdin->psz3;
289 ci.DiskName = pfdin->psz2;
290 ci.SetId = pfdin->setID;
291 ci.CabinetNumber = pfdin->iCabinet;
292 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0);
294 case fdintPARTIAL_FILE:
295 TRACE("Partial file notification\n");
296 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
299 TRACE("Copy file notification\n");
300 TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
301 /* TRACE(" File size: %ld\n", pfdin->cb);
302 TRACE(" File date: %u\n", pfdin->date);
303 TRACE(" File time: %u\n", pfdin->time);
304 TRACE(" File attr: %u\n", pfdin->attribs); */
305 fici.NameInCabinet = pfdin->psz1;
306 fici.FileSize = pfdin->cb;
308 fici.DosDate = pfdin->date;
309 fici.DosTime = pfdin->time;
310 fici.DosAttribs = pfdin->attribs;
311 memset(&(fici.FullTargetName[0]), 0, MAX_PATH);
312 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
313 (UINT) &fici, (UINT) pfdin->psz1);
314 if (err == FILEOP_DOIT) {
315 TRACE(" Callback specified filename: %s\n", debugstr_a(&(fici.FullTargetName[0])));
316 if (!fici.FullTargetName[0]) {
317 WARN(" Empty return string causing abort.\n");
318 SetLastError(ERROR_PATH_NOT_FOUND);
321 return sc_cb_open(&(fici.FullTargetName[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
323 TRACE(" Callback skipped file.\n");
326 case fdintCLOSE_FILE_INFO:
327 TRACE("Close file notification\n");
328 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
329 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
330 TRACE(" File hndl: %d\n", pfdin->hf); */
331 fp.Source = &(phsc->most_recent_cabinet_name[0]);
332 fp.Target = pfdin->psz1;
335 /* the following should be a fixme -- but it occurs too many times */
336 WARN("Should set file date/time/attribs (and execute files?)\n");
337 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0);
338 if (sc_cb_close(pfdin->hf))
339 WARN("_close failed.\n");
345 case fdintNEXT_CABINET:
346 TRACE("Next cabinet notification\n");
347 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
348 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
349 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
350 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
351 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
352 ci.CabinetFile = pfdin->psz1;
353 ci.CabinetPath = pfdin->psz3;
354 ci.DiskName = pfdin->psz2;
355 ci.SetId = pfdin->setID;
356 ci.CabinetNumber = pfdin->iCabinet;
357 /* remember the new cabinet name */
358 strcpy(&(phsc->most_recent_cabinet_name[0]), pfdin->psz1);
359 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0]));
365 /* some easy paranoia. no such carefulness exists on the wide API IIRC */
366 mysterio[SIZEOF_MYSTERIO - 1] = '\0';
367 strncpy(pfdin->psz3, &(mysterio[0]), 255);
368 mysterio[255] = '\0';
373 FIXME("Unknown notification type %d.\n", fdint);
378 static INT_PTR sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
380 FILE_IN_CABINET_INFO_W fici;
387 WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */
388 WCHAR buf[MAX_PATH], buf2[MAX_PATH];
389 CHAR charbuf[MAX_PATH];
391 memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO * sizeof(WCHAR));
392 memset(&(buf[0]), 0, MAX_PATH * sizeof(WCHAR));
393 memset(&(buf2[0]), 0, MAX_PATH * sizeof(WCHAR));
394 memset(&(charbuf[0]), 0, MAX_PATH);
396 TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin);
398 if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_W_MAGIC))
399 phsc = (PSC_HSC_W) pfdin->pv;
401 ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL);
406 case fdintCABINET_INFO:
407 TRACE("Cabinet info notification\n");
408 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
409 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
410 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
411 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
412 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
413 WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n");
414 ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
415 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
416 if ((len > MAX_PATH) || (len <= 1))
418 ci.CabinetPath = &(buf[0]);
419 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
420 if ((len > MAX_PATH) || (len <= 1))
422 ci.DiskName = &(buf2[0]);
423 ci.SetId = pfdin->setID;
424 ci.CabinetNumber = pfdin->iCabinet;
425 phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0);
427 case fdintPARTIAL_FILE:
428 TRACE("Partial file notification\n");
429 /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */
432 TRACE("Copy file notification\n");
433 TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
434 /* TRACE(" File size: %ld\n", pfdin->cb);
435 TRACE(" File date: %u\n", pfdin->date);
436 TRACE(" File time: %u\n", pfdin->time);
437 TRACE(" File attr: %u\n", pfdin->attribs); */
438 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf2[0]), MAX_PATH);
439 if ((len > MAX_PATH) || (len <= 1))
441 fici.NameInCabinet = &(buf2[0]);
442 fici.FileSize = pfdin->cb;
444 fici.DosDate = pfdin->date;
445 fici.DosTime = pfdin->time;
446 fici.DosAttribs = pfdin->attribs;
447 memset(&(fici.FullTargetName[0]), 0, MAX_PATH * sizeof(WCHAR));
448 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET,
449 (UINT) &fici, (UINT) pfdin->psz1);
450 if (err == FILEOP_DOIT) {
451 TRACE(" Callback specified filename: %s\n", debugstr_w(&(fici.FullTargetName[0])));
452 if (fici.FullTargetName[0]) {
453 len = strlenW(&(fici.FullTargetName[0])) + 1;
454 if ((len > MAX_PATH ) || (len <= 1))
456 if (!WideCharToMultiByte(CP_ACP, 0, &(fici.FullTargetName[0]), len, &(charbuf[0]), MAX_PATH, 0, 0))
459 WARN("Empty buffer string caused abort.\n");
460 SetLastError(ERROR_PATH_NOT_FOUND);
463 return sc_cb_open(&(charbuf[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
465 TRACE(" Callback skipped file.\n");
468 case fdintCLOSE_FILE_INFO:
469 TRACE("Close file notification\n");
470 /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1));
471 TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No");
472 TRACE(" File hndl: %d\n", pfdin->hf); */
473 fp.Source = &(phsc->most_recent_cabinet_name[0]);
474 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf[0]), MAX_PATH);
475 if ((len > MAX_PATH) || (len <= 1))
477 fp.Target = &(buf[0]);
480 /* a valid fixme -- but occurs too many times */
481 /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */
482 err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0);
483 if (sc_cb_close(pfdin->hf))
484 WARN("_close failed.\n");
490 case fdintNEXT_CABINET:
491 TRACE("Next cabinet notification\n");
492 /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1));
493 TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2));
494 TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3));
495 TRACE(" Cabinet Set#: %d\n", pfdin->setID);
496 TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */
497 /* remember the new cabinet name */
498 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(phsc->most_recent_cabinet_name[0]), MAX_PATH);
499 if ((len > MAX_PATH) || (len <= 1))
500 phsc->most_recent_cabinet_name[0] = '\0';
501 ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]);
502 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH);
503 if ((len > MAX_PATH) || (len <= 1))
505 ci.CabinetPath = &(buf[0]);
506 len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH);
507 if ((len > MAX_PATH) || (len <= 1))
509 ci.DiskName = &(buf2[0]);
510 ci.SetId = pfdin->setID;
511 ci.CabinetNumber = pfdin->iCabinet;
512 err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0]));
518 len = strlenW(&(mysterio[0])) + 1;
519 if ((len > 255) || (len <= 1))
521 if (!WideCharToMultiByte(CP_ACP, 0, &(mysterio[0]), len, pfdin->psz3, 255, 0, 0))
527 FIXME("Unknown notification type %d.\n", fdint);
532 /***********************************************************************
533 * SetupIterateCabinetA (SETUPAPI.@)
535 BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved,
536 PSP_FILE_CALLBACK_A MsgHandler, PVOID Context)
541 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p;
546 TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n",
547 debugstr_a(CabinetFile), Reserved, MsgHandler, Context);
549 if (! LoadCABINETDll())
552 memset(&my_hsc, 0, sizeof(SC_HSC_A));
553 pszCabinet[0] = '\0';
554 pszCabPath[0] = '\0';
556 fpnsize = strlen(CabinetFile);
557 if (fpnsize >= MAX_PATH) {
558 SetLastError(ERROR_BAD_PATHNAME);
562 fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p);
563 if (fpnsize > MAX_PATH) {
564 SetLastError(ERROR_BAD_PATHNAME);
569 strcpy(pszCabinet, p);
572 strcpy(pszCabinet, CabinetFile);
573 pszCabPath[0] = '\0';
576 TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet));
578 /* remember the cabinet name */
579 strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet);
581 my_hsc.magic = SC_HSC_A_MAGIC;
582 my_hsc.msghandler = MsgHandler;
583 my_hsc.context = Context;
584 my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
585 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
587 if (!my_hsc.hfdi) return FALSE;
589 ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
590 0, sc_FNNOTIFY_A, NULL, &my_hsc) ) ? TRUE : FALSE;
592 sc_FDIDestroy(my_hsc.hfdi);
597 /***********************************************************************
598 * SetupIterateCabinetW (SETUPAPI.@)
600 BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved,
601 PSP_FILE_CALLBACK_W MsgHandler, PVOID Context)
603 CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH];
607 WCHAR pszCabPathW[MAX_PATH], *p;
611 TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n",
612 debugstr_w(CabinetFile), Reserved, MsgHandler, Context);
614 if (!LoadCABINETDll())
617 if (!CabinetFile) return FALSE;
619 memset(&my_hsc, 0, sizeof(SC_HSC_W));
621 fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p);
622 if (fpnsize > MAX_PATH) {
623 SetLastError(ERROR_BAD_PATHNAME);
628 strcpyW(my_hsc.most_recent_cabinet_name, p);
630 len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath,
632 if (!len) return FALSE;
634 strcpyW(my_hsc.most_recent_cabinet_name, CabinetFile);
635 pszCabPath[0] = '\0';
638 len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1,
639 pszCabinet, MAX_PATH, 0, 0);
640 if (!len) return FALSE;
642 TRACE("path: %s, cabfile: %s\n",
643 debugstr_a(pszCabPath), debugstr_a(pszCabinet));
645 my_hsc.magic = SC_HSC_W_MAGIC;
646 my_hsc.msghandler = MsgHandler;
647 my_hsc.context = Context;
648 my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read,
649 sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf );
651 if (!my_hsc.hfdi) return FALSE;
653 ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath,
654 0, sc_FNNOTIFY_W, NULL, &my_hsc) ) ? TRUE : FALSE;
656 sc_FDIDestroy(my_hsc.hfdi);
661 /***********************************************************************
665 * hinstDLL [I] handle to the DLL's instance
667 * lpvReserved [I] reserved, must be NULL
674 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
677 case DLL_PROCESS_ATTACH:
678 DisableThreadLibraryCalls(hinstDLL);
679 OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
680 if (!GetVersionExW(&OsVersionInfo))
683 case DLL_PROCESS_DETACH: