Лицензирование элемента управления ActiveX

Подход лицензирования, поддерживаемый непосредственно Visual Basic.

Вы можете создать залицензированное управление, выбирая переключатель Require License Key в позиции табуляции General диалогового окна Project Properties. Когда Вы делаете это, следующее происходит:

·        Управление будет всегда требовать ключ лицензии, чтобы загрузиться.

·        Visual Basic создает файл лицензии VBL для управления.

·        Когда управление откомпилировано, Visual Basic регистрирует ключ лицензии.

 

Каждое залицензированное управление поддерживает интерфейс по имени IClassFactory2, который используется в течение создания управления. Это - стандарт интерфейса ActiveX, предназначенный для поддержки этого типа лицензирования. Контейнер, который загружает управление, обязан передавать этот ключ лицензии в виде уникальной строки, определенной управлением. Если ключ обеспечен парой контейнеров для управления, то управление загружается успешно.

Откуда исходит патентование ключа? Visual Basic перемещает ключ из одного из двух источников, в зависимости от того, находится ли контейнер во времени разработки или времени выполнения. Если контейнер находится во времени разработки, Visual Basic просматривает в системном реестре ключ лицензии для управления.

Когда управление откомпилировано в приложение, Visual Basic сохраняет ключи лицензии для каждого управления вместе с приложением. Тот путь, куда управление загружено в выполняющуюся прикладную программу, Visual Basic, может использовать сохраненный ключ и позволить управлению работать без обращения к реестру.

Когда контейнер управления находится в режиме конструирования, Visual Basic пытается находить ключ лицензии непосредственно для каждого управления. Если контроль залицензирован, и ключ лицензии не найден, управление не будет в состоянии загрузиться. Когда управление откомпилировано в приложение, Visual Basic сохраняет ключ лицензии каждого контроля непосредственно в приложении, чтобы оно могло создать его во время выполнения.

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

Ключи лицензии сохранены в системном реестре под ключом

HKEY_CLASSES_ROOT\Licenses.

Например, Вы создаете управление, названное xyz.ocx с GUID: 93A7C69D-7FEE-11D0-93A6-00AA0036005A.

Когда Вы создаете проект, то создается VBL файл следующего вида:

REGEDIT

HKEY_CLASSES_ROOT\Licenses = Licensing: Copying the keys may be a violation of established copyrights.

HKEY_CLASSES_ROOT\Licenses\546ADAFB-34C9-11D9-85CF-A83678CA1D28 = uhnhjohomhjhvomosihhthjhlisnjolhtoli

 

Этот VBL файл содержит команды для регистрации ключа лицензии и ключа случайной строки данных. Этот GUID появится как дополнительный ключ в системном реестре следующим образом:

HKEY_CLASSES_ROOT\Licenses\546ADAFB-34C9-11D9-85CF-A83678CA1D28= uhnhjohomhjhvomosihhthjhlisnjolhtoli

 

Мастер установки Visual Basic использует VBL файл для добавления команды регистрации лицензирования к программе установки. Когда Вы выполняете программу установки, он добавит ключ лицензии в системный реестр. Если кто-нибудь скопирует управление на другую систему, то оно будет прекрасно работать с приложениями; непосредственно им скомпилированным в приложение с ключем лицензии. Но если пользователь пробует размещать или загружать управление на форму Visual Basic во время разработки, Visual Basic будет не в состоянии находить ключ лицензии и не будет загружать управление.

Этот подход имеет одно главное ограничение: это не помогает Вам со средами, которые не имеют отдельного режима создания программы и автономного режима времени выполнения. Например: приложения Microsoft Office всегда проверяют системный реестр для ключа лицензии. Это означает, что, если Вы хотите, чтобы ваше управление было пригодным для использования в пределах приложений Office, Вы должны всегда обеспечивать ключ лицензии. ActiveX документы также не способны сохранить ключ лицензии. Таким образом, они также проверяют системный реестр для ключей лицензии в любое время загрузки управления.

На Web-страницах требуется, чтобы ключи лицензии для управления всегда работали. Также ясно, что регистрация ключей лицензии для каждого управления, которое загружено, не может быть приемлема. Это означает обеспечение неограниченной лицензии для использования каждого загруженного управления. Включая ключ в Интернет, сама страница делала бы доступ к ключу слишком простым способом.

Таким образом, броузеры, которые поддерживают элементы управления ActiveX, обеспечивают механизм, чтобы загрузить файл пакета лицензии, или .LPK файл. Этот файл создается программой по имени lpk_tool.exe, которая может быть найдена в каталоге Tools на вашем CD-ROM Visual Basic. Эта программа позволяет Вам объединять ключи лицензии для всех контролей на Web-странице в файл с расширением .LPK. Вы можете тогда добавить параметр для объектного тэга Web-страницы следующим образом:

<PARAM NAME="LPKPath" VALUE = "mylpk.lpk">

Это добавляет к объекту специальный параметр по имени LPKPath, который сообщает броузеру имя .LPK файла для его нахождения. Это имя файла должно быть относительно страницы, а не абсолютного URL, чтобы невозможно было скопировать страницу и выполнить ее на вашей местной системе.

Почему Вы должны использовать специальный инструмент, чтобы создать файл пакета лицензии? Почему Visual Basic не может сделать этого для Вас? Поскольку файл должен содержать ключи лицензии для каждого управления на Web-странице, и Visual Basic возможно не будет знать, на какой странице используется контроль. Ключи лицензии, обеспеченные в этом файле только используются броузером для загрузки контроля. Они не добавляются к системному реестру.

Альтернатива, лицензирующая подход

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

Создание Компонентов Демонстрации

Группа программ gtpDT.vbg демонстрирует альтернативный подход для лицензирования. Проекты gtpLicDT.vbp и gtpLicRT.vbp обращаются к классу, названный gtpLicensed.cls, содержащий следующий код:

 

Option Explicit

 

Public Sub A()

   ' Prevent key functionality

   If Not VerifyLicense() Then

      MsgBox "Отказ лицензии не позволяет выполнить эту команду"

      Exit Sub

   End If

   MsgBox "Подпрограмма была выолнена"

End Sub

 

Private Sub Class_Initialize()

   MsgBox "gtpLicensed создает объект"

End Sub

 

В этом примере функциональные возможности функции A блокированы, если лицензия наблюдает сбои. Вы можете обеспечить более сложный код инициализации класса с вызовом ошибки, если лицензирование терпит неудачу. Обычно, Вы никогда не должны поднимать произвольные ошибки в компоненте кода, но в этом случае Вы вероятно не будете возражать, если приложение терпит неудачу неприятным способом. Только убедитесь, что сначала подняли окно сообщения или диалог, объясняя проблему, чтобы конечный пользователь не тратил часы, пробуя выяснить что не так.

Функция VerifyLicense может быть найдена в модуле Licenser.bas, который содержит следующий код:

 

' Guide to the Perplexed

' Copyright © 1997 by Desaware Inc. All Rights Reserved

 

' Варианты, поддержавшие этим модулем включают:

' DEMOVERSION - Проверяет хорошо только в среде VB

' DLLCHECK - Требует файл лицензии в среде VB

 

Option Explicit

 

' Функция GetModuleFileName отыскивает полный путь и имя файла

' для файла, содержащего указанный модуль.

' Windows 95/98/Me: функция GetModuleFilename отыскивает длинные имена

' файлов, когда номер версии приложения больше чем или равен 4.00,

' и длинное имя файла доступно. Иначе, это возвращает только 8.3 имен

' файла формата.

Private Declare Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA" (ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long

' Функция GetModuleHandle отыскивает дескриптор для указанного модуля,

' если файл отображен в адресном пространстве процесса запроса.

Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long

 

#If DEMOVERSION Or DLLCHECK Then

' Возвратите Истину если

' Демонстрационная версия может работать на любой VB платформе, дизайне или времени выполнения

Public Function IsVBEnvironment() As Boolean

   Dim thismod&

   Dim thisfile$

   Dim basename$

   Dim thispos%

   Dim thischar$

 

   On Error GoTo nogo

   thismod = GetModuleHandle(0)

   thisfile = String$(262, Chr$(0))

   Call GetModuleFileName(thismod, thisfile, 261)

   thisfile = Left$(thisfile, InStr(thisfile, Chr$(0)) - 1)

   thispos = Len(thisfile)

   Do

      thischar = Mid$(thisfile, thispos, 1)

      If thischar = "\" Or thischar = ":" Then Exit Do

      thispos = thispos - 1

   Loop While thispos > 0

   basename = LCase$(Mid$(thisfile, thispos + 1))

   If basename = "vb.exe" Or _

      basename = "vb32.exe" Or _

      basename = "vb6.exe" Or _

      basename = "devenv.exe" Then

         IsVBEnvironment = True

   End If

   Exit Function

nogo:

End Function

#End If

 

Public Function VerifyLicense() As Boolean

   Static PriorVerification As Boolean

   Static VerifiedOnce As Boolean

   ' Быстро вернуться при втором обращении

   If PriorVerification Then

      VerifyLicense = VerifiedOnce

      Exit Function

   End If

   PriorVerification = True

   #If DEMOVERSION Then

      If Not IsVBEnvironment() Then

         ' Вывести экран отказа лицензии

         frmAbout.MessageType = 1

         frmAbout.Show vbModal

         VerifiedOnce = False

      Else

         ' Вывести информационный экран

         frmAbout.MessageType = 0

         frmAbout.Show vbModal

         VerifiedOnce = True

      End If

      VerifyLicense = VerifiedOnce

      Exit Function

   #End If

   #If DLLCHECK Then

      If IsVBEnvironment Then

         ' Здесь проверить DLL или объект.

         ' Если не найдено, вернуть VerifyLicense = False

         VerifiedOnce = False

      Else

         VerifiedOnce = True

      End If

      VerifyLicense = VerifiedOnce

      Exit Function

   #End If

   ' Значение по умолчанию хорошо

   VerifiedOnce = True

   VerifyLicense = True

End Function

 

Поведение этого модуля зависит от двух условных констант трансляции. Пока, мы остановимся на константе DEMOVERSION.

ActiveX компоненты не могут обнаружить различие между временем разработки и временем выполнения. Условная константа трансляции DEMOVERSION предназначена для компилирования двух версий компонента: всегда выполняемый и тот, который только работает в пределах среды Visual Basic.

Когда эта константа и константа DLLCHECK (которая будет описана позже), не определены или равны 0, функция VerifyLicense всегда возвращает TRUE. Это обеспечивает очень быструю проверку для правильного компонента. Когда указанные константы отличны от нуля, функция VerifyLicense выполняет запрос к функции IsVBEnvironment, чтобы проверить, принадлежит ли текущий процесс к Visual Basic. Это осуществляется функцией GetModuleHandle с пустым параметром, чтобы восстановить описатель экземпляра выполняющейся прикладной программы. После этого может быть использована функция GetModuleFileName для восстановления имени исполняемого файла для приложения. Если функция возвращает одно из возможных имен выполнимой программы Visual Basic, то функция IsVBEnvironment возвращает TRUE, указывая, что компонент выполняется под Visual Basic.

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

Функция VerifyLicense исполняет проверку только однажды, возвращая результат начального испытания. Это обеспечивает две цели. Сначала, это улучшает эффективность. Во вторых, это облегчит использование диалогового окна «About», который появляется только при первой загрузке DLL или OCX.

При первом вызове функции VerifyLicense осуществляется обращение к форме frmAbout.frm. Код этой формы показан ниже:

 

' Guide to the Perplexed

' Лицензирование примера диалога

Option Explicit

 

Public MessageType As Integer

 

Private Sub Command1_Click()

   Unload Me

End Sub

 

Private Sub Form_Load()

   Select Case MessageType

      Case 0

         lblMessage.Caption = "Это - демонстрационная версия компонента gtpLicensed"

      Case 1

         lblMessage.Caption = "Этот компонент незалицензирован"

   End Select

End Sub

 

Общедоступная переменная MessageType позволяет модулю запроса определять предупреждающее сообщение: стандартный экран идентификации компонента или предупреждение лицензирования. Есть одна вещь, которую Вы должны иметь в виду при выборе отображения этого информационного экрана. Если Вы создаете объект DLL и затем обращаетесь к нему, осуществляется вывод этого информационного окна и через некоторое время – загрузка DLL. Когда Вы завершаете его работу, то информационный экран появится снова.

 

Есть три различия между проектами gtpLicRT и gtpLicDT:

·        Проект gtpLicDT имеет условную переменную трансляции DEMOVERSION, установленную в 1.

·        Проектные названия различны.

·        Проект gtpLicRT не включает форму frmAbout.

 

Почему используется трансляция условного выражения для дифференцирования между компонентами вместо использования только глобальной константы?

Поскольку:

·        вы можете обеспечить лучшее выполнение не демонстрационной версии;

·        два проекта могут совместно использовать одно и то же основу кода; единственное различие находится в проектном файле;

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

 

Если посмотреть на форму frmLicTest.frm в проекте LicTest, то Вы будете видеть следующий код:

 

Option Explicit

' Изменяющаяся ссылка проста

Dim obj As New gtpLicensed

 

Private Sub Command1_Click()

   obj.A

End Sub

 

Скажем, проект первоначально создан с использованием демонстрационного компонента gtpLicDT. Как Вы можете переключиться к другому компоненту? Просто. Только измените ссылку в диалоговом окне Project-References к ссылке проекта gtpLicRT вместо проекта gtpLicDT. Никакие другие изменения кода не нужны.

Лицензирование управления на основе файла

Небольшое изменение этого подхода может быть замечено в группе программ ctlTest.vbg, которая содержит проект LicCtl.vbp и испытательный проект ctlTest.vbp. Управление использует тот же самый модуль Licenser.bas, который Вы видели в предыдущем примере, но в этом случае он определяет условную переменную трансляции DLLCHECK.

Процедуру VerifyLicense можно вызвать двумя возможными случаями: при инициализации управления или в событиях InitProperties и ReadProperties. Если Вы выбираете последнюю, убедитесь, что исполнили испытание лицензии как в событии InitProperties, так и в событии ReadProperties, охватили создание нового контроля и загрузки существующих проектов.

 

Option Explicit

 

Private Sub UserControl_Initialize()

   If Not VerifyLicense Then

      MsgBox "Licensing error"

      Err.Raise vbObjectError + 1000, "Control", "Управление не залицензировано для этой платформы"

   End If

End Sub

 

Private Sub UserControl_InitProperties()

   ' An alternate approach

   'If (Not Ambient.UserMode) And (Not VerifyLicense) Then

   '   MsgBox "Licensing error"

   '   Err.Raise vbObjectError + 1000, "Control", "Управление не залицензировано для этой платформы"

   'End If

End Sub

 

Если Вы не заботитесь, находится ли управление во времени разработки или времени выполнения, то исполняйте проверку при инициализации элемента управления. Например: Вы можете использовать этот подход для разрешения или отключения управления при использовании его с приложениями Office. Если Вы действительно хотите базировать проверку на контейнере UserMode, Вы должны выполнить эту проверку до случаев InitProperties или ReadProperties, когда объект Ambient существует. С ActiveX документами Вы можете ждать до случая Show, когда Вы можете базировать операцию на контейнере, который является доступным через родительское свойство.

Сама проверка может быть основана на любых критериях, которые Вы желаете. Один общий подход состоит в том, чтобы распределить отдельный DLL или ActiveX DLL, который содержит информацию о патентовании режима создания программы. Вы можете проверить на существование информации версии в этом DLL во времена, которые Вы выбираете.

 

   #If DLLCHECK Then

      If IsVBEnvironment Then

         ' Здесь проверить DLL или объект.

         ' Если не найдено, вернуть VerifyLicense = False

         VerifiedOnce = False

      Else

         VerifiedOnce = True

      End If

      VerifyLicense = VerifiedOnce

      Exit Function

   #End If

 

При сбоях лицензирования имеется множество вариантов. Документация Visual Basic правильно предупреждает Вас против подъема ошибок времени выполнения, когда контейнер не ожидает это, например в событиях InitProperties, ReadProperties, и составляющих инициализации. Почему нарушается это правило здесь? Поскольку предполагается, что попытка выполнить незалицензированный компонент – неустранимая ошибка. Я хочу, чтобы контейнер прервался, если возможно. Но подъем ошибки не гарантирует, что управление будет не в состоянии загружаться (это действительно имеет этот эффект в контейнерах). Таким образом, Вы должны следить за фактом, что лицензирование терпело неудачу в переменной уровня модуля и используйте эту переменную, чтобы отключить различные части управления при сбоях лицензирования.

Как прежде, управление действительно поднимает окно сообщений для сообщения конечному пользователю, что проблема происходит из-за лицензирования. Лучший подход состоит в том, чтобы включить модальное диалоговое окно с информацией относительно того, как получить лицензию.

Эти два простых примера иллюстрируют некоторые важные принципы для лицензирования. Рассмотрите сначала информацию, которую Вы имеете в наличии:

·        Имя выполнимой программы, которая выполняет текущий процесс (процесс запроса для ActiveX DLLs, DLL-основанных ActiveX документов, и элементов управления ActiveX).

·        Находится ли контейнер в режиме конструирования или режиме прогона (только элементы управления ActiveX).

Теперь рассмотрите инструментальные средства, которые Вы имеете в наличии, чтобы указать, что управление залицензировано:

·        Вы можете распределить текстовый файл лицензии.

·        Вы можете создать невидимые файлы для того, чтобы лицензировать цели.

·        Вы можете распределить DLL или ActiveX DLL для лицензирования.

·        Вы можете добавить ваши собственные входы в системном реестре.

Комбинируйте указанные два примера, и Вы увидите, что есть почти неограниченные разновидности, доступные для управления лицензированием любого компонента типа ActiveX.

Например: ограниченный компонент продолжительности мог быть осуществлен следующим образом:

·        Когда управление загружается, впервые это добавляет вход системного реестра или невидимый файл, который указывает дату первого использования.

·        Управление тогда проверяет этот скрытый вход каждый раз при загрузке. Если управление выполняется в Visual Basic и истекло, это заканчивается с ошибкой.

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

Несомненно, пользователь мог выяснить, какой вход системного реестра Вы использовали или находить невидимый файл и перезапускать испытательный срок. Они могут также задержать часы на их системе. Помните, что намерение здесь состоит в том, чтобы предупредить пользователя, потому что все эти подходы основаны при условии, что большинство разработчиков честные.

 

Daniel Appleman
 Email:
dan@desaware.com

Web: http://www.desaware.com/

March 1997