制作 MSI 安装程序少不了 CAB 文件,CAB 文件可以对需要安装程序进行压缩,以达到快速分发新程序的目的,通过参考高人的代码和 MSDN 整理了一套 Cabinet 文件的操作实现类,使用这些类可以:
1、将多个文件制作为一个 CAB 文件
2、将一个目录直接打包为 CAB 文件
3、将磁盘上的 CAB 文件中解包出文件
4、从内存中的 CAB 数据流中解包出文件
5、从程序的 CAB 资源中解包出文件
6、通过策略模式可以对 CAB 文件中的数据进行加解密
通过该套封装类,已经实现了制作单文件的安装程序 Setup.exe ,该程序使用 /Create 参数启动时根据指定的目录打包为一个 CAB 文件并将该文件加入到特定的资源中生成一个用于安装的 Setup.exe(同一个程序,如果没有指定参数那么根据有无 CAB 资源来决定是进行“安装”还是“卸载”),在程序中添加资源很简单,参考下面的例子代码:
//--------------------------------------------------------------------------
// 概述:
// 根据指定的程序和 CAB 文件创建安装程序
// 参数:
// szInstall - [ IN ] 生产的目标安装程序路径
// szPackage - [ IN ] 安装程序使用的 CAB 文件路径
// szProgram - [ IN ] 原始的安装程序路径
BOOL CreateSetup(LPTSTR szInstall, LPTSTR szPackage, LPTSTR szProgram);
// 概述:
// 根据指定的程序和 CAB 文件创建安装程序
// 参数:
// szInstall - [ IN ] 生产的目标安装程序路径
// szPackage - [ IN ] 安装程序使用的 CAB 文件路径
// szProgram - [ IN ] 原始的安装程序路径
BOOL CreateSetup(LPTSTR szInstall, LPTSTR szPackage, LPTSTR szProgram);
下面是该函数的实现:
BOOL CPagePackage::CreateSetup(LPTSTR szInstall, LPTSTR szPackage, LPTSTR szProgram)
{
// 复制安装程序到目标路径处
BOOL bCopy = CopyFile(szProgram, szInstall, FALSE);
CHK_EXP_RET( FALSE == bCopy , ShowSystemError() );
// 打开 CAB 文件
HANDLE hFile = CreateFile(szPackage, GENERIC_READ, 0, 0, OPEN_ALWAYS, 0, 0);
CHK_EXP_RET( hFile == INVALID_HANDLE_VALUE , ShowSystemError() );
BasicHelper::CHandleManager xAutoFileManager( hFile );
// 创建 CAB 文件到共享内存映射的句柄
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL );
CHK_EXP_RET( hMapping == NULL , ShowSystemError() );
BasicHelper::CHandleManager xMapping( hMapping );
CONST LPCTSTR szResName = MAKEINTRESOURCE( 1 );
CONST WORD wLanguage = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
// 获取 CAB 文件大小
DWORD dwSize = GetFileSize( hFile, ERROR_SUCCESS + NO_ERROR );
CHK_EXP_RET( dwSize == INVALID_FILE_SIZE , ShowSystemError() );
// 将 CAB 文件映射到共享内存中
LPVOID lpBuffer = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
CHK_EXP_RET( lpBuffer == NULL , ShowSystemError() );
// 准备将 CAB 文件内容添加到安装程序中
HANDLE hUpdate = BeginUpdateResource(szInstall, FALSE);
CHK_EXP_RET( hUpdate == NULL , ShowSystemError() );
// 将 CAB 文件内容更新到目标安装程序的资源中
UpdateResource(hUpdate, RT_RCDATA, szResName, wLanguage, lpBuffer, dwSize);
EndUpdateResource(hUpdate, FALSE);
UnmapViewOfFile(lpBuffer);
return NO_ERROR + TRUE;
}
{
// 复制安装程序到目标路径处
BOOL bCopy = CopyFile(szProgram, szInstall, FALSE);
CHK_EXP_RET( FALSE == bCopy , ShowSystemError() );
// 打开 CAB 文件
HANDLE hFile = CreateFile(szPackage, GENERIC_READ, 0, 0, OPEN_ALWAYS, 0, 0);
CHK_EXP_RET( hFile == INVALID_HANDLE_VALUE , ShowSystemError() );
BasicHelper::CHandleManager xAutoFileManager( hFile );
// 创建 CAB 文件到共享内存映射的句柄
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL );
CHK_EXP_RET( hMapping == NULL , ShowSystemError() );
BasicHelper::CHandleManager xMapping( hMapping );
CONST LPCTSTR szResName = MAKEINTRESOURCE( 1 );
CONST WORD wLanguage = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
// 获取 CAB 文件大小
DWORD dwSize = GetFileSize( hFile, ERROR_SUCCESS + NO_ERROR );
CHK_EXP_RET( dwSize == INVALID_FILE_SIZE , ShowSystemError() );
// 将 CAB 文件映射到共享内存中
LPVOID lpBuffer = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
CHK_EXP_RET( lpBuffer == NULL , ShowSystemError() );
// 准备将 CAB 文件内容添加到安装程序中
HANDLE hUpdate = BeginUpdateResource(szInstall, FALSE);
CHK_EXP_RET( hUpdate == NULL , ShowSystemError() );
// 将 CAB 文件内容更新到目标安装程序的资源中
UpdateResource(hUpdate, RT_RCDATA, szResName, wLanguage, lpBuffer, dwSize);
EndUpdateResource(hUpdate, FALSE);
UnmapViewOfFile(lpBuffer);
return NO_ERROR + TRUE;
}
呵呵,最后附上 CAB 文件完整的实现文件:
ExtractFile(szCabinet, szTarget);
}
};
}
}
};
}