This site uses cookies to deliver our services. By using this site, you acknowledge that you have read and understand our Cookie and Privacy policy. Your use of Kontext website is subject to this policy. Allow Cookies and Dismiss

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

786 views 2 comments last modified about 6 years ago Raymond

背景

在使用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安装文件而导致验证失效。建议将验证放在程序运行中,而非安装过程中;否则安装过程仅提供输入,程序运行时进行验证。

Related pages

Set AttachDbFilename as Relative Path in .NET Core

317 views   0 comments last modified about 5 months ago

.NET Framework, you can use |DataDirectory| to configure connection string when connecting to SQL Server database file via attach mode: AttachDbFilename=|DataDirectory|\dbname.mdf In .NET Core, you cannot directly set SQL Server Express connec...

View detail

Set AttachDbFilename as Relative Path in .NET Core

317 views   0 comments last modified about 5 months ago

.NET Framework, you can use |DataDirectory| to configure connection string when connecting to SQL Server database file via attach mode: AttachDbFilename=|DataDirectory|\dbname.mdf In .NET Core, you cannot directly set SQL Server Express connec...

View detail

Instantiate a Service in ConfigureServices Method in .NET Core

45 views   0 comments last modified about 5 months ago

.NET Core is built in with dependency injection. Usually method ConfigureServices in Startup class is used to register services in the container. The signature of the method looks like the following: public void ConfigureServices(IServiceC...

View detail

Instantiate a Service in ConfigureServices Method in .NET Core

45 views   0 comments last modified about 5 months ago

.NET Core is built in with dependency injection. Usually method ConfigureServices in Startup class is used to register services in the container. The signature of the method looks like the following: public void ConfigureServices(IServiceC...

View detail

ASP.NET Core 2.1 Error - 'Cyrillic' is not a supported encoding name

279 views   0 comments last modified about 5 months ago

After upgrading to ASP.NET Core 2.1 (.NET Core SDK 2.1.301), you may encounter the following error about encoding: System.ArgumentException &nbsp;&nbsp; HResult=0x80070057 &nbsp;&nbsp; Message='Cyrillic' is not a supported encoding name. For information on defining a custo...

View detail

SQLite in .NET Core with Entity Framework Core

173 views   0 comments last modified about 5 months ago

SQLite is a self-contained and embedded SQL database engine. In .NET Core, Entity Framework Core provides APIs to work with SQLite. This page provides sample code to create a SQLite database using package Microsoft.EntityFrameworkCore.Sqlite . Create sample project ...

View detail

Add comment

Please login first to add comments.  Log in New user?  Register

Comments (2)

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

Ra*** about 6 years ago

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

bi*** about 6 years ago

Raymond 这个序列号验证规则是什么啊
B Re:使用VSI/Orca/C++创建带序列号验证的Windows Installer项目

bi*** about 6 years ago

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