使用FDICreate、FDICopy分离cab包

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值