diff --git a/dlls/setupapi/Makefile.in b/dlls/setupapi/Makefile.in index 24ba96d27e8..52515dbc96c 100644 --- a/dlls/setupapi/Makefile.in +++ b/dlls/setupapi/Makefile.in @@ -20,6 +20,7 @@ C_SRCS = \ install.c \ parser.c \ queue.c \ + setupcab.c \ stubs.c C_SRCS16 = \ diff --git a/dlls/setupapi/setupapi_private.h b/dlls/setupapi/setupapi_private.h index 10d0eeb5293..6c556442cf5 100644 --- a/dlls/setupapi/setupapi_private.h +++ b/dlls/setupapi/setupapi_private.h @@ -64,4 +64,8 @@ struct callback_WtoA_context UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, UINT_PTR, UINT_PTR ); +/* from msvcrt/sys/stat.h */ +#define _S_IWRITE 0x0080 +#define _S_IREAD 0x0100 + #endif /* __SETUPAPI_PRIVATE_H */ diff --git a/dlls/setupapi/setupcab.c b/dlls/setupapi/setupcab.c new file mode 100644 index 00000000000..f49e594f153 --- /dev/null +++ b/dlls/setupapi/setupcab.c @@ -0,0 +1,677 @@ +/* + * 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 --debugmsg +setupapi + * + */ + +#include "string.h" +#include "stdlib.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" + +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_INFOA fici; + PSC_HSC_A phsc; + CABINET_INFOA 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."); + 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_INFOW fici; + PSC_HSC_W phsc; + CABINET_INFOW 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 CabinetFile_A[MAX_PATH]; + UINT32 len; + SC_HSC_W 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_w(CabinetFile), Reserved, MsgHandler, Context); + + if (!LoadCABINETDll()) + return FALSE; + + if (!CabinetFile) return FALSE; + if (!WideCharToMultiByte(CP_ACP, 0, CabinetFile, -1, CabinetFile_A, MAX_PATH, 0, 0)) + return FALSE; + + memset(&my_hsc, 0, sizeof(SC_HSC_W)); + pszCabinet[0] = '\0'; + pszCabPath[0] = '\0'; + + fpnsize = GetFullPathNameA(CabinetFile_A, 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_A); + pszCabPath[0] = '\0'; + } + + TRACE("path: %s, cabfile: %s\n", debugstr_a(pszCabPath), debugstr_a(pszCabinet)); + + /* remember the cabinet name */ + len = 1 + MultiByteToWideChar(CP_ACP, 0, pszCabinet, -1, + &(my_hsc.most_recent_cabinet_name[0]), MAX_PATH); + if (len > MAX_PATH) + return FALSE; + else if (len <= 1) + my_hsc.most_recent_cabinet_name[0] = '\0'; + 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); + break; + case DLL_PROCESS_DETACH: + UnloadCABINETDll(); + break; + } + + return TRUE; +} diff --git a/dlls/setupapi/setupx_main.c b/dlls/setupapi/setupx_main.c index 774b28cd418..4daa621cc3e 100644 --- a/dlls/setupapi/setupx_main.c +++ b/dlls/setupapi/setupx_main.c @@ -70,7 +70,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(setupapi); - /*********************************************************************** * SURegOpenKey (SETUPX.47) */ diff --git a/dlls/setupapi/stubs.c b/dlls/setupapi/stubs.c index 7619f526699..f7b7b063944 100644 --- a/dlls/setupapi/stubs.c +++ b/dlls/setupapi/stubs.c @@ -24,28 +24,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(setupapi); - -/*********************************************************************** - * SetupIterateCabinetA (SETUPAPI.@) - */ -BOOL WINAPI SetupIterateCabinetA(PCSTR CabinetFile, DWORD Reserved, - PSP_FILE_CALLBACK_A MsgHandler, PVOID Context) -{ - FIXME("not implemented (setupapi.dll) \n"); - return 0; -} - -/*********************************************************************** - * SetupIterateCabinetW (SETUPAPI.@) - */ -BOOL WINAPI SetupIterateCabinetW(PWSTR CabinetFile, DWORD Reserved, - PSP_FILE_CALLBACK_W MsgHandler, PVOID Context) -{ - FIXME("not implemented (setupapi.dll) \n"); - return 0; -} - - /*********************************************************************** * TPWriteProfileString (SETUPX.62) */ diff --git a/include/setupapi.h b/include/setupapi.h index 0c85a90cdee..e0fd1a3eec1 100644 --- a/include/setupapi.h +++ b/include/setupapi.h @@ -153,6 +153,48 @@ typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATAW DECL_WINELIB_TYPE_AW(SP_DEVICE_INTERFACE_DETAIL_DATA) DECL_WINELIB_TYPE_AW(PSP_DEVICE_INTERFACE_DETAIL_DATA) +typedef struct _FILE_IN_CABINET_INFOA { + LPCSTR NameInCabinet; + DWORD FileSize; + DWORD Win32Error; + WORD DosDate; + WORD DosTime; + WORD DosAttribs; + CHAR FullTargetName[MAX_PATH]; +} FILE_IN_CABINET_INFOA, *PFILE_IN_CABINET_INFOA; + +typedef struct _FILE_IN_CABINET_INFOW { + LPCWSTR NameInCabinet; + DWORD FileSize; + DWORD Win32Error; + WORD DosDate; + WORD DosTime; + WORD DosAttribs; + WCHAR FullTargetName[MAX_PATH]; +} FILE_IN_CABINET_INFOW, *PFILE_IN_CABINET_INFOW; + +DECL_WINELIB_TYPE_AW(FILE_IN_CABINET_INFO) +DECL_WINELIB_TYPE_AW(PFILE_IN_CABINET_INFO) + +typedef struct _CABINET_INFOA { + PCSTR CabinetPath; + PCSTR CabinetFile; + PCSTR DiskName; + USHORT SetId; + USHORT CabinetNumber; +} CABINET_INFOA, *PCABINET_INFOA; + +typedef struct _CABINET_INFOW { + PCWSTR CabinetPath; + PCWSTR CabinetFile; + PCWSTR DiskName; + USHORT SetId; + USHORT CabinetNumber; +} CABINET_INFOW, *PCABINET_INFOW; + +DECL_WINELIB_TYPE_AW(CABINET_INFO); +DECL_WINELIB_TYPE_AW(PCABINET_INFO); + #define INF_STYLE_NONE 0x00 #define INF_STYLE_OLDNT 0x01 #define INF_STYLE_WIN4 0x02 @@ -542,6 +584,8 @@ BOOL WINAPI SetupInstallFromInfSectionA(HWND,HINF,PCSTR,UINT,HKEY,PCSTR,UINT BOOL WINAPI SetupInstallFromInfSectionW(HWND,HINF,PCWSTR,UINT,HKEY,PCWSTR,UINT, PSP_FILE_CALLBACK_W,PVOID,HDEVINFO,PSP_DEVINFO_DATA); #define SetupInstallFromInfSection WINELIB_NAME_AW(SetupInstallFromInfSection) - +BOOL WINAPI SetupIterateCabinetA(PCSTR, DWORD, PSP_FILE_CALLBACK_A, PVOID); +BOOL WINAPI SetupIterateCabinetW(PCWSTR, DWORD, PSP_FILE_CALLBACK_W, PVOID); +#define SetupIterateCabinet WINELIB_NAME_AW(SetupIterateCabinet) #endif /* _INC_SETUPAPI */