Visual Basic 6 is the last native version of Visual Basic developed by Microsoft released on 1998 (now known simply as Visual Basic), On April 8, 2008 Microsoft stopped supporting Visual Basic 6.0 IDE. The Microsoft Visual Basic team still maintains compatibility for Visual Basic 6.0 applications on Windows Vista, Windows Server 2008 including R2, Windows 7, Windows 8, Windows 8.1, Windows Server 2012 and Windows 10 through its "It Just Works" program. In 2014 there were tens of thousands of developers who still prefer Visual Basic 6.0 over Visual Basic .NET
Provides initialize api interface to native gsCore.dll.
these files provides Object-Oriented programming api to different SoftwareShield objects:
These files provides apis to inspect license model parameters:
Provides date time helper utility functions.
We first make a copy of the folder "SDK_Install_Dir\Lang\VB6" to a new folder called "VB6SDK" side by side with your project folder (for example, VBdemo3):
Now we need to add our SDK files as part of the app project, you can press "Ctrl + D" to add all VB6SDK files one by one in VB6 IDE, which is too boring and error-prone, or you can quit VB6 IDE first, open the *.VBP project file in a text editor and paste the following lines (the content of file "SDK/VB6/AddVB6SDKFiles.txt"):
Module=TGSIntf; ..\VB6SDKSoftwareShieldIntf.bas Module=TGSHelper; ..\VB6SDKSoftwareShieldHelper.bas Class=TGSApp; ..\VB6SDKSoftwareShieldApp.cls Class=TGSCore; ..\VB6SDKSoftwareShieldCore.cls Class=TGS; ..\VB6SDKSoftwareShield.cls Class=TGSEvent; ..\VB6SDKSoftwareShieldEvent.cls Class=TGSAction; ..\VB6SDKSoftwareShieldAction.cls Class=TGSEntity; ..\VB6SDKSoftwareShieldEntity.cls Class=TGSLicense; ..\VB6SDKSoftwareShieldLicense.cls Class=TGSRequest; ..\VB6SDKSoftwareShieldRequest.cls Class=TGSVariable; ..\VB6SDKSoftwareShieldVariable.cls Class=TMovePackage; ..\VB6SDKSoftwareShieldMovePackage.cls Class=TGSInspector; ..\VB6SDKSoftwareShieldInspector.cls Class=TGSInspector_Period; ..\VB6SDKSoftwareShieldInspector_Period.cls Class=TGSInspector_Duration; ..\VB6SDKSoftwareShieldInspector_Duration.cls Class=TGSInspector_HardDate; ..\VB6SDKSoftwareShieldInspector_HardDate.cls Class=TGSInspector_AccessTime; ..\VB6SDKSoftwareShieldInspector_AccessTime.cls Class=TGSInspector_SessionTime; ..\VB6SDKSoftwareShieldInspector_SessionTime.cls
Save the *.VBP file and re-open it in VB6 IDE, now all SDK files are included in the test app:
By default, the VB6 is installed in "C:\Program Files\Microsoft Visual Studio\VB98" (32bit Windows) or "C:\Program Files (x86)\Microsoft Visual Studio\VB98" (64bit Windows). Once the gsCore.dll is accessible to the VB6 IDE, you can debug the project in source code level.
Before you can call most SDK apis, you must initialize the SDK first with the project-specific parameters:
Private Sub Form_Load() REM These information is a copy from SoftwareShield IDE const productId = '8d11ec62-bfa0-4794-9688-41f8aa04630d'; const password = 'walml_9282&APNQ&18163'; const license_filename = 'Advanced Tutorial of Notepad2.lic'; On Error GoTo ErrorHandler REM We put the license file side by side with the exe, and pass the full path to it SdkInitialize productId, App.Path & "\" & license_filename, password ErrorHandler: REM Update error message MsgBox "Error Code:" & gs.Core.LastErrorCode & " Error Message: " & gs.Core.LastErrorMessage End Sub
In this demo we put the license file side by side with your exe, and resolve the exe path at run-time via App.Path, anyway, you must pass in the full path of the license file, otherwise the SDK will blinkdly assume the license file is in current directory, which will fail if the app is launched from another folder.
To query license information, you first need to find the entity objects:
Dim i as Integer Dim core as TGSCore Dim entity As TGSEntity Set core = gs.Core For i = 0 To core.EntityCount-1 Set entity = core.Entities(i) REM dump entity information... Next
You can also get the specific entity by its entityId:
REM EntityId is copied from IDE const entityId = "b15c8ac2-d87c-4483-be77-5a8cbc89a62b" Set entity = core.getEntityById( entityId )
If your app has only one entity, let's get it by a single line:
Set entity = core.Entities(0)
This is because the entity is the only single entity with index 0.
Given an entity object, we can easily retrieve its properties:
Dim id, name, description As String id = entity.Id name = entity.Name description = entity.Description
If your entity is associated with a trial license model (Expire by Access Times, Expire By Hard Date, Expire By Period, Expire by Duration, Expire by Session Time), you can test the entity's license status as following:
If entity.Unlocked Then ' this entity is already activated / fully purchased. ' app should run in full featured mode for this entity (game level, app module, etc.)... Call run_in_full_featured_mode() ElseIf entity.Locked Then 'this entity is locked or trial already expired. 'we may pop up info to prompt for purchase. Call cannot_run() Else 'this entity still in trial period or duration Call run_in_trial_mode() End If
If your entity is using License Model Always Lock, then the logic can be simplied as:
If entity.Unlocked then 'this entity is already activated / fully purchased. 'app should run in full featured mode for this entity (game level, app module, etc.)... Call run_in_full_featured_mode() Else 'this entity is still locked, we need a license to continue. 'we may pop up info to prompt for purchase. Call cannot_run() End If
In the above section, we have detected that an entity is still in trial mode, so in order to display proper license information to end user on app UI, such as tell the game player how many trial time left before the game will stop running, we must be able to get more details of the license model.
Dim lic As TGSLicense Set lic = entity.License
Now that the license object is ready, we can inspect it in various perspectives:
As a developer we have designed the license project in SoftwareShield IDE before, so we should have known which kind of license model being used for an entity. However, if you are developing a universal logic to parse any entity, it is helpful to find out the license model type being bundled with the input entity:
SoftwareShield SDK defines the following enumeration type for each built-in license model:
Public Enum GSLicenseModelKind LM_UNKNOWN = 0 LM_EXPIRE_PERIOD = 1 LM_EXPIRE_DURATION = 2 LM_EXPIRE_HARDDATE = 3 LM_EXPIRE_ACCESSTIME = 4 LM_EXPIRE_SESSIONTIME = 5 LM_ALWAYS_LOCK = 6 LM_ALWAYS_RUN = 7 End Enum
To get the license's type, you can use the license's property Kind:
Dim model_kind As GSLicenseModelKind Dim model_description As String model_kind = lic.Kind model_description = lic.Description
For example, for Expire By Period, its kind is LM_EXPIRE_PERIOD, so by comparing the license kind you can figure out the correct license model type to inspect further.
Now we have known which license model to inspect, let's retrieve the license parameters according to its model type.
This license model (Expire by Access Times) has two parameters of int type: "usedTimes" and "maxAccessTimes"
Dim usedTimes, maxAccessTimes, how_many_access_left As Integer Dim inspector As TGSInspector_AccessTime Set inspector = lic.Inspector usedTimes = inspector.TimeUsed maxAccessTimes = inspector.MaxAccesssTime 'How many times left the app can launch in trial mode? how_many_access_left = inspector.TimeLeft
This model (Expire By Hard Date) is a bit complex since it have three different use cases, in this tutorial we only demonstrate the most commonly used one: "Expire After", in this case, the license has a predefined expiry date "timeEnd", the app trial mode expires after this date.
Dim expiryDateLocal As Date Dim inspector As TGSInspector_HardDate Set inspector = lic.Inspector expiryDateLocal = inspector.ExpireDate
The interest part is that SoftwareShield SDK api always returns TDateTime in UTC time zone, but \SDK for VB6 inspectors have convert it to local time to display the expiry date in local time zone. SoftwareShield SDK/VB6 has several time convert functions in TGSHelper.bas:
'Helpers 'UTC <=> Local Function LocalTimeToUTC(ByVal the_date As Date) As Date Function UTCToLocalTime(ByVal the_date As Date) As Date 'Date <=> SYSTEMTIME Sub DateToSystemTime(ByVal the_date As Date, ByRef system_time As SYSTEMTIME) Sub SystemTimeToDate(system_time As SYSTEMTIME, ByRef the_date As Date) 'Format seconds to a string in format "XX day(s) YY hour(s) ZZ minute(s) DD second(s)" Function ConvertSecondsToString(ByVal totalSeconds As Long) As String
This license model (Expire By Period) has a UTC datetime parameter "timeFirstAccess", specify the timestamp the entity is first accessed, and an integer parameter "periodInSeconds", specify the total trial period allowed. The following code tries to figure out when the license will expire and how many trial time left before expire.
Dim periodInSeconds, timeLeftInSeconds As Integer; Dim timeFirstAccess, expiryDate As Date; Dim inspector As TGSInspector_Period Set inspector = lic.Inspector periodInSeconds = inspector.Period timeLeftInSeconds = inspector.TimeLeft 'Figure out when the entity is first accessed (aka. entity.beginAccess() is first called) If inspector.IsEntityEverAccessed Then timeFirstAccess = inspector.TimeFirstAccess expiryDate = inspector.ExpireDate Else ' Never Accessed! End If
The interesting part of the above code is that: if the "timeFirstAccess" does not hold a valid timestamp (the default value is undefined), which occurs when the entity is never accessed before, we cannot deduce the exact expiry date, however we can deduce how many time left before expire.
This license model (Expire by Duration) is simple, it just adds up all elapsed trial time cumulatively (in "usedDurationInSeconds") until the total trial time exceeds the pre-defined maximum value ("maxDurationInSeconds"). We cannot figure out the expiry date.
'Total trial period in seconds Dim maxDurationInSeconds, usedDurationInSeconds, timeLeftInSeconds As Integer Dim inspector As TGSInspector_Duration Set inspector = lic.Inspector maxDurationInSeconds = inspector.Duration usedDurationInSeconds = inspector.TimeUsed 'How many trial time left? timeLeftInSeconds = inspector.TimeLeft
This license model (Expire by Session Time) allows an entity can always be accessed (never expire) but in a limited time, we can get the session time left but cannot get the expiry date.
Dim maxSessionTime, sessionTimeUsed, timeLeftInSeconds As Integer Dim inspector As TGSInspector_SessionTime Set inspector = lic.Inspector maxSessionTime = inspector.MaxSessionTime sessionTimeUsed = inspector.TimeUsed timeLeftInSeconds = inspector.TimeLeft
There are two methods to activate your app, online and offline.
After user've made purchase of your app, you send a serial number to the customer as a proof of valid customer and the key to activate your app.
Dim rc As Long Dim success As Boolean If core.isServerAlive Then success = core.applySN(serial, rc) Else ' license server is not available! ' optionally fall back to offline activation... End If
In order to do offline activation, we need to go through three steps:
Dim requeseCode As String requestCode = core.DummyRequestCode
We are using dummy request code because the license server can deduce all valid actions from the customer's serial number.
You display the request code on UI, asking the customer to contact your support team for a valid license code, or if possible, let the customer uses another machine (or a mobile device) to generate the license code by himself/herself via the app's public App Web Activator.
Once the user input a license code, we can apply it to the app:
'user input the license code. Dim licenseCode As String Dim success As Boolean success = core.applyLicenseCode(licenseCode, serial);
SoftwareShield SDK allows you to revoke serial numbers to license server so that the revoked serial numbers can be reused in another machine or the same machine (after hardware upgrade, system re-install, etc.)
Dim serialToRevoke As String success = core.revokeSN(serialToRevoke)
After successful revoke, all those entities previously unlocked by this serial are locked.
success = core.revokeApp
After successful revoke, all previously unlocked entities are locked.
Revoke serial number is good for most cases, but there are other scenerios that the serial-based revoke won't work. For example, your license model is based on Pay-as-you-go concept, your app is not fully activated, the serial is used to extend the app's life span, so the unlock-lock based serial-number revoke does not make sense at all.
On machine A (sender):
Dim receiptSN As String receiptSN = core.uploadApp
On machine B (receiver):
success = core.applySN(receiptSN)
On machine A (sender):
Dim lic_backup As string lic_backup = core.exportApp
On machine B (receiver):
Dim mv As TMovePackage Dim success As Boolean Dim moveRequestCode As String 'the user reads the request code from app UI and gets license code from support team (or via App Web Activator) Dim licenseCode As string mv = core.createMovePackage( lic_backup ) If Core.IsServerAlive Then 'online import success = mp.importOnline(serial) Else 'offline import moveRequestCode = mp.getImportOfflineRequestCode 'user get the licenseCode... success = mp.importOffline(licenseCode) End If Set mv = Nothing
The workflow seems a little messy, but you do not have to fully support all online/offline cases in your app. The SoftwareShield SDK provides complete apis to support all possible use cases.
Sometimes you want to implement a logic to test if a serial number is still valid before app can run at client side. You can disable or delete a serial number at CheckPoint2 license management web portal, as a result you can remote control if the app should run by manipulating the serial number on the server side.
'the serial issued from app vendor Dim serial As String If Not core.isValidSN( serial ) Then core.lockAllEntities; 'quit app... End If
To handle SoftwareShield license events in VB6, you can add event handlers to interested events:
In GSApp.cls, there are all pre-defined events:
'Generic event handler Public Event OnEvent(ByVal eventId As Long) Public Event OnAppBegin() Public Event OnAppRun() Public Event OnAppExit() Public Event OnAppFirstRun() Public Event OnLicenseLoading() Public Event OnLicenseLoaded() Public Event OnAccessStarting(entity As TGSEntity) Public Event OnAccessStarted(entity As TGSEntity) Public Event OnAccessEnding(entity As TGSEntity) Public Event OnAccessEnded(entity As TGSEntity) Public Event OnAccessInvalid(entity As TGSEntity) Public Event OnAccessHeartBeat(entity As TGSEntity) Public Event OnUserEvent(ByVal eventId As Long, ByVal usrDataPtr As Long, ByVal usrDataSize As Long) 'Error handler Public Event OnError(ByVal err As GSErrorType, ByVal errCode As Long, ByVal errMsg As String)
To handle these events, you can add the following lines to the Form code file as following:
'Declare the instance of gs.App so that all events become visible in VB6 IDE Private WithEvents GSApp As TGSApp
Then in the VB6 IDE, you can choose the GSApp object and add event handler as usual:
In FormMain.frm we catch several events in the demo app:
Private WithEvents GSApp As TGSApp Private core As TGSCore 'Initialize SDK on form loading Private Sub Form_Load() 'We put the license file side by side with the exe, and pass the full path to it SdkInitialize ProductId, App.Path & "\" & LicenseFile, Password 'Assign GSApp so we can receive events Set GSApp = gs.App 'Assign the single gs.Core instance for later reference Set Core = gs.Core ... End Sub Private Sub GSApp_OnAppBegin() 'App launches, say hello... End Sub Private Sub GSApp_OnAppExit() Dim entity As TGSEntity ' Render Exit-UI Set entity = Core.Entities(0) If entity.Unlocked Then ' activated, do nothing ElseIf entity.Locked Then ' trial already expired, need license to run MsgBox ("your trial is expired, please activate now") Else ' trial mode... MsgBox ("your trial will expire in XXX") End If End Sub 'EVENT_ENTITY_TRY_ACCESS Private Sub GSApp_OnAccessStarting(entity As TGSEntity) If entity.Unlocked Then ' activated, do nothing... ElseIf entity.Locked Then ' trial already expired, need license to run ' render_activate_UI(entity) Else ' trial mode... End If End Sub 'EVENT_ENTITY_ACCESS_INVALID Private Sub GSApp_OnAccessInvalid(entity As TGSEntity) ' trial expired! ' render_activate_UI(entity) End Sub 'EVENT_ENTITY_ACCESS_HEARTBEAT Private Sub GSApp_OnAccessHeartBeat(entity As TGSEntity) ' check when the entity will expire, inspect its license parameter to give user feedback ' when 5 minutes left before expire... End Sub
So you can see that the SoftwareShield event handling in Visual Basic is pretty easy in IDE.