快速链接:Managed Code Custom Actions(以下是 C++ 原生自定义操作)。
更新:一些有用的链接。
怀疑原因:
在此处顶部列出一些建议。
-
1) 错误的 C++ 自定义操作代码配置,经常忘记创建 CA.def 文件来定义 dll 导出。我也一直用__stdcall(微星是个老姑娘)。
-
2) WiX 标记中自定义操作 dll 的路径错误(MSI 中的 dll 无效)。
-
3) 忘记启用检查 WiX 标记 (*.WXS) 中的错误代码,然后 CA 没有结束设置。在您的情况下,这看起来是正确的 (Return='check')。
-
4) 忘记在安装顺序中插入自定义操作。
- 还有几个,暂时想不到。以后可能会添加...想到的一个是位问题 (x86/64)...
-
文件和运行时依赖项是典型的故障转移原因。
- 尽量静态链接。
- 部署 DLL 应该是最小依赖项,因为它们需要在任何系统、任何语言、任何状态、任何操作系统版本等上运行...
- 真正推荐静态链接且始终是正确选择的少数情况之一。
注意:避免在设置中获得许可?我建议您将许可证验证放在您的应用程序中,而不是您的设置中。这里
关于这个问题的一些想法:
Installer with Online Registration for Windows Application(推荐阅读)。
技术问题:
FileName.def:我不是 C++ 专家,但是您的项目中有 FileName.def 文件来声明导出的dll的功能?如果没有 - 添加一个(下面的步骤/程序)。确保它的格式正确(通过 Visual Studio 添加,我认为它是没有 BOM 的 UTF8)。编译并检查Dependency Walker是否所有导出都正确:
验证 MSI 文件 DLL:您应该检查已编译的 MSI 以验证其内部是否有正确的 DLL 以及可用的正确导出。因此;验证 DLL 是否已安全进入 MSI 的二进制表:
- 使用 Orca (or equivalent) 打开您编译的 MSI。
-
二进制表,双击您的 DLL 条目的数据列。
- 选择“将二进制文件写入文件名”并保存到桌面(或其他地方)。
- 使用Dependency Walker (depends.exe) 来验证您是否拥有如上图所示的有效DLL。 常见的问题是您根本看不到导出(
MyImmediateCA、MyTestFail、MyTestSuccess、etc...)。
- 验证文件-和产品版本以及文件属性。
错误处理:可以设置自定义操作来抑制错误。设置了“返回属性”后,您的标记看起来正确:(Return='check')。你的sn-p:
<CustomAction Id='TestPassword' BinaryKey='TestPassword'
DllEntry='TestPassword' Execute='immediate' Return='check'/>
测序:还要检查您的测序是否正常。总之,您需要指向二进制表 DLL,声明自定义操作,然后将其插入到正确的序列中。模拟 WiX 标记:
<!--<Binary Id="CustomActions" SourceFile="$(var.TestDll.TargetPath)" />-->
<Binary Id="CustomActions" SourceFile="C:\TestDll.dll" />
<CustomAction Id="MyTestFail" BinaryKey="CustomActions" DllEntry="MyTestFail"/>
<CustomAction Id="MyTestSuccess" BinaryKey="CustomActions" DllEntry="MyTestSuccess"/>
<InstallExecuteSequence>
<Custom Action="MyTestSuccess" After="CostFinalize" />
<Custom Action="MyTestFail" After="MyTestSuccess" />
</InstallExecuteSequence>
C++ DLL:以及实际的 C++ DLL 本身(记住 *.def 文件)。来自MSI API Custom Action Security的底部代码段中的片段:
Visual Studio 2017 的建议步骤:
- 创建新的 VC+ DLL 项目 - 动态链接库 (DLL)。
- 将以下代码转储到主
*.cpp 文件中(我避免使用 dllmain.cpp)。
- 添加 *.def 文件!
-
Right Click Source Files => Add => New Item... => Code => Module-Definition File (.def) => 任何名字都可以……(只允许一个 def 文件)
- 添加您的导出函数名称:
模型:
LIBRARY
EXPORTS
MyTestFail
MyTestSuccess
MyImmediateCA
关闭并重新打开文件以验证是否有任何格式错误。如果出现警告,请选择修复。 UTF8 without BOM 我认为是必需的。
#include "stdafx.h"
#include <windows.h>
#include <Msiquery.h>
#pragma comment(lib, "msi.lib")
UINT __stdcall MyTestFail(MSIHANDLE hInstall)
{
MessageBox(NULL, L"MyTestFail", L"MyTestFail", MB_OK);
return ERROR_INSTALL_FAILURE;
}
UINT __stdcall MyTestSuccess(MSIHANDLE hInstall)
{
MessageBox(NULL, L"MyTestSuccess", L"MyTestSuccess", MB_OK);
return ERROR_SUCCESS;
}
// I will leave in the below snippet from the MSI API - section "Custom Action Security". Above two test methods will do though...
UINT __stdcall MyImmediateCA(MSIHANDLE hInstall)
{
MessageBox(NULL, L"Test", L"Test", MB_OK);
// set up information for deferred custom action called MyDeferredCA
const TCHAR szValue[] = TEXT("data");
UINT uiStat = ERROR_INSTALL_FAILURE;
if (ERROR_SUCCESS == MsiSetProperty(hInstall, TEXT("MyDeferredCA"), szValue))
{
uiStat = MsiDoAction(hInstall, TEXT("MyDeferredCA"));
// clear CustomActionData property
if (ERROR_SUCCESS != MsiSetProperty(hInstall, TEXT("MyDeferredCA"), TEXT("")))
return ERROR_INSTALL_FAILURE;
}
return (uiStat == ERROR_SUCCESS) ? uiStat : ERROR_INSTALL_FAILURE;
}
Another answer on MsiGetProperty(检索属性值)。这在 C++ 中稍微复杂一点——包括缓冲区和所有内容。向下滚动查看源代码。
最小依赖关系:为了最小化依赖关系,您应该消除 Visual C / C++ 运行时依赖关系和任何 MFC
依赖项(如果您可以帮助解决文件大小和问题,请不要使用 MFC
性能原因)。如果您使用 MFC,请将其设置为使用静态链接 -
也适用于 ATL。最后对于 C/C++ 运行时,请参见此处:
Visual Studio 2010 MSVCR dependency removal?
(有更好的链接,但我能找到的只是我有时间
现在 - 只是想把它放在那里,这样它就不会被遗忘)。
发布模式 C++ 二进制文件现在不应依赖于任何 MSVC 运行时 dll:
这是 DLL 如何在不进行此调整的情况下依赖于 MSVC 运行时 dll 的屏幕截图 - 不要介意红色图标 - 这是古老的依赖遍历器工具,它没有针对现代依赖进行更新,但完美地显示了旧式依赖:
请注意,调试模式 DLL 可能依赖于不同于发布模式二进制文件的文件。发布模式二进制文件是重要的。显然永远不要分发调试模式的二进制文件!