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.
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.
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.
Private FunctionGetLicenseLevel()As String DimpLicenseAsIAoInitializeSetpLicense =NewAoInitializeSelect CasepLicense.InitializedProductCaseesriLicenseProductCodeArcView GetLicenseLevel = "ArcView"CaseesriLicenseProductCodeArcEditor GetLicenseLevel = "ArcEditor"CaseesriLicenseProductCodeArcInfo GetLicenseLevel = "ArcInfo"End Select EndFunction
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.
DimpExporterAsIExporterSetpExporter =NewArcPressExporterJPEG ...DimhDcAsOLE_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:
Public FunctionGetArcPressLicense()As Boolean DimpUidAsUIDSetpUid =NewUID pUid.Value = "esriOutputExtensions.ArcPressExtension"DimpExtAdminAsIExtensionManagerAdminSetpExtAdmin =NewExtensionManager'Necessary in standalone applicationpExtAdmin.AddExtension pUid, 0DimpExtManagerAsIExtensionManagerSetpExtManager = pExtAdminDimpExtConfigAsIExtensionConfigSetpExtConfig = pExtManager.FindExtension(pUID)If(NotpExtConfig.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 successfullyGetArcPressLicense = (pExtConfig.State = esriESEnabled)End If If(NotGetArcPressLicense)Then_ MsgBox "No ArcPress licenses available"EndFunction
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.
Public SubReleaseArcPressLicense()DimpUidAsUIDSetpUid =NewUID pUid.Value = "esriOutputExtensions.ArcPressExtension"DimpExtManagerAsIExtensionManagerSetpExtManager =NewExtensionManagerDimpExtConfigAsIExtensionConfigSetpExtConfig = pExtManager.FindExtension(pUID)If(NotpExtConfig.State = esriESUnavailable)ThenpExtConfig.State = esriESDisabledEnd If EndSub
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.
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 levelfor example, ArcView, ArcEditor, or ArcInfofor 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.
Option Explicit Privatem_pAoInitializeAsIAoInitializePrivate SubForm_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.DimlicenseStatusAsesriLicenseStatus licenseStatus = CheckOutLicenses(esriLicenseProductCodeArcEditor)'Take a look at the licenseStatus to see if it failed'Not licensedIf(licenseStatus = esriLicenseNotLicensed)ThenMsgBox "You are not licensed to run this product" Unload Form1'The licenses needed are currently in useElseIf(licenseStatus = esriLicenseUnavailable)ThenMsgBox "There are insufficient licenses to run" Unload Form1'The licenses unexpectedly failed.ElseIf(licenseStatus = esriLicenseFailure)ThenMsgBox "Unexpected license failure please contact your administrator" Unload Form1'Already initialized (Initialization can only occur once)ElseIf(licenseStatus = esriLicenseAlreadyInitialized)ThenMsgBox "Your license has already been initialized; please check your implementation." Unload Form1'Everything was checked out successfully.ElseIf(licenseStatus = esriLicenseCheckedOut)ThenMsgBox "Licenses checked out successfully"End If End Sub Private FunctionCheckOutLicenses(productCodeAsesriLicenseProductCode)AsesriLicenseStatusDimlicenseStatusAsesriLicenseStatusSetm_pAoInitialize =NewAoInitialize CheckOutLicenses = esriLicenseUnavailable'Check the productCodelicenseStatus = m_pAoInitialize.IsProductCodeAvailable(productCode)If(licenseStatus = esriLicenseAvailable)Then'Initialize the licenselicenseStatus = m_pAoInitialize.Initialize(productCode)End IfCheckOutLicenses = licenseStatusEndFunction
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.
Private SubForm_Unload(CancelAs Integer)'Shutdownm_pAoInitialize.ShutdownEndSu
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:
Private FunctionSelectLicensedEditClasses()AsIEnumGxObjectDimpGxDialogAsIGxDialogSetpGxDialog =NewGxDialogDimpFiltersAsIGxObjectFilterCollectionSetpFilters = pGxDialog pFilters.RemoveAllFilters'Add filters common to all productspFilters.AddFilterNewGxFilterShapefiles,FalsepFilters.AddFilterNewGxFilterPGDBFeatureClasses,FalsepFilters.AddFilterNewGxFilterPGDBFeatureDatasets,FalsepFilters.AddFilterNewGxFilterPGDBTables,False DimpLicInfoAsIAoInitializeSetpLicInfo =NewAoInitialize'Add filters based on product level - ArcEditor, ArcInfoIf((pLicInfo.InitializedProduct = esriLicenseProductCodeArcEditor)Or_ (pLicInfo.InitializedProduct = esriLicenseProductCodeArcInfo))ThenpFilters.AddFilterNewGxFilterCoverageAnnotationClasses,FalsepFilters.AddFilterNewGxFilterCoverageFeatureClasses,FalsepFilters.AddFilterNewGxFilterCoverages,FalsepFilters.AddFilterNewGxFilterDimensionFeatureClasses,FalsepFilters.AddFilterNewGxFilterGeometricNetworks,FalsepFilters.AddFilterNewGxFilterInfoTables,FalsepFilters.AddFilterNewGxFilterRelationshipClasses,FalsepFilters.AddFilterNewGxFilterSDEFeatureClasses,FalsepFilters.AddFilterNewGxFilterSDEFeatureDatasets,FalsepFilters.AddFilterNewGxFilterSDETables,False End If WithpGxDialog .AllowMultiSelect =True.Title = "Select Editable data" .DoModalOpen 0, SelectLicensedEditClassesEnd With EndFunction
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.
Private FunctionDeleteDataset(pDatasetAsIDataset)As Boolean On Error GoToErrorHandler pDataset.Delete DeleteDataset =True Exit FunctionErrorHandler:If(Err.Number = FDO_E_NO_OPERATION_LICENSE)ThenMsgBox "You do not have a license that enables you to delete _ dataset " & pDataset.Name, vbCriticalElseMsgBox "Error Deleting Dataset " & pDataset.Name & vbCrLf & _ "Error Description : " & Err.Description, vbCriticalEnd If EndFunction
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.
Private SubStartEditWithCheck(pWorkspaceAsIWorkspace)DimpWorkspaceEditAsIWorkspaceEditSetpWorkspaceEdit = pWorkspace pWorkspaceEdit.StartEditingTrue DimpDatasetsAsIEnumDatasetSetpDatasets = pWorkspace.Datasets(esriDTFeatureClass) pDatasets.ResetDimpDatasetAsIDatasetDimpDatasetEditAsIDatasetEditSetpDatasetEdit = pDatasets.NextDimfailedClassesAs String Do Until(pDatasetEditIs Nothing)If(NotpDatasetEdit.isBeingEdited)Then SetpDataset = pDatasetEdit failedClasses = failedClasses & pDataset.Name & vbCrLfEnd If SetpDatasetEdit = pDatasets.NextLoop If(failedClasses <> "")Then_ MsgBox "Start edit failed for the following classes : " & _ failedClasses, vbCriticalEndSub
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.
Private FunctionAllOrNothingStartEdit(pWorkspaceAsIWorkspace)As Boolean DimpDatasetsAsIEnumDatasetSetpDatasets = pWorkspace.Datasets(esriDTFeatureClass) pDatasets.ResetDimpDatasetEditInfoAsIDatasetEditInfoSetpDatasetEditInfo = pDatasets.NextDo Until(pDatasetEditInfoIs Nothing)If(NotpDatasetEditInfo.CanEdit)Then Exit Function SetpDatasetEditInfo = pDatasets.NextLoop DimpWorkspaceEditAsIWorkspaceEditSetpWorkspaceEdit = pWorkspace pWorkspaceEdit.StartEditingTrueAllOrNothingStartEdit =True EndFunction
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: