Licensing your solutions  

ArcGIS Desktop licensing model

This topic is relevant for the following:
Product(s): ArcGIS Desktop: All
Version(s): 9.1, 9.2
Language(s): VB6
Experience level(s): New to ArcGIS development here



Developing ArcGIS Desktop applications should not be undertaken in isolation from the deployment of the final application. Currently, there are three possible deployments or software products with ArcGIS Desktop: ArcView, ArcEditor, and ArcInfo. There may be more deployment options in the future. As a developer you may need to know what product a user has installed so your code can be robust enough to work on all deployments or at least have the appropriate error checking. This maximizes the potential number of users for your components.

This topic outlines how to write code in a way that requires only one code base to support all possible deployment options, both at present and in the future.

License checking in ArcGIS Desktop

The object models for ArcView, ArcEditor, and ArcInfo are identical. All classes, interfaces, methods, and properties are present in all products. This means that the same DLLs containing the same components with the same GUIDs are installed for all deployments; in other words, code written on one deployment will successfully compile on another. What will differ for the various deployments is the behavior of certain method calls.

All the ESRI-developed components handle the possible deployment options in a unified manner. The functionality available with these different deployments is controlled via a license. This means that if a user installs a new license, the software does not require a reinstallation to access the functionality permitted under the new license.

For more information on the ArcGIS license manager, view the license manager reference guide under the ArcGIS > license manager Programs menu.

ArcObjects performs several types of license checking:

When executing code, no query interface call will fail because of a license issue, for this would break the rules of COM. If license checking were implemented at the query interface level, depending on licenses being checked in and out, the query interface call may succeed the first time but fail the next or vice versa.

It is likely that you will be interacting with more than one of these license-checking mechanisms. For instance, you may check for the appropriate component-level license; then, when working with individual methods, you will have to be aware of the license restrictions associated with these methods.

ESRI engineers use the same coding techniques outlined in this topic to write code that works with the various deployment options of ArcGIS. Using these techniques, you will be able to write your code to handle the various deployment models.

Application license checking

The simplest form of license checking for you to deal with is when your components are running within an ArcGIS Desktop application, since there is little for you to do. The license-checking procedures are contained within the ArcGIS applications, and the fact that your components are initialized means that the user has a valid ArcGIS license. However, determining what license is currently checked out by the user can be useful for working with licensing at the functional level.

To determine the level of license currently in use, use the AOInitialize coclass and the Initialize method on its IAOInitialize interface.

[Visual Basic 6]
Private Function GetLicenseLevel() As String
  Dim pLicense As IAoInitialize
  Set pLicense = New AoInitialize

  Select Case pLicense.InitializedProduct
    Case esriLicenseProductCodeArcView
      GetLicenseLevel = "ArcView"
    Case esriLicenseProductCodeArcEditor
      GetLicenseLevel = "ArcEditor"
    Case esriLicenseProductCodeArcInfo
      GetLicenseLevel = "ArcInfo"
  End Select
End Function

Extension license checking

ESRI desktop extension products, such as 3D Analyst or Spatial Analyst, provide additional functionality and components for ArcGIS Desktop users and developers. To use an extension, a valid extension license must be available. If you are using the desktop interface, a license is checked out when you select an extension in the Extension Manager dialog box. When you are developing, however, you must ensure the appropriate extension is checked out before making calls to objects within that extension, since you cannot guarantee the user has checked out an extension before running your code.

If you are developing an ArcGIS Engine component, you may use AoInitialize to check out an extension instead.

For example, if the following lines of code are executed in a VBA macro, an error will be raised when the StartExporting method is executed, since an ArcPress license has not been checked out. The method calls do not attempt to check one out; they only ensure that one already has been checked out. This gives you license usage control.

[Visual Basic 6]
Dim pExporter As IExporter
  Set pExporter = New ArcPressExporterJPEG
  ...
  Dim hDc As OLE_HANDLE
  hDc = pExporter.StartExporting

For the above code to execute without the license error, the ArcPress extension must be initialized before the call to the StartExporting method. The function below shows how to check out an ArcPress license:

[Visual Basic 6]
Public Function GetArcPressLicense() As Boolean
  Dim pUid As UID
  Set pUid = New UID
  pUid.Value = "esriOutputExtensions.ArcPressExtension"

  Dim pExtAdmin As IExtensionManagerAdmin
   Set pExtAdmin = New ExtensionManager
   'Necessary in standalone application
   pExtAdmin.AddExtension pUid, 0

  Dim pExtManager As IExtensionManager
  Set pExtManager = pExtAdmin
  Dim pExtConfig As IExtensionConfig
  Set pExtConfig = pExtManager.FindExtension(pUID)

  If (Not pExtConfig.State = esriESUnavailable) Then
    On Error Resume Next
     'Check the license out. Enabling the extension checks out a license.
     pExtConfig.State = esriESEnabled
    'Return TRUE if the license was checked out successfully
    GetArcPressLicense = (pExtConfig.State = esriESEnabled)
  End If

  If (Not GetArcPressLicense) Then _
    MsgBox "No ArcPress licenses available"
End Function

A license will fail to check out if you have exceeded the number of licenses available for a product.

Assuming that the process of exporting only requires access to the license for a short time, the license should be released upon completion of the export. Releasing the license means that another user can export using the same license; the only restriction is that the other user cannot export at the same time, assuming you only have one ArcPress license.

Note that license checking is per machine rather than per process. Checking out the same license in different processes on the same machine will only check out one license.

[Visual Basic 6]
Public Sub ReleaseArcPressLicense()
  Dim pUid As UID
  Set pUid = New UID
  pUid.Value = "esriOutputExtensions.ArcPressExtension"
  Dim pExtManager As IExtensionManager
  Set pExtManager = New ExtensionManager

  Dim pExtConfig As IExtensionConfig
  Set pExtConfig = pExtManager.FindExtension(pUID)

  If (Not pExtConfig.State = esriESUnavailable) Then
    pExtConfig.State = esriESDisabled
  End If
End Sub

If you are developing an extension to which you want to add license checking in a way similar to ESRI, you must follow certain rules when dealing with the configuration state of your extension. These rules are outlined in the ArcObjects Library Reference for the Framework library.

Component license checking

When embedding ArcObjects components within another application, careful thought must be given to license issues.

Before calling any other ArcObjects code, you must first initialize the application with a suitable license for it to run successfully. Failure to do so will result in application errors.

For more information on embedding ArcObjects components within other applications or to create standalone applications, see one of the SDKs for Building solutions with ArcGIS Engine.

Initialization is performed with the Initialize method on the IAoInitialize interface and establishes the product level—for example, ArcView, ArcEditor, or ArcInfo—for the duration of the application. The product license determines the functionality the application will be able to access. Once the product license has been initialized, it cannot be changed for the duration of the application's life, as it is not possible to reinitialize the application.

The following Visual Basic 6 code shows an example of intializing an application during the form load procedure.

[Visual Basic 6]
Option Explicit
Private m_pAoInitialize As IAoInitialize

Private Sub Form_Load()
  'This sample is designed to perform license initialization on a system
  'that may have access to a floating license. An ArcEditor license will be used.

  Dim licenseStatus As esriLicenseStatus
  licenseStatus = CheckOutLicenses(esriLicenseProductCodeArcEditor)

  'Take a look at the licenseStatus to see if it failed
  'Not licensed
  If (licenseStatus = esriLicenseNotLicensed) Then
    MsgBox "You are not licensed to run this product"
    Unload Form1
  'The licenses needed are currently in use
  ElseIf (licenseStatus = esriLicenseUnavailable) Then
    MsgBox "There are insufficient licenses to run"
    Unload Form1
  'The licenses unexpectedly failed.
  ElseIf (licenseStatus = esriLicenseFailure) Then
    MsgBox "Unexpected license failure please contact your administrator"
    Unload Form1
  'Already initialized (Initialization can only occur once)
  ElseIf (licenseStatus = esriLicenseAlreadyInitialized) Then
    MsgBox "Your license has already been initialized; please check your implementation."
    Unload Form1
  'Everything was checked out successfully.
  ElseIf (licenseStatus = esriLicenseCheckedOut) Then
    MsgBox "Licenses checked out successfully"
  End If
End Sub

Private Function CheckOutLicenses(productCode As esriLicenseProductCode) As esriLicenseStatus

  Dim licenseStatus As esriLicenseStatus
  Set m_pAoInitialize = New AoInitialize
  CheckOutLicenses = esriLicenseUnavailable

  'Check the productCode
  licenseStatus = m_pAoInitialize.IsProductCodeAvailable(productCode)
  If (licenseStatus = esriLicenseAvailable) Then
    'Initialize the license
    licenseStatus = m_pAoInitialize.Initialize(productCode)
  End If

  CheckOutLicenses = licenseStatus
End Function

The AoInitialize help topic in the ArcObjects Library Reference section contains more information and examples.

Before an application is shut down, the AOInitialize object must be shut down via the Shutdown method. This ensures that any ESRI libraries that have been used are unloaded in the correct order. Failure to do this may result in random crashes on exit due to the operating system unloading the libraries in the incorrect order.

The following Visual Basic 6 code shows an example of the Shutdown method being called in the form unload procedure associated with the example above.

[Visual Basic 6]
Private Sub Form_Unload(Cancel As Integer)
  'Shutdown
  m_pAoInitialize.Shutdown
End Su

Functional license checking

Interaction with the three previous forms of license checking in ArcObjects is relatively straightforward. Depending on the functionality accessed, the functional license checking is more involved.

A personal geodatabase is stored in the Microsoft Access .mdb format. An enterprise geodatabase is stored within an RDBMS.

The differences between ArcObjects software-based functionality available through ArcGIS deployments are centered on the geodatabase. ArcEditor and ArcInfo products have the same capabilities, and ArcView has reduced functionality.

ArcView can view all supported ArcGIS data sources, but only shapefiles and personal geodatabases can be edited. Geodatabase functionality is further refined to provide a user read access to all geodatabases. What can be created and edited within a personal geodatabase is further refined to prohibit the following:

Knowing this list of supported functionality will help you make decisions on whether licensing issues are of concern for the components you are developing.

As a developer, you have the choice to write proactive or reactive code when dealing with these functional license checks. Proactive code determines the license that is currently in use, which dictates the flow through the program. Reactive code does not perform up-front checking, but it does perform checks after the methods with license behavior are called. In reality, you will most often employ a mixture of both techniques.

An example of proactive code might involve an application that will display and edit data from a variety of data sources. You might choose to limit the data that a user can add to the application based on the license in use. This can be achieved in conjunction with the GxDialog coclass and a selection of GxObject filters, as illustrated below:

[Visual Basic 6]
Private Function SelectLicensedEditClasses() As IEnumGxObject
  Dim pGxDialog As IGxDialog
  Set pGxDialog = New GxDialog

  Dim pFilters As IGxObjectFilterCollection
  Set pFilters = pGxDialog
  pFilters.RemoveAllFilters
  'Add filters common to all products  
  pFilters.AddFilter New GxFilterShapefiles, False
  pFilters.AddFilter New GxFilterPGDBFeatureClasses, False
  pFilters.AddFilter New GxFilterPGDBFeatureDatasets, False
  pFilters.AddFilter New GxFilterPGDBTables, False

  Dim pLicInfo As IAoInitialize
  Set pLicInfo = New AoInitialize

  'Add filters based on product level - ArcEditor, ArcInfo
  If ((pLicInfo.InitializedProduct = esriLicenseProductCodeArcEditor) Or _
   (pLicInfo.InitializedProduct = esriLicenseProductCodeArcInfo)) Then
   pFilters.AddFilter New GxFilterCoverageAnnotationClasses, False
    pFilters.AddFilter New GxFilterCoverageFeatureClasses, False
    pFilters.AddFilter New GxFilterCoverages, False
    pFilters.AddFilter New GxFilterDimensionFeatureClasses, False
    pFilters.AddFilter New GxFilterGeometricNetworks, False
    pFilters.AddFilter New GxFilterInfoTables, False
    pFilters.AddFilter New GxFilterRelationshipClasses, False
    pFilters.AddFilter New GxFilterSDEFeatureClasses, False
    pFilters.AddFilter New GxFilterSDEFeatureDatasets, False
    pFilters.AddFilter New GxFilterSDETables, False
  End If

  With pGxDialog
    .AllowMultiSelect = True
    .Title = "Select Editable data"
    .DoModalOpen 0, SelectLicensedEditClasses
  End With
End Function

Functional changes take two forms. A method either returns an appropriate error HRESULT to signal that there is not an appropriate license available to successfully execute the method, or it returns a successful HRESULT, but the behavior of the method changes to reflect the available licenses.

As an example of the first kind of functional license check, the Delete method on the IDataset interface may return the HRESULT FDO_E_NO_OPERATION_LICENSE to say that you did not have the correct license to complete the operation. This type of error can be easily found reactively, then reported to the user using an informative message box.

[Visual Basic 6]
Private Function DeleteDataset(pDataset As IDataset) As Boolean
  On Error GoTo ErrorHandler

  pDataset.Delete
  DeleteDataset = True

  Exit Function
ErrorHandler:
  If (Err.Number = FDO_E_NO_OPERATION_LICENSE) Then
    MsgBox "You do not have a license that enables you to delete _
            dataset " & pDataset.Name, vbCritical
  Else
    MsgBox "Error Deleting Dataset " & pDataset.Name & vbCrLf & _
           "Error Description : " & Err.Description, vbCritical
  End If
End Function
The alternative is to determine the license in use and the type of dataset that the user wants to delete, then decide whether or not to allow the DeleteDataset function to be called.

The more difficult scenario is when the behavior of a method changes depending on the available licenses. For instance, assume that the user has defined a personal geodatabase using ArcEditor and has a number of classes defined. Two of these feature classes have a relationship class. This means that as long as an ArcEditor or ArcInfo license is used to edit the database, all classes are editable. If an ArcView user starts editing on the database, the start edit operation will succeed for all the classes except the two with the relationship. The method's behavior has changed, but there was no failure HRESULT returned from the method call since it successfully started editing all the other classes. In this case, you must perform another step after calling StartEdit to determine whether or not the start edit operation was successful on all classes. If you find that it was not successful, you can retrieve the reason from the database and present that information to the user or perhaps configure your tools accordingly.

[Visual Basic 6]
Private Sub StartEditWithCheck(pWorkspace As IWorkspace)
  Dim pWorkspaceEdit As IWorkspaceEdit
  Set pWorkspaceEdit = pWorkspace
  pWorkspaceEdit.StartEditing True
  Dim pDatasets As IEnumDataset

  Set pDatasets = pWorkspace.Datasets(esriDTFeatureClass)
  pDatasets.Reset

  Dim pDataset As IDataset
  Dim pDatasetEdit As IDatasetEdit
  Set pDatasetEdit = pDatasets.Next

  Dim failedClasses As String
  Do Until (pDatasetEdit Is Nothing)
    If (Not pDatasetEdit.isBeingEdited) Then
      Set pDataset = pDatasetEdit
      failedClasses = failedClasses & pDataset.Name & vbCrLf
    End If

    Set pDatasetEdit = pDatasets.Next
  Loop
  If (failedClasses <> "") Then _
    MsgBox "Start edit failed for the following classes : " & _
         failedClasses, vbCritical
End Sub

The above function can be changed slightly to perform the checking proactively. In the following function, the class is checked to see if it can be edited using its IDatasetEditInfo interface. This is the preferred method of checking since there are a number of reasons, in addition to the license issues discussed here, that a user may not be able to start editing a feature class. For more information, see the overview for the Geodatabase library in the ArcObjects Library Reference section.

[Visual Basic 6]
Private Function AllOrNothingStartEdit(pWorkspace As IWorkspace) As Boolean
  Dim pDatasets As IEnumDataset
  Set pDatasets = pWorkspace.Datasets(esriDTFeatureClass)
  pDatasets.Reset
  Dim pDatasetEditInfo As IDatasetEditInfo
  Set pDatasetEditInfo = pDatasets.Next

  Do Until (pDatasetEditInfo Is Nothing)
    If (Not pDatasetEditInfo.CanEdit) Then Exit Function
    Set pDatasetEditInfo = pDatasets.Next
  Loop

  Dim pWorkspaceEdit As IWorkspaceEdit
  Set pWorkspaceEdit = pWorkspace

  pWorkspaceEdit.StartEditing True
  AllOrNothingStartEdit = True
End Function

When designing your functionality, being aware of these license issues will help you create a solid application that will work on any deployment of the ArcGIS functionality.

In general, in any application you should always:

Using the following tables will help you decide when it is appropriate to check for license-related HRESULTs. You should not treat this as a fixed list of method calls since changes in ArcGIS deployments may result in changes to the functional license-checking routines.

The following table lists the license-related HRESULTs:


The following tables list the method calls that can return license-related HRESULTs: