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
Python
Def_DLL = DLL.DefineDLL("USER32")
VBScript
DelphiScript
C++Script, C#Script
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, seeIDefineDLL.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. SinceDrawTextExA
returns an integer value, we have specifiedvt_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
orvt_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 byDLL.DefineType
. Despite the fact that theRECT
andDRAWTEXTPARAMS
structures are passed by reference, we did not use thevt_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