从一个或多个文件创建 .cab 压缩包





5.00/5 (11投票s)
MakeCab 工具内置于 Windows 中,但使用它创建 .cab 压缩包有点棘手。为什么不编写一个小程序来为你完成这项任务呢?
引言
微软要求希望将其驱动程序认证为 Windows 10 的开发者,需要将驱动程序文件打包成单个 cab 并进行代码签名。我正在寻找一种以编程方式实现的方法。我找到了 MakeCab 工具,但初步看来,它只允许传递一个文件参数,所以我正在寻找将多个文件打包的最简单方法。
背景
.Cab 格式 似乎有点过时了。它是由微软在需要将属于安装应用程序的文件打包到磁盘时创建的。
我阅读了 Cabinet 文件压缩和提取 这篇文章。
我希望找到一种更简单的方法来创建 .cab 文件,这促使我写这篇文章。
即使在今天,当创建一个 .cab 文件时,它也会在名为“Disk1”、“Disk2”等文件夹中创建。我的代码也通过允许简单的函数调用来简化这一点。
CreateCabFromFiles(TargetCabName, n, File1,File2,File3, ...);
例如
CreateCabFromFiles(L"test.cab",5,L"aaa.txt",L"bbb.txt",L"ccc.txt",L"ddd.txt",L"eee.txt");
目标 cab 文件将放置在文件的旁边。
关于 MakeCab 的另一个有趣的事实是,将多个文件添加到新的 .cab 的唯一方法是创建一个包含所有要添加的文件列表的文件。我的函数为你执行此操作。然后它会清理,你只会找到创建的 .cab。
构建块
我将首先向你展示我们在 Secured Globe, Inc. 中使用的一些构建块。首先,一个用于执行命令的函数,就像它已在 CMD 中键入并执行一样,收集结果并将其显示给你。如果发生错误,则编写友好的错误描述。
bool DoRun(WCHAR *command)
{
DWORD retSize;
LPTSTR pTemp = NULL;
TCHAR Command[BUFSIZE] = L"";
DeleteFile(RESULTS_FILE);
_tcscpy_s(Command, L"/C ");
_tcscat_s(Command, command);
_tcscat_s(Command, L" >");
_tcscat_s(Command, RESULTS_FILE);
wprintf(L"Calling:\n%s\n", Command);
bool result = ShellExecute(GetActiveWindow(), L"OPEN", L"cmd", Command, NULL, 0L);
Sleep(1000);
if (result)
{
std::FILE *fp = _wfopen(RESULTS_FILE, L"rb");
if (fp)
{
std::string contents;
std::fseek(fp, 0, SEEK_END);
contents.resize(std::ftell(fp));
std::rewind(fp);
std::fread(&contents[0], 1, contents.size(), fp);
std::fclose(fp);
CString temp1 = (CString)(CStringA)(contents.c_str());
wprintf(L"Result:\n%s\n", temp1.GetBuffer());
}
}
else
{
retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
GetLastError(),
LANG_NEUTRAL,
(LPTSTR)&pTemp,
0,
NULL);
return(L"Error: %s\n", pTemp);
}
}
基本上,我们将生成文件列表,然后使用适当的参数调用 MakeCab
并返回结果。
CreateCabFromFiles 函数
有几个 const
需要定义
#define RESULTS_FILE L"result.txt"
#define FILELIST_FILE L"files.txt"
#define MAKECAB_COMMAND L"makecab /d CabinetName1=%s /f %s"
#define CAB_DEF_FOLDER L"disk1"
我们假设对于函数的范围,将创建一个名为“disk1
”的单个“磁盘”。
这是 CreateCabFromFiles()
函数
//
bool CreateCabFromFiles(LPWSTR TargetCab, int argc, ...)
{
va_list ptr;
va_start(ptr, argc);
FILE *fp = _wfopen(FILELIST_FILE, L"w");
if (fp)
{
for (int i = 0; i < argc; i++)
{
LPWSTR *filetowrite = va_arg(ptr, LPWSTR *);
fwprintf(fp, L"%s\n", filetowrite);
}
fclose(fp);
CString command;
command.Format(MAKECAB_COMMAND, TargetCab, FILELIST_FILE);
if (DoRun(command.GetBuffer()))
{
if (CopyFile(CAB_DEF_FOLDER + (CString)L"\\" + TargetCab, TargetCab, FALSE))
{
wprintf(L"Created cab file: %s\n", TargetCab);
DeleteFile(CAB_DEF_FOLDER + (CString)L"\\" + TargetCab);
RemoveDirectory(CAB_DEF_FOLDER);
DeleteFile(FILELIST_FILE);
return true;
}
}
}
return true;
}
//
清理
为了避免打开“磁盘”并查找创建的 .cab,以及删除为正确“馈送”MakeCab
而创建的文件,此函数清理包括以下步骤
- .cab 文件从“disk1”复制到当前路径。
- “disk1”文件夹被清空并删除。
- 用于托管要添加的文件列表的文件被删除。
- 用于我们的
DoRun()
函数的“results”文件也被删除。
测试代码
我使用了以下函数调用,发现它在 3 个驱动程序文件旁边创建了“drivers.cab”。
CreateCab(L"drivers.cab", 3,L"drv.sys", L"drv.inf", L"drv.cat");