Alexandre, please do not apply. This is a crack at implementing SetupIterateCabinet using the stuff in fdi.c. I'd appreciate some comments on this code, esp. from any SETUPAPI experts out there. Would love to hear if I have not done things in a properly "SETUPAPI" way, i.e., am I supposed to be performing certain logging or memory allocation rituals, anything like that? This code works under laboratory conditions. Also, I don't know of anything in the wild that calls this API. Real-world examples, preferably free ones, would be appreciated, if anyone happens to know of any, against which I could test. LICENSE: Bugroff -- diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.test/dlls/setupapi/Makefile.in ./dlls/setupapi/Makefile.in --- ../wine.test/dlls/setupapi/Makefile.in 2003-07-30 23:23:26.000000000 -0500 +++ ./dlls/setupapi/Makefile.in 2003-07-31 21:24:43.000000000 -0500 @@ -4,7 +4,7 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = setupapi.dll -IMPORTS = user32 version advapi32 kernel32 ntdll +IMPORTS = user32 version advapi32 kernel32 ntdll msvcrt ALTNAMES = setupx.dll EXTRALIBS = $(LIBUNICODE) @@ -20,6 +20,7 @@ install.c \ parser.c \ queue.c \ + setupcab.c \ setupx_main.c \ stubs.c \ virtcopy.c diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.test/dlls/setupapi/setupapi_private.h ./dlls/setupapi/setupapi_private.h --- ../wine.test/dlls/setupapi/setupapi_private.h 2003-07-30 23:23:26.000000000 -0500 +++ ./dlls/setupapi/setupapi_private.h 2003-08-01 23:05:49.000000000 -0500 @@ -64,4 +64,17 @@ UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification, UINT_PTR, UINT_PTR ); +void UnloadCABINETDll(); + +/* from include/msvcrt/io.h */ +extern int _open(const char*,int,...); +extern int _close(int); +extern int _read(int,void*,unsigned int); +extern int _write(int,const void*,unsigned int); +extern long _lseek(int,long,int); + +/* from msvcrt/sys/stat.h */ +#define _S_IWRITE 0x0080 +#define _S_IREAD 0x0100 + #endif /* __SETUPAPI_PRIVATE_H */ diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.test/dlls/setupapi/setupx_main.c ./dlls/setupapi/setupx_main.c --- ../wine.test/dlls/setupapi/setupx_main.c 2003-07-30 23:23:26.000000000 -0500 +++ ./dlls/setupapi/setupx_main.c 2003-07-29 21:50:55.000000000 -0500 @@ -70,6 +70,32 @@ WINE_DEFAULT_DEBUG_CHANNEL(setupapi); +/*********************************************************************** + * 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; +} /*********************************************************************** * SURegOpenKey (SETUPX.47) diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.test/dlls/setupapi/stubs.c ./dlls/setupapi/stubs.c --- ../wine.test/dlls/setupapi/stubs.c 2003-07-30 23:23:26.000000000 -0500 +++ ./dlls/setupapi/stubs.c 2003-07-29 20:16:43.000000000 -0500 @@ -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 -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.test/include/setupapi.h ./include/setupapi.h --- ../wine.test/include/setupapi.h 2003-07-30 23:23:26.000000000 -0500 +++ ./include/setupapi.h 2003-08-01 23:05:42.000000000 -0500 @@ -153,6 +153,48 @@ 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 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 */ --- /dev/null 1969-12-31 18:00:00.000000000 -0600 +++ ./dlls/setupapi/setupcab.c 2003-08-02 06:38:53.000000000 -0500 @@ -0,0 +1,554 @@ +/* + * 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 + */ + +#include "string.h" +#include "stdlib.h" +#include "winnls.h" +#include "setupapi.h" +#include "setupapi_private.h" +#include "fdi.h" + +#include "msvcrt/fcntl.h" + +#include "wine/unicode.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); + +BOOL LoadCABINETDll() +{ + 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; +} + +void UnloadCABINETDll() +{ + if (CABINET_hInstance) { + FreeLibrary(CABINET_hInstance); + CABINET_hInstance = 0; + } +} + +/* FDICreate callbacks */ + +__cdecl void *sc_FNALLOC(ULONG cb) +{ + return malloc(cb); +} + +__cdecl void sc_FNFREE(void *pv) +{ + free(pv); +} + +__cdecl INT_PTR sc_FNOPEN(char *pszFile, int oflag, int pmode) +{ + INT_PTR ret = 0; + /* TRACE("(pszFile == %s, oflag == %d, pmode == %d)\n", debugstr_a(pszFile), oflag, pmode); */ + ret = _open(pszFile, oflag, pmode); + /* TRACE("<-- %d\n", ret); */ + return ret; +} + +__cdecl UINT sc_FNREAD(INT_PTR hf, void *pv, UINT cb) +{ + /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */ + return _read(hf, pv, cb); +} + +__cdecl UINT sc_FNWRITE(INT_PTR hf, void *pv, UINT cb) +{ + /* TRACE("(hf == %d, pv == ^%p, cb == %u)\n", hf, pv, cb); */ + return _write(hf, pv, cb); +} + +__cdecl int sc_FNCLOSE(INT_PTR hf) +{ + /* TRACE("(hf == %d)\n", hf); */ + return _close(hf); +} + +__cdecl long sc_FNSEEK(INT_PTR hf, long dist, int seektype) +{ + /* TRACE("(hf == %d, dist == %ld, seektype == %d)\n", hf, dist, seektype); */ + return _lseek(hf, dist, seektype); +} + +#define SIZEOF_MYSTERIO (MAX_PATH*3) + +/* FDICopy callbacks */ + +__cdecl 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 _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; + /* 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 (_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; + } +} + +__cdecl 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 _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 (_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_FNALLOC, sc_FNFREE, sc_FNOPEN, sc_FNREAD, + sc_FNWRITE, sc_FNCLOSE, sc_FNSEEK, 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]; + CHAR *CabinetFile_A = &(_CabinetFile_A[0]); + 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) { + len = strlenW(CabinetFile) + 1; + if ((len > MAX_PATH ) || (len <= 1)) + return FALSE; + if (!WideCharToMultiByte(CP_ACP, 0, CabinetFile, len, CabinetFile_A, MAX_PATH, 0, 0)) + return FALSE; + } else + return FALSE; + + memset(&my_hsc, 0, sizeof(SC_HSC_W)); + pszCabinet[0] = '\0'; + pszCabPath[0] = '\0'; + + fpnsize = strlen(CabinetFile_A); + if (fpnsize >= MAX_PATH) { + SetLastError(ERROR_BAD_PATHNAME); + return FALSE; + } + + 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_FNALLOC, sc_FNFREE, sc_FNOPEN, sc_FNREAD, + sc_FNWRITE, sc_FNCLOSE, sc_FNSEEK, 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; +} + -- gmt "Microsoft is committed to making cabinet files an open technology" http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncabsdk/html/cabdl.asp