preload

GP/QTP Automation: Overcoming VBScript limitation with Excel macros

Posted by Albert Gareev on Sep 23, 2009 | Categories: Great PlainsSource code

All related posts: Reference Page – GP/QTP Automation  

VBScript limitation 

Since VBscript supports only Variant type attempts to use variable in a COM call with an argument defined as “[in, out] BSTR * “ reasonably end with “Type mismatch” error. This error is generated by the COM object itself rather then VBscript interpreter since the object gets string instead of a pointer.

ExecuteSanScript method uses “string pointer” for parameter exchange which is not supported in VBScript that has only and single “variant” data type. Passing in VBScript variables causes “Type Mismatch”.

There are 3 ways to overcome the identified limitation.

  • Do not use “string pointer” type in the COM function. – Not applicable way in case of QTP/GP automation as we have the vendor provided code.
  • Implement in C++ (or other similar language) COM compatible DLL module with the all library functions directly operating with Dynamics.Application object and serving as a wrapping bridge to convert “string pointer” type to “variant” and backward.
  • Use existing COM object that may act both as Automation Server and Automation Client.

Excel.Application object is a good candidate as it has built-in internal Excel.VBA execution engine.

Documentation 

The following portal could be useful both for beginners and advanced Excel.VBA programmers and users: http://www.functionx.com/excel/index.htm 

Excel Object Model Overview from Microsoft contains full description and some examples

http://msdn.microsoft.com/en-us/library/wss56bz7(VS.80).aspx 

Creating Excel macro module 

1)     Start Excel application and create new workbook

2)     Go to “Main Menu \ Tools \ Macro \ Visual Basic Editor”

3)     Right-click on the VBA Project panel and insert Code Module and Class Module

4)     Select Class Module and on the Properties panel define its name: ParamHandlerClass. Get to the Code Editor and on the “General/Declarations” section define (type in or copy/paste) parameter names:


Public Value1 As String
Public Value2 As String
Public Value3 As String
Public Value4 As String

5) Select Code Module and get to the Code Editor. Copy the following code.


Option Explicit

Public GPApp As Object

Public ParamHandler As ParamHandlerClass

Public Function Init()
    Dim intRC
    Set GPApp = GetObject("", "Dynamics.Application")
    Set ParamHandler = New ParamHandlerClass
    intRC = GPApp.SetParamHandler(ParamHandler)
End Function

Public Function Done()
    Set GPApp = Nothing
    Set ParamHandler = Nothing
End Function

Public Function GetDexActiveWindow()
    Dim intRC As Integer
    Dim sFormName As String
    Dim sWindowName As String
    Dim sDictName As String
    Dim sTitle As String

    'Clean
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 1) = ""
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 2) = ""
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 3) = ""
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 4) = ""

    'Call method
    intRC = GPApp.GetDexActiveWindow(sFormName, sWindowName, sDictName, sTitle)

    'Store parameters
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 1) = sFormName
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 2) = sWindowName
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 3) = sDictName
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 4) = sTitle

End Function

'Note.
'SanScript's string data type is limited up to 255 chars
'Therefore contents of the list is retrieved in a loop of calls
'and one by one items are collected in VB
Public Function GetListContent()
    Dim intRC As Integer
    Dim intCount, Iter As Integer
    Dim sCode, sErrMsg As String
    Dim sListName, sResult As String

    sListName = Workbooks.Item(1).Sheets.Item(1).Cells(2, 1)

    'Get list content count
    sCode = "local integer count; count = countitems(" & sListName & "); OLE_SetProperty(""Value1"", str(count));"

    intRC = GPApp.ExecuteSanScript(sCode, sErrMsg)
    If intRC <> 0 Then
        Workbooks.Item(1).Sheets.Item(1).Cells(2, 5) = intRC
        Workbooks.Item(1).Sheets.Item(1).Cells(2, 4) = sErrMsg
        Exit Function
    End If

    intCount = ParamHandler.Value1
    If intCount = 0 Then
        Workbooks.Item(1).Sheets.Item(1).Cells(2, 5) = -1
        Workbooks.Item(1).Sheets.Item(1).Cells(2, 4) = "The list is empty"
        Exit Function
    End If

    'Get first element
    sCode = "OLE_SetProperty(""Value1"", itemname(" & sListName & ", 1));"
    intRC = GPApp.ExecuteSanScript(sCode, sErrMsg)
    If intRC <> 0 Then
        Workbooks.Item(1).Sheets.Item(1).Cells(2, 5) = intRC
        Workbooks.Item(1).Sheets.Item(1).Cells(2, 4) = sErrMsg
        Exit Function
    End If

    sResult = ParamHandler.Value1

    'Loop and retrieve the rest
    For Iter = 2 To intCount
        sCode = "OLE_SetProperty(""Value1"", itemname(" & sListName & ", " & Iter & "));"
        intRC = GPApp.ExecuteSanScript(sCode, sErrMsg)
        If intRC <> 0 Then
            Workbooks.Item(1).Sheets.Item(1).Cells(2, 5) = intRC
            Workbooks.Item(1).Sheets.Item(1).Cells(2, 4) = sErrMsg
            Exit Function
        End If
        sResult = sResult & Chr(10) & ParamHandler.Value1
    Next

    'Store result
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 5) = 0
    Workbooks.Item(1).Sheets.Item(1).Cells(2, 1) = sResult

End Function

6)     Save and close Excel and Excel.VBA windows.

Next posts will demonstrate examples on using VB macros called by VBScript from within QTP.

If someone experiences difficulties creating Excel file, you can download it.

If you have any additional questions on the code samples presented you’re welcome to put them in comments for this post.


  • 2 responses to "GP/QTP Automation: Overcoming VBScript limitation with Excel macros"

  • Gary
    21st July 2013 at 2:01

    I have read a few excellent stuff here. Certainly value bookmarking for revisiting.
    I wonder how a lot effort you set to create this type of wonderful informative website.

  • Rolland
    23rd September 2014 at 11:32

    Magnificient post, very informative.

Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported
This work by Albert Gareev is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported.