65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 VSI、Orca、C++ 或 Delphi 构建带序列号验证的安装项目

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (9投票s)

2013年4月2日

CPOL

7分钟阅读

viewsIcon

56047

downloadIcon

1064

使用 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 产品密钥那样序列号的安装项目并不会那么困难。

参考

© . All rights reserved.