https://msdn.microsoft.com/en-us/library/ff797944(v=vs.85).aspx
#include <stdio.h>
#include <Windows.h>
#include <Fdi.h>
#include <fcntl.h>
#include <strsafe.h>
#include <io.h>
#pragma comment(lib,"cabinet.lib")
FNALLOC(fnMemAlloc)
{
return malloc(cb);
}
FNFREE(fnMemFree)
{
free(pv);
}
FNOPEN(fnFileOpen)
{
HANDLE hFile = NULL;
DWORD dwDesiredAccess = 0;
DWORD dwCreationDisposition = 0;
UNREFERENCED_PARAMETER(pmode);
if ( oflag & _O_RDWR )
{
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
}
else if ( oflag & _O_WRONLY )
{
dwDesiredAccess = GENERIC_WRITE;
}
else
{
dwDesiredAccess = GENERIC_READ;
}
if ( oflag & _O_CREAT )
{
dwCreationDisposition = CREATE_ALWAYS;
}
else
{
dwCreationDisposition = OPEN_EXISTING;
}
hFile = CreateFileA(pszFile,
dwDesiredAccess,
FILE_SHARE_READ,
NULL,
dwCreationDisposition,
FILE_ATTRIBUTE_NORMAL,
NULL);
return (INT_PTR)hFile;
}
FNREAD(fnFileRead)
{
DWORD dwBytesRead = 0;
if ( ReadFile((HANDLE)hf, pv, cb, &dwBytesRead, NULL) == FALSE )
{
dwBytesRead = (DWORD)-1L;
}
return dwBytesRead;
}
FNWRITE(fnFileWrite)
{
DWORD dwBytesWritten = 0;
if ( WriteFile((HANDLE)hf, pv, cb, &dwBytesWritten, NULL) == FALSE )
{
dwBytesWritten = (DWORD)-1;
}
return dwBytesWritten;
}
FNCLOSE(fnFileClose)
{
return ( CloseHandle((HANDLE)hf) == TRUE ) ? 0 : -1;
}
FNSEEK(fnFileSeek)
{
return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
}
BOOL ExtractCabinetFiles(
LPSTR pszCabinetName,
LPSTR pszCabinetPath,
LPSTR pszDestinationDir
);
LPCSTR FDIErrorToString(FDIERROR err);
FNFDINOTIFY(fnNotify)
{
INT_PTR iResult = 0;
switch(fdint)
{
case fdintCOPY_FILE:
{
CHAR cResponse;
CHAR pszNewFileName[MAX_PATH];
LPSTR pszFileName;
HRESULT hr = S_OK;
//TODO Validate if file name contains characters
//that are not allowed by the file system.
//Remove any directory structure from the file name in cabinet
pszFileName = strrchr(pfdin->psz1, '\\');
if ( pszFileName == NULL )
{
pszFileName = pfdin->psz1;
}
//Append the destination directory to the file name.
hr = StringCchPrintfA(pszNewFileName,
ARRAYSIZE(pszNewFileName),
"%s\\%s",
pfdin->pv, //Destination directory provided by user
pszFileName);
if ( SUCCEEDED(hr) )
{
printf("Extract File \"%s\" (Size: %d bytes) -> \"%s\"? (Yes/No/Quit): ",
pfdin->psz1,
pfdin->cb,
pszNewFileName); //uncompressed size of file
do
{
cResponse = (CHAR)getchar();
cResponse = (CHAR)toupper(cResponse);
} while ( cResponse != 'Y' && cResponse != 'N' && cResponse != 'Q');
printf("\n");
if ( cResponse == 'Y' )
{
iResult = fnFileOpen(pszNewFileName, _O_WRONLY | _O_CREAT, 0);
}
else if ( cResponse == 'Q' )
{
iResult = -1;
}
}
else
{
printf("Failed to append file name \"%s\" to destination directory \"%s\"\n",
pszFileName,
pfdin->pv);
iResult = -1;
}
break;
}
case fdintCLOSE_FILE_INFO:
{
FILETIME fileTime;
FILETIME fileTimeLocal;
FILE_BASIC_INFO fbi;
//Converts MS-DOS date and time values to a file time
if ( DosDateTimeToFileTime(pfdin->date, pfdin->time, &fileTime) == TRUE &&
LocalFileTimeToFileTime(&fileTime, &fileTimeLocal) == TRUE )
{
fbi.CreationTime.LowPart = fileTimeLocal.dwLowDateTime;
fbi.CreationTime.HighPart = fileTimeLocal.dwHighDateTime;
fbi.LastWriteTime.QuadPart = -1;
fbi.ChangeTime.QuadPart = -1;
fbi.LastAccessTime.QuadPart = -1;
//Retrieve the file attributes.
fbi.FileAttributes = pfdin->attribs;
fbi.FileAttributes &= ( _A_RDONLY | _A_HIDDEN |
_A_SYSTEM | _A_ARCH );
//Set the date, time and attributes
SetFileInformationByHandle((HANDLE)pfdin->hf,
FileBasicInfo,
&fbi,
sizeof(FILE_BASIC_INFO));
}
iResult = !fnFileClose(pfdin->hf);
break;
}
case fdintNEXT_CABINET:
if ( pfdin->fdie != FDIERROR_NONE )
{
printf("Failed to process the spanned cabinet file \"%s\""
"with error code %d: %s\n",
pfdin->psz1,
pfdin->fdie,
FDIErrorToString(pfdin->fdie));
iResult = -1;
}
break;
case fdintPARTIAL_FILE:
iResult = 0;
break;
case fdintCABINET_INFO:
iResult = 0;
break;
case fdintENUMERATE:
iResult = 0;
break;
default:
iResult = -1;
break;
}
return iResult;
}
int main(INT argc, CHAR *argv[])
{
INT iExitCode = -1;
HRESULT hr = S_OK;
HANDLE hFile = INVALID_HANDLE_VALUE;
LPSTR pszCabinetName = NULL; //the cabinet name
LPSTR pszDestinationDir = NULL; //the destination directory
CHAR pszCabinetPath[MAX_PATH]; //the cabinet path
WIN32_FIND_DATAA findFileData;
(VOID)HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
if ( argc != 3 )
{
printf("Usage: %s [cabinet] [destination]\n", argv[0]);
goto CLEANUP;
}
//Split the cabinet name and path
pszCabinetName = strrchr(argv[1], '\\');
if ( pszCabinetName == NULL )
{
pszCabinetName = argv[1];
pszCabinetPath[0] = '\0';
}
else
{
pszCabinetName++;
hr = StringCchCopyA(pszCabinetPath, MAX_PATH, argv[1]);
if ( SUCCEEDED(hr) )
{
pszCabinetPath[(INT)( pszCabinetName - argv[1] )] = '\0';
}
else
{
printf("Failed to split the cabinet name \"%s\".\n",
argv[1]);
goto CLEANUP;
}
}
pszDestinationDir = argv[2]; //Destination directory
//Determine whether the destination directory provided by the user exists
hFile = FindFirstFileA(pszDestinationDir, &findFileData);
if ( hFile == INVALID_HANDLE_VALUE )
{
printf("Destination directory \"%s\" does not exist.\n",
pszDestinationDir);
goto CLEANUP;
}
if ( (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FALSE )
{
printf("Destination, \"%s\", is not a directory.\n",
pszDestinationDir);
goto CLEANUP;
}
//Get the files from the cabinet
if ( ExtractCabinetFiles(pszCabinetName, pszCabinetPath, pszDestinationDir) == TRUE )
{
iExitCode = 0;
}
CLEANUP:
if ( hFile != INVALID_HANDLE_VALUE )
{
FindClose(hFile);
}
return iExitCode;
}
BOOL ExtractCabinetFiles(
LPSTR pszCabinetName,
LPSTR pszCabinetPath,
LPSTR pszDestinationDir
)
{
ERF erf; //FDI error structure
HFDI hfdi = NULL; //FDI handle
BOOL bSuccessful = FALSE;
//Creates the FDI context
hfdi = FDICreate(fnMemAlloc, //function to allocate memory
fnMemFree, //function to free memory
fnFileOpen, //function to open a file
fnFileRead, //function to read data from a file
fnFileWrite, //function to write data to a file
fnFileClose, //function to close a file
fnFileSeek, //function to move the file pointer
cpuUNKNOWN, //only used by the 16-bit version of FDI
&erf); //pointer the FDI error structure
if ( hfdi == NULL )
{
printf("FDICreate failed with error code %d: %s\n",
erf.erfOper,
FDIErrorToString((FDIERROR)erf.erfOper));
goto CLEANUP;
}
//Extract the files from the cabinet
if ( FDICopy(hfdi, //FDI handle
pszCabinetName, //the cabinet name
pszCabinetPath, //the cabinet path
0, //not used, set to zero
fnNotify, //function for notifications
NULL, //not used, set to NULL
pszDestinationDir) == FALSE )//this value is application-specific
{
printf("FDICopy failed with error code %d: %s\n",
erf.erfOper,
FDIErrorToString((FDIERROR)erf.erfOper));
goto CLEANUP;
}
bSuccessful = TRUE;
CLEANUP:
//Destory the FDI context
if ( hfdi != NULL )
{
if ( FDIDestroy(hfdi) != TRUE )
{
printf("FDIDestroy failed with error code %d: %s\n",
erf.erfOper,
FDIErrorToString((FDIERROR)erf.erfOper));
}
}
return bSuccessful;
}
LPCSTR FDIErrorToString(FDIERROR err)
{
switch (err)
{
case FDIERROR_NONE:
return "No error";
case FDIERROR_CABINET_NOT_FOUND:
return "Cabinet not found";
case FDIERROR_NOT_A_CABINET:
return "Not a cabinet";
case FDIERROR_UNKNOWN_CABINET_VERSION:
return "Unknown cabinet version";
case FDIERROR_CORRUPT_CABINET:
return "Corrupt cabinet";
case FDIERROR_ALLOC_FAIL:
return "Memory allocation failed";
case FDIERROR_BAD_COMPR_TYPE:
return "Unknown compression type";
case FDIERROR_MDI_FAIL:
return "Failure decompressing data";
case FDIERROR_TARGET_FILE:
return "Failure writing to target file";
case FDIERROR_RESERVE_MISMATCH:
return "Cabinets in set have different RESERVE sizes";
case FDIERROR_WRONG_CABINET:
return "Cabinet returned on fdintNEXT_CABINET is incorrect";
case FDIERROR_USER_ABORT:
return "Application aborted";
default:
return "Unknown error";
}
}
当然也可以使用SetupIterateCabinet ,Demo见https://support.microsoft.com/zh-cn/help/189085/howto-use-the-setupapi-s-setupiteratecabinet-function