背景

在使用Visual Studio Setup项目模版创建Windows Installer项目时,我们有时需要用户输入序列号,同时验证序列号是否正确。在VS Setup模版中,我们往往仅能进行一些简单的验证,如果需要复杂的验证,怎么办呢?这里介绍一种结合Orac以及C++来实现此功能。

Orca

Orca是一款编辑Windows Installer (*.msi) 文件的工具,借助它我们可以对安装包中的表数据进行修改。此工具使用以及下载地址请参考: http://msdn.microsoft.com/en-us/library/windows/desktop/aa370557(v=vs.85).aspx

准备安装项目

首先我们准备好一个VS解决方案,此方案仅包括两个项目:

image

其中ConsoleAppTest是简单的控制台应用程序,而ConsoleAppTestSetup也是Windows Installer安装项目。

将ConsoleAppTest作为主输出添加到安装项目中。

在ConsoleAppTestSetup的User Interface View中,添加对话框,如下列所示:

image

选择Customer Information:

image

上移此对话框至“Welcome”下。设置其属性SerialNumberTemplate属性为 “<####-####-####>”,ShowSerialNumber为True:

image

这样我的安装项目就创建好了。

创建验证的C++类库项目

在VS中,创建C++ Win32 项目,名称为 CheckPIDDll:

image

image

创建C++文件 “PIDCheck.cpp”,其代码如下:

///////////////////////////////////////////////////////////////////////
//
// PIDCheck.cpp : Serial Number Validation
//
///////////////////////////////////////////////////////////////////////



#include "stdafx.h"

// Export the function so MSI can call it using undecorated C style name
extern "C" _declspec(dllexport) UINT __stdcall VerifyPID(MSIHANDLE hInstall);

// Private Function definitions
TCHAR* GetPIDValue(TCHAR*);

extern "C" UINT __stdcall VerifyPID(MSIHANDLE hInstall)
{
   // Local variables
   UINT    nRetVal = 0;
   UINT    uiMsiRc;
   TCHAR   szPidKey[MAX_PATH];
   TCHAR   szSourceDir[MAX_PATH];
   TCHAR*  lpszPidValue;
   DWORD   dwBuffer;

   // Get the source folder for the msi project
   dwBuffer = sizeof(szSourceDir)/sizeof(TCHAR);

   uiMsiRc = MsiGetProperty(hInstall, TEXT("SourceDir"), szSourceDir, &dwBuffer);

   if (ERROR_SUCCESS != uiMsiRc)
   {
      MessageBox(NULL, L"Not able to retrieve the SourceDir property. The setup may be corrupt.", L"Setup Error", MB_OK | MB_ICONEXCLAMATION);
      return 0;
   }

   // the correct key
   lpszPidValue = L"1234-5678-9012";

    // Get the PIDKEY property value entered by the user from the active msi
   dwBuffer = sizeof(szPidKey)/sizeof(TCHAR);
 
   uiMsiRc = MsiGetProperty(hInstall, TEXT("PIDKEY"), szPidKey, &dwBuffer);

   // If we cannot retrieve PIDKEY, show error message dialog
   if (ERROR_SUCCESS != uiMsiRc)
   {
      MessageBox(NULL, L"Not able to retrieve PIDKEY property.  The setup may be corrupt.", L"Setup Error", MB_OK | MB_ICONEXCLAMATION);
      return 0;
   }

   //Insert code to check PIDKEY here
   int str = lstrcmp(szPidKey, lpszPidValue);

   //If PIDKEY passes check
   if (str == 0)
      MsiSetProperty(hInstall, L"PIDCHECK", L"TRUE");
   //If PIDKEY doesn't pass check
   else
   {
      MsiSetProperty(hInstall, L"PIDCHECK", L"FALSE");
      MessageBox(NULL, L"Please enter the correct serial number!", L"Invalid Serial Number", MB_OK | MB_ICONINFORMATION);
   }

   return 0;
}

其中Header文件stdafx.h代码如下:

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// Need the following header files to access the MSI API
#include "msi.h"
#include "msiquery.h"



// TODO: reference additional headers your program requires here

 

设置此项目属性“Linker –> Input –> Additional Dependencies“属性为“msi.lib;%(AdditionalDependencies)”。

image

生成此项目。VerifyPID 用于验证客户输入的序列号是否为1234-5678-9012, 如果是则设置属性PIDCheck为True。根据需要,请自行修改验证逻辑,比如可以通过Web Service来验证。

用Orca编辑Msi

在Orca中打开VS生成的安装文件ConsoleAppTestSetup.msi。

image

在Binary Table中,添加一行,名称为CheckPIDDll,选择C++项目生成的dll:

image

在CustomerAction Table中,新建一行 (注意Target请设置_VerifyPID@4):

image

在Property Table中新建一行,如下图所示:

image

接下来,我们设置“Customer Information”对话框的“Next”按钮为自定义Action “CheckSerial”。

在ControlEvent Table中,修改CustomerInfoForm Dialog的ValidateProductID事件,

image

修改为:

Event: DoAction

Argument: CheckSerial

然后修改Event为NewDialog的行,设置Condition: ((PIDCHECK = "TRUE") AND CustomerInfoForm_NextArgs <> "" AND CustomerInfoForm_ShowSerial <> "")

image

修改完毕后,另存为“ConsoleAppTestSetup - Modified.msi”。

运行效果

点击新的msi文件,在Customer Information界面,如果随意输入序列号,则会提示如下:

image

输入序列号“1234-5678-9012”则能进入下一步正常安装:

image

总结

这种方式实现验证序列号实际上是很脆弱的,因为用户也可以利用Orca自行编辑msi安装文件而导致验证失效。建议将验证放在程序运行中,而非安装过程中;否则安装过程仅提供输入,程序运行时进行验证。

About author
Disclaimer
The opinions and comments expressed herein are my own personal opinions and do not represent my employer's view in any way.
Comments

Re:使用VSI/Orca/C++创建带序列号验证的Windows Installer项目

Raymond 这个序列号验证规则是什么啊

Author: bianlei @ 6/19/2013 6:02:37 PM | [Reply]

Re:使用VSI/Orca/C++创建带序列号验证的Windows Installer项目

@bianlei 如果你看我那段C++代码 它是直接判断输入的序列号是否等于1234-5678-9012 如果不是则提示错误 你可以改成你想要的效果

Author: Raymond @ 6/19/2013 6:48:05 PM | [Reply]

Add comment
Title
Title is required.
Name
Name is required.
Email
Please input your personal email with valid format.
Comments
Please input comment content.
Captcha Refresh
Input captcha:

Subscription

Statistics

Locations of visitors to this page