| /* | |
| * Setupapi cabinet routines | |
| * | |
| * Copyright 2003 Gregory M. Turner | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| * | |
| * | |
| * Many useful traces are commented in code, uncomment them if you have | |
| * trouble and run with WINEDEBUG=+setupapi | |
| * | |
| */ | |
| #include <stdarg.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include "wine/debug.h" | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "winnls.h" | |
| #include "winreg.h" | |
| #include "setupapi.h" | |
| #include "setupapi_private.h" | |
| #include "fdi.h" | |
| #include "wine/unicode.h" | |
| #include "msvcrt/fcntl.h" | |
| #include "msvcrt/share.h" | |
| #include "wine/debug.h" | |
| OSVERSIONINFOW OsVersionInfo; | |
| static HINSTANCE CABINET_hInstance = 0; | |
| static HFDI (__cdecl *sc_FDICreate)(PFNALLOC, PFNFREE, PFNOPEN, | |
| PFNREAD, PFNWRITE, PFNCLOSE, PFNSEEK, int, PERF); | |
| static BOOL (__cdecl *sc_FDICopy)(HFDI, char *, char *, int, | |
| PFNFDINOTIFY, PFNFDIDECRYPT, void *); | |
| static BOOL (__cdecl *sc_FDIDestroy)(HFDI); | |
| #define SC_HSC_A_MAGIC 0xACABFEED | |
| typedef struct { | |
| UINT magic; | |
| HFDI hfdi; | |
| PSP_FILE_CALLBACK_A msghandler; | |
| PVOID context; | |
| CHAR most_recent_cabinet_name[MAX_PATH]; | |
| } SC_HSC_A, *PSC_HSC_A; | |
| #define SC_HSC_W_MAGIC 0x0CABFEED | |
| typedef struct { | |
| UINT magic; | |
| HFDI hfdi; | |
| PSP_FILE_CALLBACK_W msghandler; | |
| PVOID context; | |
| WCHAR most_recent_cabinet_name[MAX_PATH]; | |
| } SC_HSC_W, *PSC_HSC_W; | |
| WINE_DEFAULT_DEBUG_CHANNEL(setupapi); | |
| static BOOL LoadCABINETDll(void) | |
| { | |
| if (!CABINET_hInstance) { | |
| CABINET_hInstance = LoadLibraryA("cabinet.dll"); | |
| if (CABINET_hInstance) { | |
| sc_FDICreate = (void *)GetProcAddress(CABINET_hInstance, "FDICreate"); | |
| sc_FDICopy = (void *)GetProcAddress(CABINET_hInstance, "FDICopy"); | |
| sc_FDIDestroy = (void *)GetProcAddress(CABINET_hInstance, "FDIDestroy"); | |
| return TRUE; | |
| } else { | |
| ERR("load cabinet dll failed.\n"); | |
| return FALSE; | |
| } | |
| } else | |
| return TRUE; | |
| } | |
| static void UnloadCABINETDll(void) | |
| { | |
| if (CABINET_hInstance) { | |
| FreeLibrary(CABINET_hInstance); | |
| CABINET_hInstance = 0; | |
| } | |
| } | |
| /* FDICreate callbacks */ | |
| static void *sc_cb_alloc(ULONG cb) | |
| { | |
| return malloc(cb); | |
| } | |
| static void sc_cb_free(void *pv) | |
| { | |
| free(pv); | |
| } | |
| static INT_PTR sc_cb_open(char *pszFile, int oflag, int pmode) | |
| { | |
| DWORD creation = 0, sharing = 0; | |
| int ioflag = 0; | |
| INT_PTR ret = 0; | |
| SECURITY_ATTRIBUTES sa; | |
| /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */ | |
| switch(oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { | |
| case _O_RDONLY: | |
| ioflag |= GENERIC_READ; | |
| break; | |
| case _O_WRONLY: | |
| ioflag |= GENERIC_WRITE; | |
| break; | |
| case _O_RDWR: | |
| ioflag |= GENERIC_READ & GENERIC_WRITE; | |
| break; | |
| case _O_WRONLY | _O_RDWR: /* hmmm.. */ | |
| ERR("_O_WRONLY & _O_RDWR in oflag?\n"); | |
| return -1; | |
| } | |
| if (oflag & _O_CREAT) { | |
| if (oflag & _O_EXCL) | |
| creation = CREATE_NEW; | |
| else if (oflag & _O_TRUNC) | |
| creation = CREATE_ALWAYS; | |
| else | |
| creation = OPEN_ALWAYS; | |
| } else /* no _O_CREAT */ { | |
| if (oflag & _O_TRUNC) | |
| creation = TRUNCATE_EXISTING; | |
| else | |
| creation = OPEN_EXISTING; | |
| } | |
| switch( pmode & 0x70 ) { | |
| case _SH_DENYRW: | |
| sharing = 0L; | |
| break; | |
| case _SH_DENYWR: | |
| sharing = FILE_SHARE_READ; | |
| break; | |
| case _SH_DENYRD: | |
| sharing = FILE_SHARE_WRITE; | |
| break; | |
| case _SH_COMPAT: | |
| case _SH_DENYNO: | |
| sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; | |
| break; | |
| default: | |
| ERR("<-- -1 (Unhandled pmode 0x%x)\n", pmode); | |
| return -1; | |
| } | |
| if (oflag & ~(_O_BINARY | _O_TRUNC | _O_EXCL | _O_CREAT | _O_RDWR | _O_WRONLY | _O_NOINHERIT)) | |
| WARN("unsupported oflag 0x%04x\n",oflag); | |
| sa.nLength = sizeof( SECURITY_ATTRIBUTES ); | |
| sa.lpSecurityDescriptor = NULL; | |
| sa.bInheritHandle = (ioflag & _O_NOINHERIT) ? FALSE : TRUE; | |
| ret = (INT_PTR) CreateFileA(pszFile, ioflag, sharing, &sa, creation, FILE_ATTRIBUTE_NORMAL, NULL); | |
| /* TRACE("<-- %d\n", ret); */ | |
| return ret; | |
| } | |
| static UINT sc_cb_read(INT_PTR hf, void *pv, UINT cb) | |
| { | |
| DWORD num_read; | |
| BOOL rslt; | |
| /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */ | |
| rslt = ReadFile((HANDLE) hf, pv, cb, &num_read, NULL); | |
| /* eof and failure both give "-1" return */ | |
| if ((! rslt) || ((cb > 0) && (num_read == 0))) { | |
| /* TRACE("<-- -1\n"); */ | |
| return -1; | |
| } | |
| /* TRACE("<-- %lu\n", num_read); */ | |
| return num_read; | |
| } | |
| static UINT sc_cb_write(INT_PTR hf, void *pv, UINT cb) | |
| { | |
| DWORD num_written; | |
| /* BOOL rv; */ | |
| /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */ | |
| if ( /* (rv = */ WriteFile((HANDLE) hf, pv, cb, &num_written, NULL) /* ) */ | |
| && (num_written == cb)) { | |
| /* TRACE("<-- %lu\n", num_written); */ | |
| return num_written; | |
| } else { | |
| /* TRACE("rv == %d, num_written == %lu, cb == %u\n", rv, num_written,cb); */ | |
| /* TRACE("<-- -1\n"); */ | |
| return -1; | |
| } | |
| } | |
| static int sc_cb_close(INT_PTR hf) | |
| { | |
| /* TRACE("(hf == %d)\n", hf); */ | |
| if (CloseHandle((HANDLE) hf)) | |
| return 0; | |
| else | |
| return -1; | |
| } | |
| static long sc_cb_lseek(INT_PTR hf, long dist, int seektype) | |
| { | |
| DWORD ret; | |
| /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */ | |
| if (seektype < 0 || seektype > 2) | |
| return -1; | |
| if (((ret = SetFilePointer((HANDLE) hf, dist, NULL, seektype)) != INVALID_SET_FILE_POINTER) || !GetLastError()) { | |
| /* TRACE("<-- %lu\n", ret); */ | |
| return ret; | |
| } else { | |
| /* TRACE("<-- -1\n"); */ | |
| return -1; | |
| } | |
| } | |
| #define SIZEOF_MYSTERIO (MAX_PATH*3) | |
| /* FDICopy callbacks */ | |
| static INT_PTR sc_FNNOTIFY_A(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) | |
| { | |
| FILE_IN_CABINET_INFO_A fici; | |
| PSC_HSC_A phsc; | |
| CABINET_INFO_A ci; | |
| FILEPATHS_A fp; | |
| UINT err; | |
| CHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! probably 256... */ | |
| memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO); | |
| TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin); | |
| if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_A_MAGIC)) | |
| phsc = (PSC_HSC_A) pfdin->pv; | |
| else { | |
| ERR("pv %p is not an SC_HSC_A.\n", (pfdin) ? pfdin->pv : NULL); | |
| return -1; | |
| } | |
| switch (fdint) { | |
| case fdintCABINET_INFO: | |
| TRACE("Cabinet info notification\n"); | |
| /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1)); | |
| TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2)); | |
| TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3)); | |
| TRACE(" Cabinet Set#: %d\n", pfdin->setID); | |
| TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */ | |
| WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n"); | |
| ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]); | |
| ci.CabinetPath = pfdin->psz3; | |
| ci.DiskName = pfdin->psz2; | |
| ci.SetId = pfdin->setID; | |
| ci.CabinetNumber = pfdin->iCabinet; | |
| phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0); | |
| return 0; | |
| case fdintPARTIAL_FILE: | |
| TRACE("Partial file notification\n"); | |
| /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */ | |
| return 0; | |
| case fdintCOPY_FILE: | |
| TRACE("Copy file notification\n"); | |
| TRACE(" File name: %s\n", debugstr_a(pfdin->psz1)); | |
| /* TRACE(" File size: %ld\n", pfdin->cb); | |
| TRACE(" File date: %u\n", pfdin->date); | |
| TRACE(" File time: %u\n", pfdin->time); | |
| TRACE(" File attr: %u\n", pfdin->attribs); */ | |
| fici.NameInCabinet = pfdin->psz1; | |
| fici.FileSize = pfdin->cb; | |
| fici.Win32Error = 0; | |
| fici.DosDate = pfdin->date; | |
| fici.DosTime = pfdin->time; | |
| fici.DosAttribs = pfdin->attribs; | |
| memset(&(fici.FullTargetName[0]), 0, MAX_PATH); | |
| err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET, | |
| (UINT) &fici, (UINT) pfdin->psz1); | |
| if (err == FILEOP_DOIT) { | |
| TRACE(" Callback specified filename: %s\n", debugstr_a(&(fici.FullTargetName[0]))); | |
| if (!fici.FullTargetName[0]) { | |
| WARN(" Empty return string causing abort.\n"); | |
| SetLastError(ERROR_PATH_NOT_FOUND); | |
| return -1; | |
| } | |
| return sc_cb_open(&(fici.FullTargetName[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE); | |
| } else { | |
| TRACE(" Callback skipped file.\n"); | |
| return 0; | |
| } | |
| case fdintCLOSE_FILE_INFO: | |
| TRACE("Close file notification\n"); | |
| /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1)); | |
| TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No"); | |
| TRACE(" File hndl: %d\n", pfdin->hf); */ | |
| fp.Source = &(phsc->most_recent_cabinet_name[0]); | |
| fp.Target = pfdin->psz1; | |
| fp.Win32Error = 0; | |
| fp.Flags = 0; | |
| /* the following should be a fixme -- but it occurs too many times */ | |
| WARN("Should set file date/time/attribs (and execute files?)\n"); | |
| err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0); | |
| if (sc_cb_close(pfdin->hf)) | |
| WARN("_close failed.\n"); | |
| if (err) { | |
| SetLastError(err); | |
| return FALSE; | |
| } else | |
| return TRUE; | |
| case fdintNEXT_CABINET: | |
| TRACE("Next cabinet notification\n"); | |
| /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1)); | |
| TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2)); | |
| TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3)); | |
| TRACE(" Cabinet Set#: %d\n", pfdin->setID); | |
| TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */ | |
| ci.CabinetFile = pfdin->psz1; | |
| ci.CabinetPath = pfdin->psz3; | |
| ci.DiskName = pfdin->psz2; | |
| ci.SetId = pfdin->setID; | |
| ci.CabinetNumber = pfdin->iCabinet; | |
| /* remember the new cabinet name */ | |
| strcpy(&(phsc->most_recent_cabinet_name[0]), pfdin->psz1); | |
| err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0])); | |
| if (err) { | |
| SetLastError(err); | |
| return -1; | |
| } else { | |
| if (mysterio[0]) { | |
| /* some easy paranoia. no such carefulness exists on the wide API IIRC */ | |
| mysterio[SIZEOF_MYSTERIO - 1] = '\0'; | |
| strncpy(pfdin->psz3, &(mysterio[0]), 255); | |
| mysterio[255] = '\0'; | |
| } | |
| return 0; | |
| } | |
| default: | |
| FIXME("Unknown notification type %d.\n", fdint); | |
| return 0; | |
| } | |
| } | |
| static INT_PTR sc_FNNOTIFY_W(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) | |
| { | |
| FILE_IN_CABINET_INFO_W fici; | |
| PSC_HSC_W phsc; | |
| CABINET_INFO_W ci; | |
| FILEPATHS_W fp; | |
| UINT err; | |
| int len; | |
| WCHAR mysterio[SIZEOF_MYSTERIO]; /* how big? undocumented! */ | |
| WCHAR buf[MAX_PATH], buf2[MAX_PATH]; | |
| CHAR charbuf[MAX_PATH]; | |
| memset(&(mysterio[0]), 0, SIZEOF_MYSTERIO * sizeof(WCHAR)); | |
| memset(&(buf[0]), 0, MAX_PATH * sizeof(WCHAR)); | |
| memset(&(buf2[0]), 0, MAX_PATH * sizeof(WCHAR)); | |
| memset(&(charbuf[0]), 0, MAX_PATH); | |
| TRACE("(fdint == %d, pfdin == ^%p)\n", fdint, pfdin); | |
| if (pfdin && pfdin->pv && (*((void **) pfdin->pv) == (void *)SC_HSC_W_MAGIC)) | |
| phsc = (PSC_HSC_W) pfdin->pv; | |
| else { | |
| ERR("pv %p is not an SC_HSC_W.\n", (pfdin) ? pfdin->pv : NULL); | |
| return -1; | |
| } | |
| switch (fdint) { | |
| case fdintCABINET_INFO: | |
| TRACE("Cabinet info notification\n"); | |
| /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1)); | |
| TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2)); | |
| TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3)); | |
| TRACE(" Cabinet Set#: %d\n", pfdin->setID); | |
| TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */ | |
| WARN("SPFILENOTIFY_CABINETINFO undocumented: guess implementation.\n"); | |
| ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]); | |
| len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH); | |
| if ((len > MAX_PATH) || (len <= 1)) | |
| buf[0] = '\0'; | |
| ci.CabinetPath = &(buf[0]); | |
| len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH); | |
| if ((len > MAX_PATH) || (len <= 1)) | |
| buf2[0] = '\0'; | |
| ci.DiskName = &(buf2[0]); | |
| ci.SetId = pfdin->setID; | |
| ci.CabinetNumber = pfdin->iCabinet; | |
| phsc->msghandler(phsc->context, SPFILENOTIFY_CABINETINFO, (UINT) &ci, 0); | |
| return 0; | |
| case fdintPARTIAL_FILE: | |
| TRACE("Partial file notification\n"); | |
| /* TRACE(" Partial file name: %s\n", debugstr_a(pfdin->psz1)); */ | |
| return 0; | |
| case fdintCOPY_FILE: | |
| TRACE("Copy file notification\n"); | |
| TRACE(" File name: %s\n", debugstr_a(pfdin->psz1)); | |
| /* TRACE(" File size: %ld\n", pfdin->cb); | |
| TRACE(" File date: %u\n", pfdin->date); | |
| TRACE(" File time: %u\n", pfdin->time); | |
| TRACE(" File attr: %u\n", pfdin->attribs); */ | |
| len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf2[0]), MAX_PATH); | |
| if ((len > MAX_PATH) || (len <= 1)) | |
| buf2[0] = '\0'; | |
| fici.NameInCabinet = &(buf2[0]); | |
| fici.FileSize = pfdin->cb; | |
| fici.Win32Error = 0; | |
| fici.DosDate = pfdin->date; | |
| fici.DosTime = pfdin->time; | |
| fici.DosAttribs = pfdin->attribs; | |
| memset(&(fici.FullTargetName[0]), 0, MAX_PATH * sizeof(WCHAR)); | |
| err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEINCABINET, | |
| (UINT) &fici, (UINT) pfdin->psz1); | |
| if (err == FILEOP_DOIT) { | |
| TRACE(" Callback specified filename: %s\n", debugstr_w(&(fici.FullTargetName[0]))); | |
| if (fici.FullTargetName[0]) { | |
| len = strlenW(&(fici.FullTargetName[0])) + 1; | |
| if ((len > MAX_PATH ) || (len <= 1)) | |
| return 0; | |
| if (!WideCharToMultiByte(CP_ACP, 0, &(fici.FullTargetName[0]), len, &(charbuf[0]), MAX_PATH, 0, 0)) | |
| return 0; | |
| } else { | |
| WARN("Empty buffer string caused abort.\n"); | |
| SetLastError(ERROR_PATH_NOT_FOUND); | |
| return -1; | |
| } | |
| return sc_cb_open(&(charbuf[0]), _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE); | |
| } else { | |
| TRACE(" Callback skipped file.\n"); | |
| return 0; | |
| } | |
| case fdintCLOSE_FILE_INFO: | |
| TRACE("Close file notification\n"); | |
| /* TRACE(" File name: %s\n", debugstr_a(pfdin->psz1)); | |
| TRACE(" Exec file? %s\n", (pfdin->cb) ? "Yes" : "No"); | |
| TRACE(" File hndl: %d\n", pfdin->hf); */ | |
| fp.Source = &(phsc->most_recent_cabinet_name[0]); | |
| len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(buf[0]), MAX_PATH); | |
| if ((len > MAX_PATH) || (len <= 1)) | |
| buf[0] = '\0'; | |
| fp.Target = &(buf[0]); | |
| fp.Win32Error = 0; | |
| fp.Flags = 0; | |
| /* a valid fixme -- but occurs too many times */ | |
| /* FIXME("Should set file date/time/attribs (and execute files?)\n"); */ | |
| err = phsc->msghandler(phsc->context, SPFILENOTIFY_FILEEXTRACTED, (UINT) &fp, 0); | |
| if (sc_cb_close(pfdin->hf)) | |
| WARN("_close failed.\n"); | |
| if (err) { | |
| SetLastError(err); | |
| return FALSE; | |
| } else | |
| return TRUE; | |
| case fdintNEXT_CABINET: | |
| TRACE("Next cabinet notification\n"); | |
| /* TRACE(" Cabinet name: %s\n", debugstr_a(pfdin->psz1)); | |
| TRACE(" Cabinet disk: %s\n", debugstr_a(pfdin->psz2)); | |
| TRACE(" Cabinet path: %s\n", debugstr_a(pfdin->psz3)); | |
| TRACE(" Cabinet Set#: %d\n", pfdin->setID); | |
| TRACE(" Cabinet Cab#: %d\n", pfdin->iCabinet); */ | |
| /* remember the new cabinet name */ | |
| len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz1, -1, &(phsc->most_recent_cabinet_name[0]), MAX_PATH); | |
| if ((len > MAX_PATH) || (len <= 1)) | |
| phsc->most_recent_cabinet_name[0] = '\0'; | |
| ci.CabinetFile = &(phsc->most_recent_cabinet_name[0]); | |
| len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz3, -1, &(buf[0]), MAX_PATH); | |
| if ((len > MAX_PATH) || (len <= 1)) | |
| buf[0] = '\0'; | |
| ci.CabinetPath = &(buf[0]); | |
| len = 1 + MultiByteToWideChar(CP_ACP, 0, pfdin->psz2, -1, &(buf2[0]), MAX_PATH); | |
| if ((len > MAX_PATH) || (len <= 1)) | |
| buf2[0] = '\0'; | |
| ci.DiskName = &(buf2[0]); | |
| ci.SetId = pfdin->setID; | |
| ci.CabinetNumber = pfdin->iCabinet; | |
| err = phsc->msghandler(phsc->context, SPFILENOTIFY_NEEDNEWCABINET, (UINT) &ci, (UINT) &(mysterio[0])); | |
| if (err) { | |
| SetLastError(err); | |
| return -1; | |
| } else { | |
| if (mysterio[0]) { | |
| len = strlenW(&(mysterio[0])) + 1; | |
| if ((len > 255) || (len <= 1)) | |
| return 0; | |
| if (!WideCharToMultiByte(CP_ACP, 0, &(mysterio[0]), len, pfdin->psz3, 255, 0, 0)) | |
| return 0; | |
| } | |
| return 0; | |
| } | |
| default: | |
| FIXME("Unknown notification type %d.\n", fdint); | |
| return 0; | |
| } | |
| } | |
| /*********************************************************************** | |
| * SetupIterateCabinetA (SETUPAPI.@) | |
| */ | |
| BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved, | |
| PSP_FILE_CALLBACK_A MsgHandler, PVOID Context) | |
| { | |
| SC_HSC_A my_hsc; | |
| ERF erf; | |
| CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH], *p; | |
| DWORD fpnsize; | |
| BOOL ret; | |
| TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n", | |
| debugstr_a(CabinetFile), Reserved, MsgHandler, Context); | |
| if (! LoadCABINETDll()) | |
| return FALSE; | |
| memset(&my_hsc, 0, sizeof(SC_HSC_A)); | |
| pszCabinet[0] = '\0'; | |
| pszCabPath[0] = '\0'; | |
| fpnsize = strlen(CabinetFile); | |
| if (fpnsize >= MAX_PATH) { | |
| SetLastError(ERROR_BAD_PATHNAME); | |
| return FALSE; | |
| } | |
| fpnsize = GetFullPathNameA(CabinetFile, MAX_PATH, &(pszCabPath[0]), &p); | |
| if (fpnsize > MAX_PATH) { | |
| SetLastError(ERROR_BAD_PATHNAME); | |
| return FALSE; | |
| } | |
| if (p) { | |
| strcpy(pszCabinet, p); | |
| *p = '\0'; | |
| } else { | |
| strcpy(pszCabinet, CabinetFile); | |
| pszCabPath[0] = '\0'; | |
| } | |
| TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet)); | |
| /* remember the cabinet name */ | |
| strcpy(&(my_hsc.most_recent_cabinet_name[0]), pszCabinet); | |
| my_hsc.magic = SC_HSC_A_MAGIC; | |
| my_hsc.msghandler = MsgHandler; | |
| my_hsc.context = Context; | |
| my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read, | |
| sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf ); | |
| if (!my_hsc.hfdi) return FALSE; | |
| ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, | |
| 0, sc_FNNOTIFY_A, NULL, &my_hsc) ) ? TRUE : FALSE; | |
| sc_FDIDestroy(my_hsc.hfdi); | |
| return ret; | |
| } | |
| /*********************************************************************** | |
| * SetupIterateCabinetW (SETUPAPI.@) | |
| */ | |
| BOOL WINAPI SetupIterateCabinetW(PCWSTR CabinetFile, DWORD Reserved, | |
| PSP_FILE_CALLBACK_W MsgHandler, PVOID Context) | |
| { | |
| CHAR pszCabinet[MAX_PATH], pszCabPath[MAX_PATH]; | |
| UINT len; | |
| SC_HSC_W my_hsc; | |
| ERF erf; | |
| WCHAR pszCabPathW[MAX_PATH], *p; | |
| DWORD fpnsize; | |
| BOOL ret; | |
| TRACE("(CabinetFile == %s, Reserved == %lu, MsgHandler == ^%p, Context == ^%p)\n", | |
| debugstr_w(CabinetFile), Reserved, MsgHandler, Context); | |
| if (!LoadCABINETDll()) | |
| return FALSE; | |
| if (!CabinetFile) return FALSE; | |
| memset(&my_hsc, 0, sizeof(SC_HSC_W)); | |
| fpnsize = GetFullPathNameW(CabinetFile, MAX_PATH, pszCabPathW, &p); | |
| if (fpnsize > MAX_PATH) { | |
| SetLastError(ERROR_BAD_PATHNAME); | |
| return FALSE; | |
| } | |
| if (p) { | |
| strcpyW(my_hsc.most_recent_cabinet_name, p); | |
| *p = 0; | |
| len = WideCharToMultiByte(CP_ACP, 0, pszCabPathW, -1, pszCabPath, | |
| MAX_PATH, 0, 0); | |
| if (!len) return FALSE; | |
| } else { | |
| strcpyW(my_hsc.most_recent_cabinet_name, CabinetFile); | |
| pszCabPath[0] = '\0'; | |
| } | |
| len = WideCharToMultiByte(CP_ACP, 0, my_hsc.most_recent_cabinet_name, -1, | |
| pszCabinet, MAX_PATH, 0, 0); | |
| if (!len) return FALSE; | |
| TRACE("path: %s, cabfile: %s\n", | |
| debugstr_a(pszCabPath), debugstr_a(pszCabinet)); | |
| my_hsc.magic = SC_HSC_W_MAGIC; | |
| my_hsc.msghandler = MsgHandler; | |
| my_hsc.context = Context; | |
| my_hsc.hfdi = sc_FDICreate( sc_cb_alloc, sc_cb_free, sc_cb_open, sc_cb_read, | |
| sc_cb_write, sc_cb_close, sc_cb_lseek, cpuUNKNOWN, &erf ); | |
| if (!my_hsc.hfdi) return FALSE; | |
| ret = ( sc_FDICopy(my_hsc.hfdi, pszCabinet, pszCabPath, | |
| 0, sc_FNNOTIFY_W, NULL, &my_hsc) ) ? TRUE : FALSE; | |
| sc_FDIDestroy(my_hsc.hfdi); | |
| return ret; | |
| } | |
| /*********************************************************************** | |
| * DllMain | |
| * | |
| * PARAMS | |
| * hinstDLL [I] handle to the DLL's instance | |
| * fdwReason [I] | |
| * lpvReserved [I] reserved, must be NULL | |
| * | |
| * RETURNS | |
| * Success: TRUE | |
| * Failure: FALSE | |
| */ | |
| BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) | |
| { | |
| switch (fdwReason) { | |
| case DLL_PROCESS_ATTACH: | |
| DisableThreadLibraryCalls(hinstDLL); | |
| OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); | |
| if (!GetVersionExW(&OsVersionInfo)) | |
| return FALSE; | |
| break; | |
| case DLL_PROCESS_DETACH: | |
| UnloadCABINETDll(); | |
| break; | |
| } | |
| return TRUE; | |
| } |