Windows installer 从自定义操作在msi中插入cab文件
我想在安装时在msi包中插入cab文件。这可能吗? 有立即的自定义操作:Windows installer 从自定义操作在msi中插入cab文件,windows-installer,custom-action,Windows Installer,Custom Action,我想在安装时在msi包中插入cab文件。这可能吗? 有立即的自定义操作: UINT __stdcall CreateDataCab(MSIHANDLE hInstall) { MSIHANDLE hRec = MsiCreateRecord(1); UINT status = MsiRecordSetStream(hRec, 1, T("C:\\work\\Data2.cab")); MSIHANDLE hDb = MsiGetActiveDatabase(hInsta
UINT __stdcall CreateDataCab(MSIHANDLE hInstall) {
MSIHANDLE hRec = MsiCreateRecord(1);
UINT status = MsiRecordSetStream(hRec, 1, T("C:\\work\\Data2.cab"));
MSIHANDLE hDb = MsiGetActiveDatabase(hInstall);
MSIHANDLE hView = 0;
status = MsiDatabaseOpenView(hDb, _T("INSERT INTO `_Streams` (`Name`, `Data`) VALUES ('Data2.cab', ?)"), &hView);
status = MsiViewExecute(hView, hRec);
status = MsiViewClose(hView);
status = MsiCloseHandle(hView);
status = MsiCloseHandle(hRec);
status = MsiCloseHandle(hDb);
}
它在安装操作的最开始执行。status
变量的值始终为ERROR\u SUCCESS
。看来一切都很好。但是,在msi日志中,我可以看到触发的错误:
Action start 14:29:27: INSTALL.
MSI (s) (4C:14) [14:29:27:049]: Running ExecuteSequence
MSI (s) (4C:14) [14:29:27:049]: Doing action: SetSilentInstall
Action start 14:29:27: SetSilentInstall.
MSI (s) (4C:14) [14:29:27:051]: PROPERTY CHANGE: Adding SILENT property. Its value is '/s'.
Action ended 14:29:27: SetSilentInstall. Return value 1.
MSI (s) (4C:14) [14:29:27:052]: Doing action: CreateDataCab
Action start 14:29:27: CreateDataCab.
MSI (s) (4C:1C) [14:29:27:072]: Invoking remote custom action. DLL: C:\windows\Installer\MSI3EC2.tmp, Entrypoint: CreateDataCab
MSI (s) (4C:B4) [14:29:27:074]: Generating random cookie.
MSI (s) (4C:B4) [14:29:27:079]: Created Custom Action Server with PID 32604 (0x7F5C).
MSI (s) (4C:14) [14:29:27:147]: Running as a service.
MSI (s) (4C:14) [14:29:27:151]: Hello, I'm your 64bit Impersonated custom action server.
MSI (s) (4C!50) [14:32:22:069]: Note: 1: 2263 2: Data2.cab 3: -2147287035
注意:1:2263 2:Data2.cab 3:-2147287035
日志记录表明MSI错误2263无法打开流[2]。
在自定义操作中发生。-2147287035
的十六进制值为FFFFFFFF80030005
,很可能是STG_E_ACCESSDENIED HRESULT-拒绝访问
。
我对这个错误的第一个猜测是,MSI服务在试图将源文件提取到记录中时无法访问它。我放宽了C:\work\Data2.cab的权限,但运气不好。
然后我决定在msicrecordsetstream()调用中为不存在的文件使用路径。
通过此更改MsiRecordSetStream()
调用返回161
错误。由于CreateDataCab()
中没有分支,因此它一直执行到最后,并且在msicrecordsetstream()
成功后,所有MSI函数都将被执行。
msi日志:
注意:1:1101 2:C:\work\Data2.cab 3:2
表示出现MSI错误1101无法打开文件流:[2]
。这是msi日志中的额外错误,注意:1:2263 2:Data2.cab 3:-2147287035
仍然存在
使用调试器在CreateDataCab()
中单步执行会导致以下观察结果:
注意:1:1101 2:C:\work\foo.cab 3:2
错误在返回错误时立即添加到日志中
注意:1:2263 2:Data2.cab 3:-2147287035
错误在成功调用MsiCloseHandle(hView)
后立即添加到日志中
在CreateDataCab()
的开头和结尾转储\u Streams
表的内容表示新记录已成功添加到表中
这就是我现在拥有的。似乎发生了以下情况:
msicrecordsetstream()
用于新记录的操作正常。如果指定了正确的路径,系统可以将文件提取到记录中李>
向\u Streams
表插入新记录的SQL请求成功李>
数据
新增记录字段不含数据
我很困惑,自定义操作中执行的MSI函数都通过了,但MSI日志文件中有错误。对\u Streams
表的更改也部分成功:添加了新记录,但该记录不包含数据。似乎有可能在运行时更新\u Streams
表,但在表中存储数据时出现问题
我在构建时更新msi文件中的\u Streams
没有问题。一切正常。但在运行时从自定义操作执行此操作对我来说是不正确的。我的CA功能中是否缺少某些内容?在运行时更改\u Streams
是否合法
UPD:我对这个问题做了进一步的调查。我修改了我的msi,从两个CA调用了两次CreateDataCab()
。还修改了CreateDataCab()
本身。伪代码如下:
CreateDataCab() {
dumpStream();
openDb;
_Streams["Data1.cab"].Data = "c:/work/Data1.cab";
commitDb;
closeDb;
dumpStream();
}
dumpStream() {
openDb;
if ("Data1.cab" in _Streams) {
save _Streams["Data1.cab"].Data to "c:/work/saved.cab";
}
closeDb;
}
当为第一个CA调用CreateDataCab()
时,第一个dumpStream()
不会输出任何内容,但第二个on会将某些内容写入c:/work/saved.cab
。此文件显示为二进制文件,等于用作记录流源的c:/work/Data1.cab
。这表明流数据可以在\u Streams
表中很好地更新。数据持续存在并保留在数据库中,以便看不到它是在两个不同的MsiGetActiveDatabase()/MsiDatabaseClose()
作用域中插入和检索的。非常好,但是注意:1:2263 2:Data2.cab 3:-2147287035
仍在日志中
当为第二个CA调用CreateDataCab()
时,情况就不那么好了。第一个dumpStream()
清空c:/work/saved.cab
文件。这意味着Data1.cab
记录仍在\u Streams
表中,但流数据为空
正如大家所注意到的,\u Streams
表是特殊的,我用二进制
表进行了实验。试图修改现有记录导致注意:1:22592:3:4:
错误(数据库:[2]表更新失败),即“更新二进制集数据=?其中Name='Data1.cab'”
SQL查询不起作用。因此,在运行安装之前,我重新编写了CA代码以使用MsiViewModify(hView,MSIMODIFY\u INSERT\u TEMPORARY,hRec)
,并从Binary
表中删除了Data1.cab
记录
第一个CreateDataCab()
CA工作正常:插入OK,msi日志中没有错误,第二个dumpStream()
OK。但是,当为第二个CA调用CreateDataCab()
时,第一个dumpStream()
转储零字节,随后的msiewmodify(hView,MSIMODIFY\u INSERT\u TEMPORARY,hRec)
失败
_流和二进制表的结果相同:
插入的记录在CA调用中保持不变
添加的记录中的流数据不会跨CA调用持久化,并在第二个CA中设置零长度
在二进制表中插入新的临时记录不会导致msi日志中出现错误消息。
好消息是,可以使用来自CA的流数据更改记录。不太坏的消息是,在Binary
表中,不可能更改现有记录中的数据。
坏消息是,添加/更改流数据会损坏数据库
如果有人能质疑我的结论,我会非常高兴。在运行时,数据库是只读的。您必须使用而不是仅仅插入,我不确定它是否适用于\u Streams
表。(我一般也有
CreateDataCab() {
dumpStream();
openDb;
_Streams["Data1.cab"].Data = "c:/work/Data1.cab";
commitDb;
closeDb;
dumpStream();
}
dumpStream() {
openDb;
if ("Data1.cab" in _Streams) {
save _Streams["Data1.cab"].Data to "c:/work/saved.cab";
}
closeDb;
}