Previous | Index | Next 

[PRB] Common problems when generating an ActiveX wrapper with AxWrapperGen

AxWrapperGen is a separate command-line utility that should be used to produce one wrapper class for each ActiveX control used by the VB6 application being migrated.

We recommend that you read the following whitepapers before using AxWrapperGen:

The first thing to do after generating a wrapper class is having a look at the generated source code, in the region named “Instructions”. Here we report the text you can find in that region. The most important items are in boldface.


  1. Ensure that the name you have selected for the .NET project (ie the argument of /project command line switch) doesn't match the name or the namespace of the ActiveX control. If these name match, you will receive a large number of compilation errors. In this case, change the project name in the Application page of the My Project folder.
  2. ensure that original control name is correct (this is the 1st argument of VB6Object attribute) this string must match the control string as seen in VB6 Object Browser
  3. specify an AlternateName value for the VB6Object attribute if adding an instance of the control by means of the Controls.Add method requires that you specify a different name. Example: "MSComctlLib.TreeCtrl.2" for the TreeView control)
  4. assign the IgnoreMembers property a pipe-delimited list of members to be ignored, if any. Example: "Negotiate|TransparentColor"
  5. assign the TranslateProperties property a comma-delimited list of (oldname=namename) members. Example: "Bindings=DataBindings,MaskFormat=Format"
  6. if control supports data-binding then
      edit the "BoundValue" and "BoundPropertyChanged" regions to ensure that name and type of bound property is correct
    else
      remove the "Implements IVB6BoundControl" statement
      remove the "-- Data-binding support" region
    NOTE: if the ActiveX control exposes its own DataXxxx, these elements are automatically removed
  7. if control does *not* support "classic" (VB3-style) drag-and-drop (e.g. DragIcon property and Drag method)
      remove the "Implements IClassicDragDrop" statement
      remove the "-- Classic drag-and-drop" region
  8. rename members whose name matches a VB.NET keyword or the name of another member. (For a COM component it is legal to expose a property and an event with same name, but this isn't allowed in .NET therefore one of the members must be renamed.) This step often requires that you modify the code in two or more points.

    Example: assume that the original COM component exposes an event named Error, which is a reserved VB.NET keyword. This is the code that AxWrapperGen generates:

    Public Shadows Event Error As VB6BeforePageBreakEventHandler
    Private Sub Control_Error(ByVal sender As Object, _ ByVal e As AxVSFlex8L._IVSFlexGridEvents_ErrorEvent) Handles MyBase.Error VB6BeforePageBreakEventDispatcher.Raise(Me, "Error", e.errorCode, e.showMsgBox) End Sub

    You must rename this event to something else, for example Error6. You must edit both the Event statement and the code that invokes the VB6BeforePageBreakEventDispatcher.Raise method:

    Public Shadows Event Error6 As VB6BeforePageBreakEventHandler
    Private Sub Control_Error(ByVal sender As Object, _ ByVal e As AxVSFlex8L._IVSFlexGridEvents_ErrorEvent) Handles MyBase.Error VB6BeforePageBreakEventDispatcher.Raise(Me, "Error6", e.errorCode, e.showMsgBox) End Sub

    Next, you must inform VB Migration Partner that you've renamed the event. You do it by setting the TranslateEvents property of the VB6Object attribute that precedes the Class statement:

    TranslateEvents:="Error=Error6"
    
  9. Check whether there are two or more properties with same name but different argument syntax. These properties may be the result of a combination of get/set methods with different syntax. VS.NET prevents you from displaying a form at design time if the form contains such a control. You should delete all the overloads except one or (preferably) merge the overloads in a single property that takes optional arguments.

    Example: when applied to FlexGrid control, AxWrapperGen generates the following duplicated ArchiveInfo properties:

    Public ReadOnly Property ArchiveInfo(ByVal arcFileName As String, _
                     ByVal infoType As VSFlex8L.ArchiveInfoSettings) As Object
         Get
             Return MyBase.get_ArchiveInfo(arcFileName, infoType)
         End Get
    End Property
    
    Public ReadOnly Property ArchiveInfo(ByVal arcFileName As String, _
                     ByVal infoType As VSFlex8L.ArchiveInfoSettings, _
                     ByVal index As Object) As Object
         Get
             Return MyBase.get_ArchiveInfo(arcFileName, infoType, index)
         End Get
    End Property
    

    You can merge the two code blocks in a single property by making the 3rd argument Optional and writing the code that delegates to either get_ArchiveInfo method in the base class, depending on whether the optional argument has been omitted:

    Public ReadOnly Property ArchiveInfo(ByVal arcFileName As String, _
                     ByVal infoType As VSFlex8L.ArchiveInfoSettings, _
                     Optional ByVal index As Object = Nothing) As Object
         Get
             If index Is Nothing Then
                 Return MyBase.get_ArchiveInfo(arcFileName, infoType)
              Else
                 Return MyBase.get_ArchiveInfo(arcFileName, infoType, index)
              End If
         End Get
    End Property
    
  10. check whether the wrapper class contains members that weren't in the original ActiveX control. We have noticed that AxImp.exe changes the name of a member if the AxHost base class exposes a member with same name. For example, a property named EditMode might be converted into CtlEditMode, and Text might be converted into CtlText.

    You can't change the names of these members (else the wrapper class would crash the Visual Studio .NET form designer), but you should edit the TranslateMembers property of the VB6Object attribute to specify which transformations might be necessary when converting the VB6 code that accesses those members, for example:

    ... TranslateMembers:="Text=CtlText,EditMode=CtlEditMode", ...
    

      ( a list of members for which this point applies follows )

  11. check all the properties in the "Other Properties" region. Properties in this region might require manual fixing for the following two reasons:
    1. they take or return values that are affected by the current ScaleMode Hint: use methods in the VB6Utils class to convert among different scale modes
    2. they might be read-only properties or runtime-only properties that shouldn't appear in Visual Studio's property grid. Hint: prefix the Property definition with the following attributes:
      <Browsable(False)> _           
      <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
      Public Property .....
      
    The Browsable attribute hides the property in the Property window; the DesignerSerializationVisibility attribute tells Visual Studio that the property's value must not be initialized in the *.Designer.vb file.
  12. check that no property is flagged with the following remark:
    ' TODO: .NET properties cannot have ByRef parameters. Manually fix this code as necessary.
    Each ByRef parameter in a property causes a compilation error. You can fix these errors in two ways:
    1. if the OCX documentation specifies that no value is actually returned through the parameter, you can safely each ByRef keyword into ByVal
    2. else, you need to preserve the ByRef semantics; in this case you can only split the property into two methods, get_propname and set_propname (you will also need to modify code in the client application.)
  13. once the code has no compilation errors, compile the solution in Release mode and then copy the following files to VB Migration Partner's installation folder (or a folder pointed to by an AddLibraryPath pragma)

    <the list of files to be copied>

    You can find all these files in the <releasefoldername> folder.
  14. you should be now able to migrate a VB6 form that hosts the ActiveX controls and obtain a VB.NET project that has no compilation error. However, you might still experience runtime errors.

    A common error with ActiveX wrappers is that VB Migration Partner mistakenly generates one or more properties in the *.Designer.vb that shouldn't be there. For example, we have met this problem with a property named LicenseKey. Such spurious properties typically cause an exception when you display the form at design-time or when you run the VB.NET project. In such cases you must prevent VB MigrationPartner from generating a property with that name. You achieve this by additing the name of the propertyto the IgnoreMembers property of the VB6Object attribute (see point 3).

  15. If you notice that the ActiveX works well inside the VB.NET project except it doesn't retain the size (i.e. Width and Height properties), you should uncomment a group of statements in the ParseProperties method of the <controlname>_Support class, as explained by the TODO comment.

 

Previous | Index | Next