使用 VSI、Orca、C++ 或 Delphi 构建带序列号验证的安装项目
使用 VSI、Orca、C++ 或 Delphi 构建带序列号验证的安装项目。
引言
在 Visual Studio 安装程序 (VSI) 项目中,我们可以在用户界面中添加一个客户信息对话框。此对话框有一个用于输入序列号的输入字段。Visual Studio 对此字段的验证支持很少;不幸的是,关于如何包含自定义代码来验证用户输入的序列号的文章也很少。本文提供了使用 C++ 或 Delphi 编写的外部 DLL 文件在 VSI 安装项目中执行自定义验证的必要步骤,我将提供 C++ 和 Delphi 两种语言的演示。
创建简单的 VSI 安装项目
我将尝试使本文内容清晰简单;因此,我们将只创建一个空的安装项目(没有任何东西需要安装),因为我们只想测试序列号验证。在 Visual Studio 2010 中添加新项目,选择“其他项目类型”,然后选择“Visual Studio 安装程序”,并选择“安装项目”,将其命名为“SetupDemo”。
创建客户信息对话框
在解决方案资源管理器面板中单击“用户界面编辑器”按钮。
转到“用户界面”选项卡,选择“安装 - 开始”节点,然后从上下文菜单中选择“添加对话框”。
选择“客户信息”对话框并单击“确定”,然后将此新对话框的顺序更改为在“欢迎”对话框之后。
要激活序列号验证,请选择“客户信息”对话框,并在属性面板中将 ShowSerialNumber
设置为 True。
SerialNumberTemplate 属性
默认情况下,此属性指定用于验证序列号输入的模板,它还决定文本框在对话框中如何显示。例如,此属性的默认值“<###-%%%%%%%>”创建了两个由短划线分隔并由空格包围的文本框。(###) 简单地验证用户输入了三位数字。(%%%%%%%) 通过一个算法进行验证,该算法将数字相加并将总和除以 7。如果余数为 0,则验证成功;否则,失败。当然,这个序列可以通过输入 000-0000000 轻松破解。如果我们想让序列号更难猜测,我们应该使用更复杂的模板,使用这些特殊字符
- (#) 需要一个不包含在验证算法中的数字。
- (%) 需要一个包含在验证算法中的数字。
- (?) 需要一个不包含在验证算法中的字母数字字符。
- (^) 需要一个大写或小写字符。此处不允许使用数字。
- (<) 此字符左侧的任何字符在对话框中将不可见。
- (>) 此字符右侧的任何字符在对话框中将不可见。如果使用了 < 字符,则需要作为终止符。
使用更复杂的模板时,您将面临另一个问题。例如,假设我们想制作像 Microsoft 产品密钥(CB48T - GGBCX - H269K - C9W64 - X2RWD)这样的序列号,这个序列将在 SerialNumberTemplate
属性中表示为 "^^%#^ - ^^^^^ - ^%%%^ - ^%^%% - ^%^^^",但这个模板会创建 14 个文本框而不是 5 个;因为每次更改可编辑字符时都会创建一个新的文本框。我想没有人会喜欢使用 14 个文本框来验证序列号;因此,解决所有这些问题的最佳方法是使用外部库来验证序列号。借助 SerialNumberTemplate
属性使用这个库,那么一切皆有可能;因此,我们仍然需要 SerialNumberTemplate
属性来确定序列号中有多少组。在这个示例中,我将使用默认模板;这意味着序列号由两组数字组成,并且验证将在外部库中完成。现在构建安装项目并关闭它。
编码部分
在进入代码部分之前;我想在这里提一下,为了简单起见,我假设用户将在序列号文本框中输入 11 位数字;但是,在实际项目中,我们应该添加更多代码来检查序列号的长度以及字符的类型(是否为数字等)。验证过程取决于读取序列号文本框的值。我们可以借助 msi.lib 来实现这一点;这个库为我们提供了一堆方法来处理安装程序和 MSI 包(*.msi)。这些函数可以通过使用 MSIHandle
类型的参数与 Windows Installer 运行时交互,该参数传递 Windows Installer 会话的句柄。外部库——就像我们即将制作的验证库一样——将在安装过程中加载到内存中,以便它可以获取安装程序会话的句柄并将其传递给 msi.lib 函数。验证过程中的第二个重要事项是:我们将使用一个辅助属性“PIDCHECK
”,我们稍后将使用 Orca 工具将其添加到 msi 包中。当序列号值通过验证时,我们将 PIDCHECK 值设置为“TRUE”,当序列号失败时,我们将此属性设置为“FALSE”。序列号值存在于名为“PIDKEY”的内置属性中。我们将使用 msi.lib 方法 MsiGetProperty
来读取此属性,然后检查/处理此值,最后使用 MsiSetProperty
方法将结果保存到辅助属性 PIDCHECK
中。我在此示例中的简单验证将是这样的:(第三个数字 + 最后一个数字) 除以三的余数应为零。
在 C++ 中创建验证库
在 Visual Studio 2010 中创建新的 C++ Win32 dll 项目,将其命名为 CheckPIDDll。
我们需要一个函数来验证序列号;因此,修改此库的源文件如下
#include "stdafx.h"
#include <msi.h>
#include <msiquery.h>
#include <tchar.h>
#pragma comment(lib, "msi.lib")
UINT __stdcall VerifyPID(MSIHANDLE hInstall)
{
TCHAR szPidKey[MAX_PATH];
DWORD dwBuffer;
dwBuffer = MAX_PATH * sizeof(TCHAR);
// Get the PIDKEY property
MsiGetProperty(hInstall, TEXT("PIDKEY"), szPidKey, &dwBuffer);
//check PIDKEY here
int n1 = _ttoi(&szPidKey[2]);
int n2 = _ttoi(&szPidKey[10]);
int n3 = (n1 + n2) % 3;
if (n3 == 0 && n1 != n2)
MsiSetProperty(hInstall, L"PIDCHECK", L"TRUE");//PIDKEY passes check
else
{
//PIDKEY doesn't pass check
MsiSetProperty(hInstall, L"PIDCHECK", L"FALSE");
MessageBox(NULL, L"serial number is not valid.",
L"Installer", MB_OK | MB_ICONINFORMATION);
}
return 0;
}
为了将此函数导出到外部;添加新的模块定义文件(.def),将其命名为 CheckPIDDll 并按如下方式修改它
LIBRARY "CheckPIDDll"
EXPORTS
VerifyPID
构建此项目,输出文件 CheckPIDDll.dll 现在可以用于安装项目了。
在 Delphi 中创建验证库
在 Delphi 2010(或任何 Unicode Delphi 版本)中添加新的 Dll 项目。
JEDI 提供了一个很好的 msi.lib Delphi 包装器,您可以在此处下载:http://sourceforge.net/project/platformdownload.php?group_id=121894。现在我们可以编写一个 Delphi DLL 库,它执行与之前的 C++ 库相同的验证,如下所示
library CheckPIDDll;
uses
SysUtils,
Classes,
Windows,
JwaMsi,
jwaMSIQuery;
{$R *.res}
function VerifyPID(hInstall: MSIHandle): Integer; stdcall;
var
sPidKey: PChar;
dwBuffer: Cardinal;
sKey: string;
n1,n2,n3: Integer;
begin
dwBuffer := MAX_PATH;
sPidKey := strAlloc(MAX_PATH);
try
// Get the PIDKEY property
MsiGetProperty(hInstall, 'PIDKEY', sPidKey, dwBuffer);
//check PIDKEY here
sKey := string(sPidKey);
n1 := StrToInt(sKey[3]);
n2 := StrToInt(sKey[11]);
n3 := (n1 + n2) mod 3;
if (n3 = 0) and (n1 <> n2) then
Begin
MsiSetProperty(hInstall, 'PIDCHECK', 'TRUE');//PIDKEY passes check
End
else
Begin
MsiSetProperty(hInstall, 'PIDCHECK', 'FALSE');
MessageBox(0, PChar('serial number is not valid.'),
PChar('Installer'), MB_OK or MB_ICONINFORMATION);
End;
finally
StrDispose(sPidKey);
end;
result := 0;
end;
exports
VerifyPID;
begin
end.
构建此项目,我们就可以进入下一步了。
Orca 工具
Orca 是一个 Windows Installer 包编辑器,旨在提供对构成 Windows Installer 包的数据库表的完全访问。它提供了对 Windows Installer 所有功能的强大访问。此工具作为 Windows Installer SDK 的一部分提供;因此,如果您以前没有使用或安装过 Orca,如果您安装了 Visual Studio,此工具可能存在于您的硬盘上;因此,只需在您的 Program Files 文件夹中搜索“Orca.msi”并安装该工具。您也可以从以下链接下载:http://www.microsoft.com/en-us/download/details.aspx?id=6510。在本文中,我不会详细解释 Orca。我只想向您展示将验证库添加到 msi 包的必要步骤。
编辑 MSI 包并添加验证库
运行 Orca 工具并打开我们之前制作的安装项目演示的 MSI 包“SetupDemo.msi”。从左侧面板选择“Binary”表,然后从上下文菜单中选择“Add Row”,将新行命名为“CheckPIDDll
”,并将数据值设置为验证库的路径(Delphi 或 C++ 版本)。
从左侧面板选择“Custom Action”表,并添加一个新的自定义操作,命名为 CheckSerial,将 Type 设置为 1,将 Source 设置为 CheckPIDDll
,将 Target 设置为 VerifyPID。
选择“Property”表,添加新属性,命名为“PIDCHECK”,并将其默认值设置为 FALSE。
现在我们需要将 CheckSerial
自定义操作分配给客户信息对话框中“下一步”按钮的 Click 事件;因此,选择 ControlEvent 表,并在右侧面板中向下滚动到包含 CustomerInfoForm
事件的行。我们只对 NextButton 事件感兴趣;因此,更改包含事件 ValidateProductID 的行,如下所示:Event= DoAction, Argument= CheckSerial
。将 NextButton NewDialog 事件条件更改为 ((PIDCHECK = "TRUE") AND CustomerInfoForm_NextArgs <> "" AND CustomerInfoForm_ShowSerial <> "")
。
现在保存这些更改并关闭 Orca。转到安装演示 SetupDemo.msi 并测试新更改。您可以通过更改二进制行来在 Delphi 版本和 C++ 版本的验证库之间切换。
结论
那是一个简单的演示;但在充分理解这种验证过程之后,我认为制作带有像 Microsoft 产品密钥那样序列号的安装项目并不会那么困难。