...

понедельник, 31 марта 2014 г.

VMPKit — интеграция протектора VMProtect в Windows-приложение. Часть третья. Интеграция с InnoSetup

Данная статья продолжает серию постов о продукте VMProtect Integration Kit (VMPKit).

В первой части были рассмотрены функции-обертки WinAPI, упрощающие работу с подсистемой UAC, функции VMPKit для управления хранением лицензий, сервисные функции для API VMProtect, упрощающие работу с ним, и некоторые другие вспомогательные функции.


Во второй части была рассмотрена подсистема протоколирования VMPKit, а также функции, предоставляющие настраиваемый пользовательский интерфейс для активации приложения.


В данной части будут рассмотрены функции поддержки инсталлятора, функции на языке InnoSetup-script для активации приложения в процессе инсталляции. Также будет рассмотрена поддержка опций командной строки программы установки.


Содержание




Отмазка aka disclaimer




VMPKit является молодым продуктом, и нельзя говорить, что он доведен до совершенства. Если вы обнаружите в нем недоработки или ошибки, пожалуйста, не спешите оставлять гневные комментарии, попробуйте с начала связаться с нами для устранения проблемы.

О данном руководстве




Данная статья является в настоящий момент наиболее полным руководством/справочником по VMPKit. Документация на официальном сайте vmpkit.com в настоящее время отстает по полноте и детализации от данной статьи. VMPKit поддерживает тесную интеграцию подсистемы активации в установочный пакет, создаваемый при помощи инсталлятора InnoSetup. Данная поддержка включает в себя:


  • дополнительные страницы мастера установки для выбора группы пользователей (текущий пользователь/все пользователи);

  • дополнительные страницы выбора типа активации, а также страницы активации при помощи серийного номера и ключевого файла лицензии;

  • поддержка ключей командной строки для задания параметров дополнительных страниц;

  • поддержка silent-установки.





Выбор группы пользователей




Дополнительные возможности по выбору группы пользователей, для которых устанавливается приложение (текущий пользователь/все пользователи), включают в себя функции создания страницы мастера установки и функции поддержки ключей командной строки.

Страница мастера установки - выбор группы пользователей





Активация приложения




Дополнительные возможности для интеграции активации в пакет установки включают в себя функции создания соотвествующих страниц мастера установки и функции поддержки ключей командной строки. Интеграция VMPKit в пакет установки InnoSetup включает в себя страницу выбора типа активации, поддерживающую следующие типы активации:


  • Активировать при помощи серийного номера, полученного при покупке;

  • Активировать при помощи ключевого файла лицензии;

  • Активировать пробную лицензию;

  • Активировать позже;

  • Уже активировано на этом компьютере.




Страница мастера установки - выбор типа активации (1)



Страница мастера установки - выбор типа активации (2)



Активация при помощи серийного номера



Активация при ключевого файла лицензии


Поддержка опций командной строки программы-установщика




При задании опций командной строки они могут начинаться с символа '/', с символа '-' или с символов '--'. Опции командной строки VMPKit могут требовать указания параметра. В этом случае параметр отделяется от имени опции символом ':' или символом '='.

Задание группы пользователей




Для задания группа пользователей, для которых устанавливается приложение, используются следующие опции командной строки:


  • INSTALLFORUSER, INSTALLFORUSERS — задает группу пользователей, для которых устанавливается программа. Может принимать значения:


    • ALLUSERS или 0 — устанавливает программу для всех пользователей.

    • CURRENTUSER, USER или 1 — устанавливает программу только для текущего пользователя.



  • SKIPINSTALLFORUSERPAGE или SKIPINSTALLFORUSERSPAGE — если задана опция INSTALLFORUSER, то указание данной опции подавляет отображение соответсвующей страницы мастера установки, позволяя пропустить этот шаг.





Задание серийного номера




Для того, чтобы автоматизировать установку ПО, VMPKit поддерживает следующие опции командной строки:


  • ACTIVATETRIAL — указывает, что необходимо активировать пробную (Trial) лицензию.

  • ACTIVATESERIAL, ACTIVATESERIALNUMBER — указывает активировать приложение при помощи серийного номера (кода активации). Аргументом данной опции является серийный номер.

  • SKIPACTIVATIONPAGE, ACTIVATESERIALNUMBER — если задана опция ACTIVATETRIAL или ACTIVATESERIAL, то указание данной опции подавляет отображение соответсвующих страниц мастера установки, позволяя пропустить этот шаг.





Поддержка Silent-установки




Функции интеграции VMPKit для InnoSetup поддерживают режим «тихой» (silent) установки и автоматически определяют его активность. При этом не требуется дополнительно указывать опции SKIPINSTALLFORUSERPAGE и SKIPACTIVATIONPAGE.

Протоколирование процесса активации




Функции интеграции VMPKit для InnoSetup поддерживают протоколирование процесса активации приложения для упрощения устранения возможных проблем:


  • ACTIVATIONLOG, LOGACTIVATION — если задается имя лог-файла, процесс активации будет записан в него. Если имя файла не задано, но задана стандартная опция InnoSetup LOG с именем файла, то будет использоваться путь заданного файла, имя задается в iss-файле проекта. Если имя файла не задано в опции LOG, то будет создан файл во временном каталоге ОС.






INT VMPIKAPI VMPIK_ActivateSerialNumberOnlineAndSaveW( HWND hwndParent
, UINT fAadFlags /* Only VMPIK_AADF_ALWAYS_SILENT_MESSAGEBOX allowed */
, LPCSTR serialNumber
, BOOL bTrial
, DWORD acfFlags
, HKEY hRootKey
, LPCWSTR lpcRegOrFilePath
, LPCWSTR lpcRegValOrFileNameLicense
, LPCWSTR lpcRegValOrFileNameSerial
, LPCWSTR lpcRegValOrFileNameTrial
, LPCWSTR lpActivationUrl
, LPVOID lpCallbackParam
, PFN_VMPIK_ActivateOnlineCallbackW ActivateOnlineCallback
, PFN_VMPIK_ActivateCheckLicenseCallbackW ActivateCheckLicenseCallback
);




Функция VMPIK_ActivateSerialNumberOnlineAndSaveW производит активацию серийного номера и сохраняет данные лицензии по указанному местоположению. При использовании VMProtect аргументы ActivateOnlineCallback и ActivateCheckLicenseCallback следует задать как 0. При использовании другой системы активации следует создать DLL, которая экспортирует данные функции и передать их адреса в VMPIK_ActivateSerialNumberOnlineAndSaveW.

INT VMPIKAPI VMPIK_ActivateLicenseFileAndSaveW( HWND hwndParent
, UINT fAadFlags /* Only VMPIK_AADF_ALWAYS_SILENT_MESSAGEBOX allowed */
, LPCWSTR licenseFile
, DWORD acfFlags
, HKEY hRootKey
, LPCWSTR lpcRegOrFilePath
, LPCWSTR lpcRegValOrFileNameLicense
, LPVOID lpCallbackParam
, PFN_VMPIK_ActivateCheckLicenseCallbackW ActivateCheckLicenseCallback
);




Функция VMPIKAPI VMPIK_ActivateLicenseFileAndSaveW производит активацию при помощи ключевого файла лицензии и сохраняет данные лицензии по указанному местоположению. При использовании VMProtect аргумент ActivateCheckLicenseCallback следует задать как 0. При использовании другой системы активации следует создать DLL, которая экспортирует данную функцию и передать ее адрес в VMPIKAPI VMPIK_ActivateLicenseFileAndSaveW.

Функции, импортируемые из VMPKit в InnoSetup




Вышеприведенные функции VMPIK_ActivateSerialNumberOnlineAndSaveW и VMPIKAPI VMPIK_ActivateLicenseFileAndSaveW импортируются в InnoSetup так (так же приведено описание функций протоколирования VMPKit):
Определение импортируемых функций VMPKit


function VMPIK_ActivateSerialNumberOnlineAndSaveW( hWnd: HWND;
fAadFlags: UINT;
serialNumber: AnsiString;
bTrial: BOOL;
acfFlags: DWORD;
hRootKey: Integer;
lpcRegOrFilePath : String;
lpcRegValOrFileNameLicense : String;
lpcRegValOrFileNameSerial : String;
lpcRegValOrFileNameTrial : String;
lpActivationUrl : String; // ignored, not used
lpCallbackParam : DWORD;
ActivateOnlineCallback : DWORD;
ActivateCheckLicenseCallback : DWORD
): integer;
external 'VMPIK_ActivateSerialNumberOnlineAndSaveW@files:vmpik32.dll stdcall';

function VMPIK_ActivateLicenseFileAndSaveW( hWnd: HWND;
fAadFlags: UINT;
licenseFile: String;
acfFlags: DWORD;
hRootKey: Integer;
lpcRegOrFilePath : String;
lpcRegValOrFileNameLicense : String;
lpCallbackParam : DWORD;
ActivateCheckLicenseCallback : DWORD
) : integer;
external 'VMPIK_ActivateLicenseFileAndSaveW@files:vmpik32.dll stdcall';

function VMPIK_LogCreateTemporaryW( dwFlags: DWORD;
lpszLogFilePath: String;
lpszLogFileNamePrefix: String;
lpszLogFileNameExt: String;
n: UINT;
reserved0_mustbe0: DWORD; // var: filenameBuf: String;
reserved1_mustbe0: UINT
) : integer;
external 'VMPIK_LogCreateTemporaryW@files:vmpik32.dll stdcall';

function VMPIK_LogCreateTemporaryExW( dwFlags: DWORD;
lpszLogFilePath: String;
lpszLogFileNamePrefix: String;
lpszLogFileNameExt: String;
n: UINT;
var resultName: String; // var: filenameBuf: String;
reserved1_mustbe0: UINT
) : integer;
external 'VMPIK_LogCreateTemporaryW@files:vmpik32.dll stdcall';

function VMPIK_LogCreateW( dwFlags: DWORD;
lpszLogFilename: String
) : integer;
external 'VMPIK_LogCreateW@files:vmpik32.dll stdcall';





Приведены Unicode версии функции — для использования в современных версиях InnoSetup с поддержкой Unicode.

Глобальные переменные InnoSetup для поддержки VMPKit




Глобальные переменные VMPKit для поддержки выбора группы пользователей


var
gsGroup : string;
gsDesktop : string;
gsRootKey : Integer;
gsTakenFromCmdLine : Boolean;
gsSkipPage : Boolean;



Глобальные переменные и константы VMPKit для поддержки активации


const
CF_TEXT = 1;
VK_BACK = 8;
VK_INSERT = 45; { 0x2D }

AM_SERIAL = 0;
AM_LICFILE = 1;
AM_TRIAL = 2;
AM_LATER = 3;
AM_ALREADY = 4;

VMPIK_AADF_ALWAYS_SILENT_MESSAGEBOX = $08000000;

VMPIK_ACF_SHARE64FOR32KEY = $0001;

VMPIK_IS_TRUE = 1;
VMPIK_IS_FALSE = 0;
VMPIK_IS_NA = $FFFFFFFF;

VMPIK_LOG_DEFAULT = 0;
VMPIK_LOG_APPPATH = 1;
VMPIK_LOG_EXTRACTPATH = 2;
VMPIK_LOG_OVERWRITE = 4;
VMPIK_LOG_APPEND = 8;

var
SerialEdits: array of TEdit;
VmpikSerialNumberString : AnsiString;

VmpikCommandLineTakenSerial : AnsiString;
VmpikCommandLineActivateTrial : Boolean;
VmpikCommandLineActivateSkipPage : Boolean;
VmpikCommandLineSkipActivationPages : Boolean;
VmpkitTakenLogFilename: String;



Глобальные переменные и константы, задаваемые пользователем VMPKit


var
ChoiceUserGroupPage : TInputOptionWizardPage;
ActivationType: Integer;
VmpikAppIsActivatedFlag : Boolean;

var
// see function InitializeSerialFormat and InitializeWizard
VMPIK_SERIAL_FORMAT: array of integer;
VMPIK_SERIAL_NUM_PARTS: integer; // = 10;

const

VMPIK_SERIAL_NUM_PARTS_MAX = 16;

VMPIK_ACTIVATE_CHOICE_ALLOW_SERIAL = True; // Change to your own value
VMPIK_ACTIVATE_CHOICE_ALLOW_LICENSE_KEY_FILE = True; // Change to your own value True
VMPIK_ACTIVATE_CHOICE_ALLOW_TRIAL = True;
VMPIK_ACTIVATE_CHOICE_ALLOW_LATER = True; // Change to your own value
VMPIK_ACTIVATE_CHOICE_ALLOW_ALREADY = True; // Change to your own value

// Change to your own value or keep empty if VMPIK_ACTIVATE_CHOICE_ALLOW_TRIAL = False
VMPIK_TRIAL_SERIAL_NUMBER = 'XXXX-XXXX-XXXX-XXXX';

// allow log activation process and /ACTIVATIONLOG command line switch
VMPIK_ACTIVATION_LOG_ALLOW = True;

VMPIK_ACTIVATION_LOG_FILENAME_PREFIX = 'vmpkit_'; // prefix for activation log filename

var
ActivateChoicePage: TInputOptionWizardPage;
EnterSerialNumberPage: TWizardPage;
ChoiceKeyFilePage: TInputFileWizardPage;



Функции InnoSetup-script для поддержки VMPKit




Функции поддержки выбора группы пользователей:

function GetGroupPath (Unused : string) : string;
function GetDesktopPath (Unused : string) : string;




Использование функций выбора группы пользователей:

[Icons]
Name: "{code:GetDesktopPath}\{#APP_NAME}" ; Filename: "{app}\vmpik_demo32.exe"; WorkingDir: "{app}"; Tasks: desktopicon
Name: "{code:GetGroupPath}\{#APP_NAME}" ; Filename: "{app}\vmpik_demo32.exe"; WorkingDir: "{app}"




Функции поддержки активации:

// реализуется пользователем, задает формат серийного номера
procedure InitializeSerialFormat(var fmt:Array of integer);

// Проверяет и извлекает выбранную группу пользователей
procedure TestUserGroupChoice(ChoicePage:TInputOptionWizardPage);

// Создает страницу выбора группы пользователей
function CreateChoiceUserGroupPage(PageIdAfter: Integer): TInputOptionWizardPage;

// Производит разбор параметров командной строки, задающих группу пользователей
procedure GrpParseCommandLine( ChoicePage:TInputOptionWizardPage );

// Создает страницу выбора типа активации
function VMPIK_CreateChoiceActivationPage(PageIdAfter: Integer): TInputOptionWizardPage;

// Создает страницу ввода серийного номера (кода активации)
function VMPIK_CreateEnterSerialNumberPage(PageIdAfter: Integer) : TWizardPage;

// Создает страницу выбора ключевого файла лицензии
function VMPIK_CreateChoiceKeyFilePage(PageIdAfter: Integer): TInputFileWizardPage;

// Производит разбор параметров командной строки, задающих серийный номер
procedure VMPIK_ParseCommandLineEx( ActivationChoicePage:TInputOptionWizardPage; SerialNumberPage: TWizardPage; const SerialDelimiter: string );

// Возвращает True, если страницу выбора типа активации следует пропустить
function VMPIK_IsNeedToSkipChoiceActivationTypePage(): Boolean;

// Возвращает True, если страницу ввода серийного номера следует пропустить
function VMPIK_IsNeedToSkipSerialPage(atype:Integer): Boolean;

// Возвращает True, если страницу ввода имени ключевого файла лицензии следует пропустить
function VMPIK_IsNeedToSkipLicenseKeyFilePage(atype:Integer): Boolean;

// Проверяет пользовательский ввод и возвращает одно из значений AM_*
function VMPIK_GetActivationTypeCode(ChoicePage:TInputOptionWizardPage): Integer;

// Производит активацию программы, вызывается в обработчике NextButtonClick
function VMPIK_OnNextButtonClick_TryActivateSerialNumberEx(var bNextButtonClickRes: Boolean;
CurPageID: Integer;
acfFlags: DWORD;
RegKeyRegName : String;
LicenseRegName : String;
SerialNumberRegName : String;
bTrialRegName : String;
ActivationUrl : String;
StrSerialNumber : AnsiString
): Boolean;


В качестве примера интеграции хочу привести фрагмент скрипта инсталлятора (секция [Code]) программы Клипборд Коц (Clipboard Stripper). Вы можете скачать эту программу и посмотреть все возможности VMPKit на наглядном примере.
Подключение языковых файлов


[Languages]
Name: en; MessagesFile: "compiler:Default.isl,clstripper_en.isl"
Name: ru; MessagesFile: "compiler:Languages\Russian.isl,clstripper_ru.isl"





Языковой файл clstripper_en.isl


[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=English
LanguageID=$0409
LanguageCodePage=0

[CustomMessages]
AppName=Clipboard Stripper
AboutApp=About Clipboard Stripper
AppSite=http://ift.tt/1oh6R6I
AppDefPath=Clipboard Stripper
AppDefGroupName=Clipboard Stripper
BuildingComponentsCache=Building components cache
VersionInfoDescription=The clipboard assistant program
VersionInfoProductName=Clipboard Stripper
CreateDesktopIconQuestion=Do you want to create desktop icon?
AddToAutorun=Run Clipboard Stripper on logon
AutorunName=Clipboard Stripper
PostInstallRun=Launch Clipboard Stripper
GroupQuestion =Should Clipboard Stripper be installed for all users?

#include "vmpik\setup\all_users_dlg_en.isl"
#include "vmpik\setup\activate_msg_en.isl"
#include "vmpik\setup\vmp_msg_en.isl"





Языковой файл clstripper_ru.isl


[LangOptions]
LanguageName=<0420><0443><0441><0441><043A><0438><0439>
LanguageID=$0419
LanguageCodePage=1251

[CustomMessages]
AppName=Клипборд Коц
AboutApp=О программе Клипборд Коц
AppSite=http://клипборд-коц.рф
AppDefPath=Клипборд Коц
AppDefGroupName=Клипборд Коц
BuildingComponentsCache=Создание кэша компонентов
VersionInfoDescription=Программа-помошник для буфера обмена
VersionInfoProductName=Клипборд Коц
CreateDesktopIconQuestion=Хотите создать значок Клипборд Коц на Рабочем столе?
AddToAutorun=Запускать при входе в систему
AutorunName=Clipboard Stripper
PostInstallRun=Запустить Клипборд Коц
GroupQuestion = Установить Клипборд Коц для всех пользователей?

#include "vmpik\setup\all_users_dlg_ru.isl"
#include "vmpik\setup\activate_msg_ru.isl"
#include "vmpik\setup\vmp_msg_ru.isl"





Скрипт интеграции активации в InnoSetup


[Code]
var
ChoiceUserGroupPage : TInputOptionWizardPage;
ActivationType: Integer;
VmpikAppIsActivatedFlag : Boolean;

VMPIK_SERIAL_FORMAT: array of integer;
VMPIK_SERIAL_NUM_PARTS: integer; // = 10;

const
VMPIK_SERIAL_NUM_PARTS_MAX = 16;

VMPIK_ACTIVATE_CHOICE_ALLOW_SERIAL = True; // Change to your own value
VMPIK_ACTIVATE_CHOICE_ALLOW_LICENSE_KEY_FILE = True; // Change to your own value True
VMPIK_ACTIVATE_CHOICE_ALLOW_TRIAL = True;
VMPIK_ACTIVATE_CHOICE_ALLOW_LATER = True; // Change to your own value
VMPIK_ACTIVATE_CHOICE_ALLOW_ALREADY = True; // Change to your own value
VMPIK_TRIAL_SERIAL_NUMBER = '{#CLSTRIPPER_TRIAL_SERIAL}';
VMPIK_ACTIVATION_LOG_ALLOW = True; // allow log activation process and /ACTIVATIONLOG command line switch
VMPIK_ACTIVATION_LOG_FILENAME_PREFIX = 'clp_'; // prefix for activation log filename

var
ActivateChoicePage: TInputOptionWizardPage;
EnterSerialNumberPage: TWizardPage;
ChoiceKeyFilePage: TInputFileWizardPage;

#include "select_grp_scrip.pas"
#include "activate_hlp_script.pas"

procedure InitializeSerialFormat(var fmt:Array of integer);
begin
SetArrayLength(fmt,VMPIK_SERIAL_NUM_PARTS_MAX);

// VMPKit long serial number scheme (4x4)
VMPIK_SERIAL_NUM_PARTS := 4;
fmt[0] := 4; fmt[1] := 4; fmt[2] := 4; fmt[3] := 4;
fmt[4] := 0; fmt[5] := 0; fmt[6] := 0; fmt[7] := 0;
fmt[8] := 0; fmt[9] := 0; fmt[10] := 0; fmt[11] := 0;
fmt[12] := 0; fmt[13] := 0; fmt[14] := 0; fmt[15] := 0;
end;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := False;

if ((PageID=ChoiceUserGroupPage.ID) and ((gsSkipPage<>False) or WizardSilent() )) then
begin
TestUserGroupChoice(ChoiceUserGroupPage);
Result := True;
Exit;
end;

if (PageID=ActivateChoicePage.ID) then
begin
if (VMPIK_IsNeedToSkipChoiceActivationTypePage() = True) then Result := True;
Exit;
end;

if (PageID = EnterSerialNumberPage.ID) then
begin
if (VMPIK_IsNeedToSkipSerialPage(ActivationType) = True) then Result := True;
Exit;
end;

if (PageID = ChoiceKeyFilePage.ID) then
begin
if (VMPIK_IsNeedToSkipLicenseKeyFilePage(ActivationType) = True) then Result := True;
Exit;
end;
end;


function NextButtonClick(CurPageID: Integer): Boolean;
begin

Result := True;

if (CurPageID=ChoiceUserGroupPage.ID) then
begin
TestUserGroupChoice(ChoiceUserGroupPage);
Exit;
end;

if (CurPageID=ActivateChoicePage.ID) then
begin
ActivationType := VMPIK_GetActivationTypeCode(ActivateChoicePage);
end;

if ((CurPageID=ActivateChoicePage.ID) and ((ActivationType=AM_LATER) or (ActivationType=AM_ALREADY))) then
begin
Exit;
end;

if (((CurPageID=ActivateChoicePage.ID) and (ActivationType=AM_TRIAL)) or
((CurPageID=ChoiceKeyFilePage.ID) and (ActivationType=AM_LICFILE)) or
((CurPageID=EnterSerialNumberPage.ID) and (ActivationType=AM_SERIAL)) or
((CurPageID=wpReady) and (VmpikCommandLineSkipActivationPages<>False)) // silent activation runs immediately before install
) then
begin
Result := VMPIK_OnNextButtonClick_TryActivate( CurPageID
, VMPIK_ACF_SHARE64FOR32KEY
, 'Software\' + '{#APP_REG_KEY}'
, 'License'
, 'SerialNumber'
, 'Trial'
, 'http://vmpkit.com/'
, ChoiceKeyFilePage.Values[0]
);
Exit;
end;
end;


procedure InitializeWizard ();
var
numParams : Integer;
paramNo : Integer;
StrParamName: string;
StrParamVal: string;
begin

VmpikAppIsActivatedFlag := False;

InitializeSerialFormat(VMPIK_SERIAL_FORMAT);

ChoiceUserGroupPage := CreateChoiceUserGroupPage(wpLicense);

ActivateChoicePage := VMPIK_CreateChoiceActivationPage(wpSelectTasks); // wpWelcome, wpInfoBefore
EnterSerialNumberPage := VMPIK_CreateEnterSerialNumberPage(ActivateChoicePage.ID);
ChoiceKeyFilePage := VMPIK_CreateChoiceKeyFilePage(EnterSerialNumberPage.ID);

GrpParseCommandLine( ChoiceUserGroupPage );
VMPIK_ParseCommandLine( ActivateChoicePage, EnterSerialNumberPage );
end;



Интеграция активации в InnoSetup была реализована в первую очередь, так как это основной (и пока единственный) используемый нами инсталлятор. Поддержки прочих инсталляторов на данный момент нет, но мы планируем ее реализовать в будущем. На текущий момент всё, что мы хотели рассказать об интеграции VMProtect в приложения, мы рассказали, и показали все основные возможности VMPKit. Тем не менее, у нас еще есть кое-какие планы по расширению VMPKit, а также мы всегда открыты новым идеям и пожеланиям наших пользователей.

Даже если вы решите не приобретать VMPKit, мы надеемся, что наши статьи показали, какие мероприятия необходимы для создания качественного инсталлятора и качественной подсистемы активирования, и помогли вам лучше спланировать создание инсталляционного пакета вашего продукта.


Спасибо за внимание!


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий