Calling DLL Functions From Tests - Tutorial

Applies to TestComplete 15.47, last modified on January 20, 2023

To properly call a DLL routine from your test, you need to perform a number of operations. In this tutorial, we will illustrate how you can call DLL routines by giving an example. We will describe calling the DrawTextExA function from the User32.dll library.

In the tutorial, we will consider the following steps:

At the end of the tutorial, you can find the full script code obtained as a result of performing these step-by-step instructions.

In this tutorial we will consider calling routines from the User32.dll library by using methods of the DLL object. This object is used to call routines from dynamic libraries of the same “bitness” (that is, only 32- or 64-bit libraries). If you need to call routines from both 32- and 64-bit libraries in your test, first of all, you need to create an IDLLAccessProcess helper object that provides scripting access to a program environment for loading DLLs of a certain “bitness”. Then, you need to work with your libraries of a certain “bitness” in a way similar to the one described below in this topic with only one difference: you need to call the appropriate methods from the IDLLAccessProcess object instead of calling them from the DLL program object as it is described below (this concerns the New, Load, DefineType and DefineDLL methods that are provided both by the DLL and IDLLAccessProcess objects). To create an IDLLAccessProcess object, call the DLL.DefineEnvironment or DLL.DefineEnvironmentByDLL method. For more information about such environments, see Specifics of Using 32- and 64-bit DLLs.

1. Defining DLL Type

Before calling routines from a DLL, you should define the type of this DLL and type of the desired functions. To define a new DLL type, use the DLL.DefineDLL method:

JavaScript, JScript

Def_DLL = DLL.DefineDLL("USER32");

Python

Def_DLL = DLL.DefineDLL("USER32")

VBScript

Set Def_DLL = DLL.DefineDLL("USER32")

DelphiScript

Def_DLL := DLL.DefineDLL('USER32');

C++Script, C#Script

Def_DLL = DLL["DefineDLL"]("USER32");

DefineDLL returns a helper object, IDefineDLL, which is used to define the type of routines in the DLL.

Note: When you define a new DLL type, it is recommended to have the same type name and file name (without the extension) of the desired DLL. In this case, you will not have to specify the type name when loading the DLL in memory. For more information, see the Loading DLL in Memory step below in this topic.

2. Defining Parameter Types

The TestComplete engine processes OLE-compatible and OLE-incompatible data types differently:

  • OLE-compatible data types can be processed by the TestComplete engine as is.

  • OLE-incompatible data types require specific processing.

So it is important to determine the parameter types.

Function declaration

DrawTextExA is declared in the following way:

int DrawTextExA(
  HDC hdc,
  LPSTR lpchText,
  int cchText,
  LPRECT lprc,
  UINT format,
  LPDRAWTEXTPARAMS lpdtp);

Analyzing Function Parameters
Parameters Description OLE-compatible
hdc Device context to draw text on. The type of this parameter is HDC. TestComplete can work with it as with an integer. +
lpchText String to be drawn. Though string is an OLE-compatible type, it requires specific preparations when calling a routine from a DLL. +
cchText Number of characters in the lpchText string. Integer. +
lprc Specifies the rectangle where the text is drawn. This parameter is not OLE-compatible as it points to a structure.
format Specifies the formatting options (alignment, clipping, etc.). TestComplete can work with this parameter as with an integer. +
lpdtp Points to the structure that specifies additional formatting options. This parameter is a pointer to the DRAWTEXTPARAMS structure. It is not OLE-compatible.
Defining Parameter Types for OLE-Incompatible Types

The information below illustrates how you can define OLE-incompatible types in TestComplete. The DrawTextExA function has two OLE-incompatible parameters: lprc (the pointer to the RECT structure) and lpdtp (the pointer to the DRAWTEXTPARAMS structure).

Defining the lprc parameter. Call the DLL.DefineType method, that registers the new data type in TestComplete and returns the ID of the new type. This ID can be used then to define other types or function parameters.

Note: DefineType registers only the data type, but does not create a variable of this type. To create variables of the new type, call DLL.New.

The following code illustrates the use of DefineType:

JavaScript, JScript

Def_Rect = DLL.DefineType("RECT",
                vt_i4, "left", vt_i4, "top",
                vt_i4, "right", vt_i4, "bottom");

Python

Def_Rect = DLL.DefineType("RECT", VT_I4, "left", VT_I4, "top", VT_I4, "right", VT_I4, "bottom")

VBScript

Def_Rect = DLL.DefineType("RECT", _
                vt_i4, "left", vt_i4, "top", _
                vt_i4, "right", vt_i4, "bottom")

DelphiScript

Def_Rect := DLL.DefineType('RECT',
                 vt_i4, 'left', vt_i4, 'top',
                 vt_i4, 'right', vt_i4, 'bottom');

C++Script, C#Script

Def_Rect = DLL["DefineType"]("RECT",
                 vt_i4, "left", vt_i4, "top",
                 vt_i4, "right", vt_i4, "bottom");

The parameters of the DefineType method are described below:

  • The first parameter is the name of the new type. This name is used later in a call to the DLL.New method.

  • The other parameters can be divided into pairs: Member type, Member name:

    • The member type is specified by a constant built in TestComplete or by a type ID returned by the previous call to DefineType. For detailed description of constants that define member types, see IDefineDLL.DefineProc. If a member is passed by a reference, you must specify the vt_byref constant when defining the member type. The Parameter Types for C++ Routines and Structures and Parameter Types for Delphi Routines and Structures topics illustrate what constants you can use to specify parameter types for C++ and Delphi routines and structures.

    • The member names are used to access the structure members in scripts. That is why they must agree with the naming rules of the scripting language you use. Also, member names must be unique within the structure.

Defining the lpdtp parameter. Do it similarly to the approach described above.

JavaScript, JScript

Def_DrawTextParams = DLL.DefineType("DRAWTEXTPARAMS",
                                vt_i4, "cbSize",
                                vt_i4, "iTabLength",
                                vt_i4, "iLeftMargin",
                                vt_i4, "iRightMargin",
                                vt_i4, "uiLengthDrawn");

Python

Def_DrawTextParams = DLL.DefineType("DRAWTEXTPARAMS", VT_I4, "cbSize", VT_I4, "iTabLength", VT_I4, "iLeftMargin", VT_I4, "iRightMargin", VT_I4, "uiLengthDrawn")

VBScript

Def_DrawTextParams = DLL.DefineType("DRAWTEXTPARAMS", _
                                vt_i4, "cbSize", _
                                vt_i4, "iTabLength", _
                                vt_i4, "iLeftMargin", _
                                vt_i4, "iRightMargin", _
                                vt_i4, "uiLengthDrawn")

DelphiScript

Def_DrawTextParams := DLL.DefineType('DRAWTEXTPARAMS',
                                 vt_i4, 'cbSize',
                                 vt_i4, 'iTabLength',
                                 vt_i4, 'iLeftMargin',
                                 vt_i4, 'iRightMargin',
                                 vt_i4, 'uiLengthDrawn');

C++Script, C#Script

Def_DrawTextParams = DLL["DefineType"]("DRAWTEXTPARAMS",
                                 vt_i4, "cbSize",
                                 vt_i4, "iTabLength",
                                 vt_i4, "iLeftMargin",
                                 vt_i4, "iRightMargin",
                                 vt_i4, "uiLengthDrawn");

3. Declaring Function Type

Before calling a routine from a DLL, we should define the routine type in TestComplete. In this way, we inform TestComplete about the function name, the parameter and the result type.

Note: If the DLL was built with debug information, there is no need to define routine types manually. TestComplete takes information on routine types from debug information in this case. Thus, this step is optional if your DLL contains debug information.

To define the routine, call the IDefineDLL.DefineProc method:

JavaScript, JScript

Def_DLL.DefineProc("DrawTextExA",
                          vt_i4, vt_lpstr, vt_i4,
                          Def_Rect, vt_i4,
                          Def_DrawTextParams, vt_i4);

Python

Def_DLL.DefineProc("DrawTextExA", VT_I4, VT_LPSTR, VT_I4, Def_Rect, VT_I4, Def_DrawTextParams, VT_I4)

VBScript

Call Def_DLL.DefineProc("DrawTextExA", _
                          vt_i4, vt_lpstr, vt_i4, _
                          Def_Rect, vt_i4, _
                          Def_DrawTextParams, vt_i4)

DelphiScript

Def_DLL.DefineProc('DrawTextExA',
                           vt_i4, vt_lpstr, vt_i4,
                           Def_Rect, vt_i4,
                           Def_DrawTextParams, vt_i4);

C++Script, C#Script

Def_DLL["DefineProc"]("DrawTextExA",
                           vt_i4, vt_lpstr, vt_i4,
                           Def_Rect, vt_i4,
                           Def_DrawTextParams, vt_i4);

The parameters of the DefineProc method are described below:

  • The first parameter is required. It specifies the routine name as it is declared in the dynamic link library. This name is used to call the routine in script code.

  • The last parameter is required. It specifies the type of the result value. It can be one of the constants built in TestComplete or a type ID created by the DefineType method. Since DrawTextExA returns an integer value, we have specified vt_i4 as the last parameter.

    Note: You must always specify the type of the result value. If a routine does not return any value, use vt_empty or vt_void
  • The other parameters of the DefineProc method specify the types of parameters of the DrawTextExA function. As you can see, they can be constants built in TestComplete or type IDs generated by DLL.DefineType. Despite the fact that the RECT and DRAWTEXTPARAMS structures are passed by reference, we did not use the vt_byref constant in the function declaration. vt_byref is ignored in function declarations as structures are always passed by reference.

Make sure you correctly specified the parameter types. Incorrect definition of parameter types in certain cases may cause TestComplete to shut down (this happens because erroneous definitions may cause incorrect stack processing).

4. Loading DLL in Memory

To call a routine from a dynamic link library, this library must be loaded in memory. To load the library, call the DLL.Load method. For example:

JavaScript, JScript

Lib = DLL.Load("C:\\Windows\\System32\\USER32.DLL", "USER32");

Python

Lib = DLL.Load("C:\\Windows\\System32\\USER32.DLL", "USER32")

VBScript

Set Lib = DLL.Load("C:\Windows\System32\USER32.DLL", "USER32")

DelphiScript

Lib := DLL.Load('C:\Windows\System32\USER32.DLL', 'USER32');

C++Script, C#Script

Lib = DLL["Load"]("C:\\Windows\\System32\\USER32.DLL", "USER32");

The DLL.Load method has two parameters:

  • The first parameter specifies the name and path to the desired dynamic link library.

  • The second parameter specifies the name of the defined DLL type.

That is, DLL.Load not only loads the DLL, but also binds the declared function types to actual code.

Note that since User32.dll is a system library, we can omit specifying the path in the first parameter. (For more information on how DLLs will be searched for, see DLL.Load.) Also, we can omit specifying its extension and even the name of the DLL type, because it is the same as the name of the DLL file. The following example is a shorter version of the code that loads the DLL:

JavaScript, JScript

Lib = DLL.Load("USER32");

Python

Lib = DLL.Load("USER32");

VBScript

Set Lib = DLL.Load("USER32")

DelphiScript

Lib := DLL.Load('USER32');

C++Script, C#Script

Lib = DLL["Load"]("USER32");

The WOW64 subsystem may redirect calls to some system libraries when you work with 32-bit applications. To load a library of a particular bitness, specify the full path to the required library.

5. Specifying Parameter Values

Before calling routines from DLLs and passing values through their parameters, you must create variables for parameters that have OLE-incompatible data types like structures and strings and fill them with the needed data in order to pass them properly through the routine parameters.

Filling structures with data. Before calling DrawTextExA, we must create the RECT and DRAWTEXTPARAMS structures and assign values to their members. To create a structure, use the DLL.New method. It allocates, creates and returns an object that represents the structure in scripts (the method also fills the memory block allocated for the structure with zeros). To access structure members in scripts, use names specified in the DefineType method:

JavaScript, JScript

// Creates the RECT structure
r = DLL.New("RECT");
// Assigns values to structure members
r.left = 50;
r.top = 50;
r.right = 350;
r.bottom = 100;

// Creates the DRAWTEXTPARAMS structure
dtp = DLL.New("DRAWTEXTPARAMS");
// Assigns values to structure members
dtp.cbSize = 20; // Structure size
dtp.iTabLength = 2;
dtp.iLeftMargin = 2;
dtp.iRightMargin = 2;
dtp.uiLengthDrawn = 0;

Python

# Creates the RECT structure
r = DLL.New("RECT")
# Assigns values to structure members
r.left = 50
r.top = 50
r.right = 350
r.bottom = 100

# Creates the DRAWTEXTPARAMS structure
dtp = DLL.New("DRAWTEXTPARAMS")
# Assigns values to structure members
dtp.cbSize = 20 # Structure size
dtp.iTabLength = 2
dtp.iLeftMargin = 2
dtp.iRightMargin = 2
dtp.uiLengthDrawn = 0

VBScript

' Creates the RECT structure
Set r = DLL.New("RECT")
' Assigns values to structure members
r.left = 50
r.top = 50
r.right = 350
r.bottom = 100

' Creates the DRAWTEXTPARAMS structure
Set dtp = DLL.New("DRAWTEXTPARAMS")
' Assigns values to structure members
dtp.cbSize = 20 ' Structure size
dtp.iTabLength = 2
dtp.iLeftMargin = 2
dtp.iRightMargin = 2
dtp.uiLengthDrawn = 0

DelphiScript

// Creates the RECT structure
r := DLL.New('RECT');
// Assigns values to structure members
r.left := 50;
r.top := 50;
r.right := 350;
r.bottom := 100;
 
// Creates the DRAWTEXTPARAMS structure
dtp := DLL.New('DRAWTEXTPARAMS');
// Assigns values to structure members
dtp.cbSize := 20; // Structure size
dtp.iTabLength := 2;
dtp.iLeftMargin := 2;
dtp.iRightMargin := 2;
dtp.uiLengthDrawn := 0;

C++Script, C#Script

// Creates the RECT structure
r = DLL["New"]("RECT");
// Assigns values to structure members
r["left"] = 50;
r["top"] = 50;
r["right"] = 350;
r["bottom"] = 100;

// Creates the DRAWTEXTPARAMS structure
dtp = DLL["New"]("DRAWTEXTPARAMS");
// Assigns values to structure members
dtp["cbSize"] = 20; // Structure size
dtp["iTabLength"] = 2;
dtp["iLeftMargin"] = 2;
dtp["iRightMargin"] = 2;
dtp["uiLengthDrawn"] = 0;

Note that New has the second parameter, Count, that was not used in this example. Count specifies the number of instances to create. It allows you to create an array of elements of the new type. For instance, it allows you to create an array of structures. See Using Arrays in DLL Function Calls for details.

Specifying values of the string parameters. The second parameter of the DrawTextExA method specifies a string to be drawn on screen. Such parameters should be prepared in the following way --

JavaScript, JScript

LpStr = DLL.New("LPSTR", 256);

Python

LpStr = DLL.New("LPSTR", 256)

VBScript

Set LpStr = DLL.New("LPSTR", 256)

DelphiScript

LpStr := DLL.New('LPSTR', 256);

C++Script, C#Script

LpStr = DLL["New"]("LPSTR", 256);

This code creates an empty string that consists of 256 characters. LPSTR is a predefined type name. So, there is no need to define it with DefineType.

After you created an LPSTR value, you can specify the string text using the Text property:

JavaScript, JScript

LpStr = DLL.New("LPSTR", 256);
LpStr.Text = "My text";

Python

LpStr = DLL.New("LPSTR", 256)
LpStr.Text = "My text"

VBScript

Set LpStr = DLL.New("LPSTR", 256)
LpStr.Text = "My text"

DelphiScript

LpStr := DLL.New('LPSTR', 256);
LpStr.Text := 'My text';

C++Script, C#Script

LpStr = DLL["New"]("LPSTR", 256);
LpStr["Text"] = "My text";

For more information on passing strings through DLL functions’ parameters, see Using String Parameters in DLL Function Calls.

6. Calling Function

To call a function from a DLL, use the syntax library_name.routine_name:

JavaScript, JScript

// Call the routine using alias
Lib.DrawTextExA(dc, LpStr, LpStr.Text.length, r, 0, dtp);

Python

# Call the routine using alias
Lib.DrawTextExA(dc, LpStr, LpStr.Text.length, r, 0, dtp)

VBScript

' Call the routine using the routine name
Call Lib.DrawTextExA(dc, LpStr, Len(LpStr.Text), r, 0, dtp)

DelphiScript

// Call the routine using alias
Lib.DrawTextExA(dc, LpStr, Length(LpStr.Text), r, 0, dtp);

C++Script, C#Script

// Call the routine using alias
Lib["DrawTextExA"](dc, LpStr, LpStr["Text"]["length"], r, 0, dtp);

dc is a variable that specifies the device context for drawing. In order not to distract you from the main idea, we left out the explanation on how we got the device context. You can find this in the full script code of the example provided at the end of the topic.

One thing to note at the end: it may be more convenient to define an alias for a routine and then call the routine by this alias (the syntax is library_name.routine_alias). For instance, we may call the DrawTextExA function using the DrawTextEx alias. To create an alias, use the IDefineDLL.DefineAlias method, that is --

JavaScript, JScript

Def_DLL.DefineAlias("DrawTextEx", "DrawTextExA");

// Call the routine using alias
Lib.DrawTextEx(dc, LpStr, LpStr.Text.length, r, 0, dtp);

Python

Def_DLL.DefineAlias("DrawTextEx", "DrawTextExA")

# Call the routine using alias
Lib.DrawTextEx(dc, LpStr, LpStr.Text.length, r, 0, dtp)

VBScript

Call Def_DLL.DefineAlias("DrawTextEx", "DrawTextExA")

' Call the routine using alias
Call Lib.DrawTextEx(dc, LpStr, Len(LpStr.Text), r, 0, dtp)

DelphiScript

Def_DLL.DefineAlias('DrawTextEx', 'DrawTextExA');

// Call the routine using alias
Lib.DrawTextEx(dc, LpStr, Length(LpStr.Text), r, 0, dtp);

C++Script, C#Script

Def_DLL["DefineAlias"]("DrawTextEx", "DrawTextExA");

// Call the routine using alias
Lib["DrawTextEx"](dc, LpStr, LpStr["Text"]["length"], r, 0, dtp);

The point is that a DLL may contain several functions that have similar names and perform similar actions with some differences. However, programs call these functions from a DLL by a common name that differs from the original function names. The common function name is automatically replaced by the appropriate original function name when compiling the application. For example, User32.dll contains two functions, DrawTextExA and DrawTextExW. However, in program code you usually call these functions by the same name (alias), DrawTextEx, and depending on whether the application works with ANSI or Unicode strings, the appropriate function is called from the DLL. Thus, you can create an alias for a DLL function in your TestComplete test in order to call the routine from your script in the same way as you call it in other programs.

Example

Below you can find the full script code that calls the DrawTextExA function from the Windows User32.dll library as it was described in the above step-by-step instructions:

JavaScript, JScript

function CallRoutineFromDLL()
{
  var DTPATHELLIPSIS, s;
  var Def_DLL, Def_DrawTextParams, Def_Rect;
  var r, dtp, Lib, dc, i, LpStr;
 
  DTPATHELLIPSIS = 0x4000;
 
  // Text to draw
  s = "My string: C:\\Program Files\\Files.txt";
 
  
  // Defines the dll type
  Def_DLL = DLL.DefineDLL("USER32");
 
  // Registers the DRAWTEXTPARAMS type in TestComplete
  Def_DrawTextParams = DLL.DefineType("DRAWTEXTPARAMS",
                                                vt_i4, "cbSize",
                                                vt_i4, "iTabLength",
                                                vt_i4, "iLeftMargin",
                                                vt_i4, "iRightMargin",
                                                vt_i4, "uiLengthDrawn");
 
  // Registers the RECT type in TestComplete
  Def_Rect = DLL.DefineType("RECT",
                                vt_i4, "left",
                                vt_i4, "top",
                                vt_i4, "right",
                                vt_i4, "bottom");
 
  // Registers the function type in TestComplete
  Def_DLL.DefineProc("DrawTextExA",
                            vt_i4,
                            vt_lpstr,
                            vt_i4,
                            Def_Rect,
                            vt_i4,
                            Def_DrawTextParams,
                            vt_i4);
 
  // Creates an alias for DrawTextExA
  Def_DLL.DefineAlias("DrawTextEx", "DrawTextExA");
 
  // Registers the types of the GetDC
  // and ReleaseDC routines. They will
  // be used to work with the device context
  Def_DLL.DefineProc("GetDC", vt_i4, vt_i4);
  Def_DLL.DefineProc("ReleaseDC", vt_i4, vt_i4, vt_i4);
 
  // Loads the dll.
  // We use such a brief notation,
  // because USER32.DLL is a system library and
  // the dll type name (USER32) coincides with
  // the dll file name
  Lib = DLL.Load("USER32");
 
  // Creates the RECT structure and fills it with data
  r = DLL.New("RECT");
  r.left = 50;
  r.top = 50;
  r.right = 350;
  r.bottom = 100;
 
  // Creates the DRAWTEXTPARAMS structure and fills it with data
  dtp = DLL.New("DRAWTEXTPARAMS");
  dtp.cbSize = 20; // Structure size
  dtp.iTabLength = 2;
  dtp.iLeftMargin = 2;
  dtp.iRightMargin = 2;
  dtp.uiLengthDrawn = 0;
  
  // Creates the string parameter
  LpStr = DLL.New("LPSTR", 256);
  LpStr.Text = s;
 
  // Gets the device context for drawing
  dc = Lib.GetDC(0);
  // Calls the function from the DLL
  i = Lib.DrawTextEx(dc, LpStr, s.length, r, DTPATHELLIPSIS, dtp);
  // Releases the device context
  Lib.ReleaseDC(0, dc);
}

Python

def CallRoutineFromDLL():
 
  DTPATHELLIPSIS = 0x4000
 
  # Text to draw
  s = "My string: C:\\Program Files\\Files.txt"
 
  
  # Defines the dll type
  Def_DLL = DLL.DefineDLL("USER32")
 
  # Registers the DRAWTEXTPARAMS type in TestComplete
  Def_DrawTextParams = DLL.DefineType("DRAWTEXTPARAMS",
                                                VT_I4, "cbSize",
                                                VT_I4, "iTabLength",
                                                VT_I4, "iLeftMargin",
                                                VT_I4, "iRightMargin",
                                                VT_I4, "uiLengthDrawn")
 
  # Registers the RECT type in TestComplete
  Def_Rect = DLL.DefineType("RECT",
                                VT_I4, "left",
                                VT_I4, "top",
                                VT_I4, "right",
                                VT_I4, "bottom")
 
  # Registers the function type in TestComplete
  Def_DLL.DefineProc("DrawTextExA",
                            VT_I4,
                            VT_LPSTR,
                            VT_I4,
                            Def_Rect,
                            VT_I4,
                            Def_DrawTextParams,
                            VT_I4)
 
  # Creates an alias for DrawTextExA
  Def_DLL.DefineAlias("DrawTextEx", "DrawTextExA");
 
  # Registers the types of the GetDC
  # and ReleaseDC routines. They will
  # be used to work with the device context
  Def_DLL.DefineProc("GetDC", VT_I4, VT_I4)
  Def_DLL.DefineProc("ReleaseDC", VT_I4, VT_I4, VT_I4)
 
  #Loads the dll.
  # We use such a brief notation,
  # because USER32.DLL is a system library and
  # the dll type name (USER32) coincides with
  # the dll file name
  Lib = DLL.Load("USER32")
 
  # Creates the RECT structure and fills it with data
  r = DLL.New("RECT")
  r.left = 50
  r.top = 50
  r.right = 350
  r.bottom = 100
 
  # Creates the DRAWTEXTPARAMS structure and fills it with data
  dtp = DLL.New("DRAWTEXTPARAMS");
  dtp.cbSize = 20 # Structure size
  dtp.iTabLength = 2
  dtp.iLeftMargin = 2
  dtp.iRightMargin = 2
  dtp.uiLengthDrawn = 0
  
  # Creates the string parameter
  LpStr = DLL.New("LPSTR", 256)
  LpStr.Text = s
 
  # Gets the device context for drawing
  dc = Lib.GetDC(0)
  # Calls the function from the DLL
  i = Lib.DrawTextEx(dc, LpStr, len(s), r, DTPATHELLIPSIS, dtp)
  # Releases the device context
  Lib.ReleaseDC(0, dc)

VBScript

Sub CallRoutineFromDLL
 
  DTPATHELLIPSIS = &H4000
 
  ' Text to draw
  s = "My string: C:\Program Files\Files.txt"

  ' Defines the dll type
  Set Def_DLL = DLL.DefineDLL("USER32")
 
  ' Registers the DRAWTEXTPARAMS type in TestComplete
  Def_DrawTextParams = DLL.DefineType("DRAWTEXTPARAMS", _
                                                vt_i4, "cbSize", _
                                                vt_i4, "iTabLength", _
                                                vt_i4, "iLeftMargin", _
                                                vt_i4, "iRightMargin", _
                                                vt_i4, "uiLengthDrawn")
 
  ' Registers the RECT type in TestComplete
  Def_Rect = DLL.DefineType("RECT", _
                                    vt_i4, "left", _
                                    vt_i4, "top", _
                                    vt_i4, "right", _
                                    vt_i4, "bottom")
 
  ' Registers the function type in TestComplete
  Call Def_DLL.DefineProc("DrawTextExA", _
                        vt_i4, _
                        vt_lpstr, _
                        vt_i4, _
                        Def_Rect, _
                        vt_i4, _
                        Def_DrawTextParams, _
                        vt_i4)
 
  ' Creates an alias for DrawTextExA
  Call Def_DLL.DefineAlias("DrawTextEx", "DrawTextExA")
 
  ' Registers the types of the GetDC
  ' and ReleaseDC routines. They will
  ' be used to work with the device context
  Call Def_DLL.DefineProc("GetDC", vt_i4, vt_i4)
  Call Def_DLL.DefineProc("ReleaseDC", vt_i4, vt_i4, vt_i4)
 
  ' Loads the dll.
  ' We use such a brief notation,
  ' because USER32.DLL is a system library and
  ' the dll type name (USER32) coincides with
  ' the dll file name
  Set Lib = DLL.Load("USER32")
 
  ' Creates the RECT structure and fills it with data
  Set r = DLL.New("RECT")
  r.left = 50
  r.top = 50
  r.right = 350
  r.bottom = 100
 
  ' Creates the DRAWTEXTPARAMS structure and fills it with data
  Set dtp = DLL.New("DRAWTEXTPARAMS")
  dtp.cbSize = 20 ' Structure size
  dtp.iTabLength = 2
  dtp.iLeftMargin = 2
  dtp.iRightMargin = 2
  dtp.uiLengthDrawn = 0
 
  ' Creates the string parameter
  Set LpStr = DLL.New("LPSTR", 256)
  LpStr.Text = s
 
  ' Gets the device context for drawing
  dc = Lib.GetDC(0)
  ' Calls the function from the DLL
  i = Lib.DrawTextEx(dc, LpStr, Len(s), r, _
  DTPATHELLIPSIS, dtp)
  ' Releases the device context
  Call Lib.ReleaseDC(0, dc)
 
End Sub

DelphiScript

procedure CallRoutineFromDLL;
const
  DT_PATH_ELLIPSIS = $4000;
var
  s : OleVariant;
  Def_DrawTextParams, Def_Rect, Def_DLL, Lib : OleVariant;
  dtp, LpStr, r, dc, i : OleVariant;
begin
 
  // Text to draw
  s := 'My string: C:\Program Files\Files.txt';

  // Defines the dll type
  Def_DLL := DLL.DefineDLL('USER32');
 
  // Registers the DRAWTEXTPARAMS type in TestComplete
  Def_DrawTextParams := DLL.DefineType('DRAWTEXTPARAMS',
                                        vt_i4, 'cbSize',
                                        vt_i4, 'iTabLength',
                                        vt_i4, 'iLeftMargin',
                                        vt_i4, 'iRightMargin',
                                        vt_i4, 'uiLengthDrawn');
 
  // Registers the RECT type in TestComplete
  Def_Rect := DLL.DefineType('RECT',
                                 vt_i4, 'left',
                                 vt_i4, 'top',
                                 vt_i4, 'right',
                                 vt_i4, 'bottom');
 
  // Registers the function type in TestComplete
  Def_DLL.DefineProc('DrawTextExA', // function name
                    vt_i4, // device context
                    vt_lpstr, // pointer to the string to be drawn
                    vt_i4, // the string length
                    Def_Rect, // pointer to the RECT structure
                    vt_i4, // additional drawing settings
                    Def_DrawTextParams, // pointer to DRAWTEXTPARAMS
                    vt_i4); // result type
 
  // Creates an alias for DrawTextExA
  Def_DLL.DefineAlias('DrawTextEx', 'DrawTextExA');
  
  // Registers the types of the GetDC
  // and ReleaseDC routines. They will
  // be used to work with the device context
  Def_DLL.DefineProc('GetDC', vt_i4, vt_i4);
  Def_DLL.DefineProc('ReleaseDC', vt_i4, vt_i4, vt_i4);
 
  // Loads the dll
  // We use such a brief notation,
  // because USER32.DLL is a system library and
  // the dll type name (USER32) coincides with
  // the dll file name
  Lib := DLL.Load('USER32');
  
  // Creates the RECT structure and fills it with data
  r := DLL.New('RECT');
  r.left := 50;
  r.top := 50;
  r.right := 350;
  r.bottom := 100;
 
  // Creates the DRAWTEXTPARAMS structure and fills it with data
  dtp := DLL.New('DRAWTEXTPARAMS');
  dtp.cbSize := 20; // Structure size
  dtp.iTabLength := 2;
  dtp.iLeftMargin := 2;
  dtp.iRightMargin := 2;
  dtp.uiLengthDrawn := 0;
 
  // Creates the string parameter
  LpStr := DLL.New('LPSTR', 256);
  LpStr.Text := s;
 
  // Gets the device context for drawing
  dc := Lib.GetDC(0);
  // Calls the function from the DLL
  i := Lib.DrawTextEx(dc, LpStr, Length(s), r,
  DT_PATH_ELLIPSIS, dtp);
  // Releases the device context
  Lib.ReleaseDC(0, dc);
end;

C++Script, C#Script

function CallRoutineFromDLL()
{
  var DTPATHELLIPSIS, s;
  var Def_DLL, Def_DrawTextParams, Def_Rect;
  var r, dtp, Lib, dc, i, LpStr;
 
  DTPATHELLIPSIS = 0x4000;
 
  // Text to draw
  s = "My string: C:\\Program Files\\Files.txt";


  // Defines the dll type
  Def_DLL = DLL["DefineDLL"]("USER32");
 
  // Registers the DRAWTEXTPARAMS type in TestComplete
  Def_DrawTextParams = DLL["DefineType"]("DRAWTEXTPARAMS",
                                                     vt_i4, "cbSize",
                                                     vt_i4, "iTabLength",
                                                     vt_i4, "iLeftMargin",
                                                     vt_i4, "iRightMargin",
                                                     vt_i4, "uiLengthDrawn");
 
  // Registers the RECT type in TestComplete
  Def_Rect = DLL["DefineType"]("RECT",
                                    vt_i4, "left",
                                    vt_i4, "top",
                                    vt_i4, "right",
                                    vt_i4, "bottom");
 
  // Registers the function type in TestComplete
  Def_DLL["DefineProc"]("DrawTextExA",
                            vt_i4,
                            vt_lpstr,
                            vt_i4,
                            Def_Rect,
                            vt_i4,
                            Def_DrawTextParams,
                            vt_i4);
 
  // Creates an alias for DrawTextExA
  Def_DLL["DefineAlias"]("DrawTextEx", "DrawTextExA");
 
  // Registers the types of the GetDC
  // and ReleaseDC routines. They will
  // be used to work with the device context
  Def_DLL["DefineProc"]("GetDC", vt_i4, vt_i4);
  Def_DLL["DefineProc"]("ReleaseDC", vt_i4, vt_i4, vt_i4);
 
  // Loads the dll.
  // We use such a brief notation,
  // because USER32.DLL is a system library and
  // the dll type name (USER32) coincides with
  // the dll file name
  Lib = DLL["Load"]("USER32");
 
 // Creates the RECT structure and fills it with data
  r = DLL["New"]("RECT");
  r["left"] = 50;
  r["top"] = 50;
  r["right"] = 350;
  r["bottom"] = 100;
 
 // Creates the DRAWTEXTPARAMS structure and fills it with data
  dtp = DLL["New"]("DRAWTEXTPARAMS");
  dtp["cbSize"] = 20; // Structure size
  dtp["iTabLength"] = 2;
  dtp["iLeftMargin"] = 2;
  dtp["iRightMargin"] = 2;
  dtp["uiLengthDrawn"] = 0;
  
  // Creates the string parameter
  LpStr = DLL["New"]("LPSTR", 256);
  LpStr["Text"] = s;
 
  // Gets the device context for drawing
  dc = Lib["GetDC"](0);
 // Calls the function from the DLL
  i = Lib["DrawTextEx"](dc, LpStr, s["length"], r, DTPATHELLIPSIS, dtp);
 // Releases the device context
  Lib["ReleaseDC"](0, dc);
}

See Also

Calling DLL Functions From Tests
Calling DLL Functions From Tests - Overview
Calling DLL Functions From Tests - Known Limitations
Specifics of Using 32- and 64-bit DLLs
Using Custom Data Structures in DLL Function Calls
Using String Parameters in DLL Function Calls
Calling DLL Functions From Keyword Tests
Calling Functions From .NET Assemblies

Highlight search results