Functions in custom dynamic link libraries use parameters of different data types. Often, they use arrays. TestComplete supports both arrays of ordinary types (for example, arrays of integers) and arrays of structures. This topic explains how you can create arrays and pass them as parameters to DLL functions.
Creating Arrays of Structures
Each element of such an array is a structure of some type. Before creating an array, we must register the needed structure type in TestComplete by calling the DLL.DefineType
method. Then we can create an array of elements of the registered structure type by calling the DLL.New
method:
JavaScript, JScript
var MyStructID = DLL.DefineType("MyStruct",
vt_i4, "First",
vt_i4, "Second",
vt_i4, "Third");
var A1 = DLL.New("MyStruct", 100);
Python
MyStructID = DLL.DefineType("MyStruct",
VT_I4, "First",
VT_I4, "Second",
VT_I4, "Third")
A1 = DLL.New("MyStruct", 100)
VBScript
MyStructID = DLL.DefineType("MyStruct", _
vt_i4, "First", _
vt_i4, "Second", _
vt_i4, "Third")
Set A1 = DLL.New("MyStruct", 100)
DelphiScript
MyStructID := DLL.DefineType('MyStruct',
vt_i4, 'First',
vt_i4, 'Second',
vt_i4, 'Third');
A1 := DLL.New('MyStruct', 100);
...
end;
C++Script, C#Script
var MyStructID = DLL["DefineType"]("MyStruct",
vt_i4, "First",
vt_i4, "Second",
vt_i4, "Third");
var A1 = DLL["New"]("MyStruct", 100);
Note that we should pass the name of the registered structure type through the first parameter of the DLL.New
method, not the integer ID of the type returned by DLL.DefineType
. The ID of the type is intended to define other structures that contain members of this type or to define DLL functions that take parameters or return values of this type (see descriptions of the DLL.DefineType
and IDefineDLL.DefineProc
methods). The second parameter of the DLL.New
method specifies the number of elements in the array. In our example, it is 100.
When defining custom structure types, creating arrays of such elements and passing them through the parameters of a DLL function, make sure that you specified all the data types correctly. Incorrect definition of data types passed to a DLL function may cause TestComplete to shut down (this typically happens because erroneous definitions cause invalid stack-parsing operations). |
After creating an array, we can fill it with data and pass it to the needed DLL function. To address an element in the created array, we can use the Item
property of the array and pass the needed element’s index to it. Furthermore, the Item
property name can be skipped and we can address elements of the created array in the same manner as elements of an ordinary array, by enclosing indexes in parentheses or brackets (depending on the used scripting language) right after the name of the array. Thus, we can access array elements and fill them with the needed values in one of the following equivalent ways:
JavaScript, JScript
A1.Item(2).First = 100;
A1.Item(2).Second = 200;
A1.Item(2).Third = 300;
// -- or --
A1(2).First = 100;
A1(2).Second = 200;
A1(2).Third = 300;
Python
A1.Item(2).First = 100
A1.Item(2).Second = 200
A1.Item(2).Third = 300
# -- or --
A1(2).First = 100
A1(2).Second = 200
A1(2).Third = 300
VBScript
A1.Item(2).First = 100
A1.Item(2).Second = 200
A1.Item(2).Third = 300
' -- or --
A1(2).First = 100
A1(2).Second = 200
A1(2).Third = 300
DelphiScript
A1.Item(2).First := 100;
A1.Item(2).Second := 200;
A1.Item(2).Third := 300;
// -- or --
A1[2].First := 100;
A1[2].Second := 200;
A1[2].Third := 300;
C++Script, C#Script
A1["Item"](2)["First"] = 100;
A1["Item"](2)["Second"] = 200;
A1["Item"](2)["Third"] = 300;
// -- or --
A1(2)["First"] = 100;
A1(2)["Second"] = 200;
A1(2)["Third"] = 300;
After creating the array and initializing its elements, we can pass the array to the needed DLL function like any other array. Below is a full-code example:
JavaScript, JScript
function TestArrayFunction()
{
var MyStructID, A1, Def_DLL, Lib;
MyStructID = DLL.DefineType("MyStruct",
vt_i4, "First",
vt_i4, "Second",
vt_i4, "Third");
A1 = DLL.New("MyStruct", 3);
A1.Item(0).First = 100;
A1.Item(0).Second = 200;
A1.Item(0).Third = 300;
A1.Item(1).First = 101;
A1.Item(1).Second = 201;
A1.Item(1).Third = 301;
A1.Item(2).First = 102;
A1.Item(2).Second = 202;
A1.Item(2).Third = 302;
Def_DLL = DLL.DefineDLL("MyDLL");
Def_DLL.DefineProc("MyArrayFunction", vt_byref | MyStructID, vt_void);
Lib = DLL.Load("C:\\MyDLL.dll");
Lib.MyArrayFunction(A1);
}
Python
def TestArrayFunction():
MyStructID = DLL.DefineType("MyStruct",
VT_I4, "First",
VT_I4, "Second",
VT_I4, "Third")
A1 = DLL.New("MyStruct", 3)
A1.Item(0).First = 100
A1.Item(0).Second = 200
A1.Item(0).Third = 300
A1.Item(1).First = 101
A1.Item(1).Second = 201
A1.Item(1).Third = 301
A1.Item(2).First = 102
A1.Item(2).Second = 202
A1.Item(2).Third = 302
Def_DLL = DLL.DefineDLL("MyDLL")
Def_DLL.DefineProc("MyArrayFunction", VT_BYREF | MyStructID, VT_VOID)
Lib = DLL.Load("C:\\MyDLL.dll")
Lib.MyArrayFunction(A1)
VBScript
Sub TestArrayFunction
Dim MyStructID, A1, Def_DLL, Lib
MyStructID = DLL.DefineType("MyStruct", _
vt_i4, "First", _
vt_i4, "Second", _
vt_i4, "Third")
Set A1 = DLL.New("MyStruct", 3)
A1.Item(0).First = 100
A1.Item(0).Second = 200
A1.Item(0).Third = 300
A1.Item(1).First = 101
A1.Item(1).Second = 201
A1.Item(1).Third = 301
A1.Item(2).First = 102
A1.Item(2).Second = 202
A1.Item(2).Third = 302
Set Def_DLL = DLL.DefineDLL("MyDLL")
Def_DLL.DefineProc "MyArrayFunction", vt_byref Or MyStructID, vt_void
Set Lib = DLL.Load("C:\MyDLL.dll")
Lib.MyArrayFunction A1
End Sub
DelphiScript
var
MyStructID, Def_DLL, Lib, A1;
begin
MyStructID := DLL.DefineType('MyStruct',
vt_i4, 'First',
vt_i4, 'Second',
vt_i4, 'Third');
A1 := DLL.New('MyStruct', 3);
A1.Item(0).First := 100;
A1.Item(0).Second := 200;
A1.Item(0).Third := 300;
A1.Item(1).First := 101;
A1.Item(1).Second := 201;
A1.Item(1).Third := 301;
A1.Item(2).First := 102;
A1.Item(2).Second := 202;
A1.Item(2).Third := 302;
Def_DLL := DLL.DefineDLL('MyDLL');
Def_DLL.DefineProc('MyArrayFunction', vt_byref or MyStructID, vt_void);
Lib := DLL.Load('C:\MyDLL.dll');
Lib.MyArrayFunction(A1);
end;
C++Script, C#Script
function TestArrayFunction()
{
var MyStructID, A1, Def_DLL, Lib;
MyStructID = DLL["DefineType"]("MyStruct",
vt_i4, "First",
vt_i4, "Second",
vt_i4, "Third");
A1 = DLL["New"]("MyStruct", 3);
A1["Item"](0)["First"] = 100;
A1["Item"](0)["Second"] = 200;
A1["Item"](0)["Third"] = 300;
A1["Item"](1)["First"] = 101;
A1["Item"](1)["Second"] = 201;
A1["Item"](1)["Third"] = 301;
A1["Item"](2)["First"] = 102;
A1["Item"](2)["Second"] = 202;
A1["Item"](2)["Third"] = 302;
Def_DLL = DLL["DefineDLL"]("MyDLL");
Def_DLL["DefineProc"]("MyArrayFunction", vt_byref | MyStructID, vt_void);
Lib = DLL["Load"]("C:\\MyDLL.dll");
Lib["MyArrayFunction"](A1);
}
Note: | The DLL.DefineType , DLL.New , DLL.DefineDLL and DLL.Load methods of the DLL object are used if you do not create an environment for loading DLLs and calling routines from them (see Specifics of Using 32- and 64-bit DLLs for more information about this). However, if you explicitly create and use an environment for DLLs (for instance, if you use both 32-bit and 64-bit DLLs in your script and create appropriate environments for them), you should call the corresponding methods of an IDLLAccessProcess object that represents an environment for DLLs with certain “bitness”.
For instance, if a 32-bit environment is used for 32-bit DLLs, the above-mentioned example will look like this: JavaScript, JScript function TestArrayFunction() Python
VBScript Sub TestArrayFunction DelphiScript var C++Script, C#Script function TestArrayFunction() |
When TestComplete creates an array, it organizes the structures in memory in a specific way. Namely, it positions them one after another. Using this feature you can easily create an array of elements of ordinary types. The next section in the topic explains how you can create such an array.
Creating Arrays of Ordinary Data Types
To create an array of elements of an ordinary data type (for instance, an array of integer values), we should define a helper structure that holds the only member of the same data type as the type of elements in the array to be created. Then we create an array of such helper structures. For instance, we may create an array of integers in the following manner:
JavaScript, JScript
var Def_TmpStruct = DLL.DefineType("TmpStruct", vt_i4, "Value");
var A2 = DLL.New("TmpStruct", 100);
Python
Def_TmpStruct = DLL.DefineType("TmpStruct", VT_I4, "Value")
A2 = DLL.New("TmpStruct", 100)
VBScript
Def_TmpStruct = DLL.DefineType("TmpStruct", vt_i4, "Value")
Set A2 = DLL.New("TmpStruct", 100)
DelphiScript
var
Def_TmpStruct, A2 : OleVariant;
begin
Def_TmpStruct := DLL.DefineType('TmpStruct', vt_i4, 'Value');
A2 := DLL.New('TmpStruct', 100);
end;
C++Script, C#Script
var Def_TmpStruct = DLL["DefineType"]("TmpStruct", vt_i4, "Value");
var A2 = DLL["New"]("TmpStruct", 100);
As the structures are located in memory one after another, we have got an array of integers. This is exactly what is needed.
When you need an array of 8-bit integers or unsigned 8-bit integers, you must define a 1-byte aligned structure. You can do this by using the DefineTypeWithAlignment method. |
Now, we can fill the array with data. To address a structure element in the created array, we can use the Item
property of the array and pass the needed element’s index to it or skip the Item
property name and address the needed element in the same manner as elements of an ordinary array, by enclosing indexes in parentheses or brackets (depending on the scripting language used) right after the name of the array.
Since ordinary type values are stored in the array as a member of the structure, we can access the needed value via the appropriate name of the structure’s field. Moreover, when working with the structure in the array we can skip the name of the structure’s first member. Thus, we can access array elements and fill them with the needed values in one of the following equivalent ways:
JavaScript
A2.Item(0).Value = 100;
A2.Item(1).Value = 200;
// -- or --
A2.$set("Item", 0, 100);
A2.$set("Item", 1, 200);
// -- or --
A2(0) = 100;
A2(1) = 200;
JScript
A2.Item(0).Value = 100;
A2.Item(1).Value = 200;
// -- or --
A2.Item(0) = 100;
A2.Item(1) = 200;
// -- or --
A2(0) = 100;
A2(1) = 200;
Python
A2.Item(0).Value = 100
A2.Item(1).Value = 200
# -- or --
A2.Item(0) = 100
A2.Item(1) = 200
# -- or --
A2(0) = 100
A2(1) = 200
VBScript
A2.Item(0).Value = 100
A2.Item(1).Value = 200
' -- or --
A2.Item(0) = 100
A2.Item(1) = 200
' -- or --
A2(0) = 100
A2(1) = 200
DelphiScript
A2.Item(0).Value := 100;
A2.Item(1).Value := 200;
// -- or --
A2.Item(0) := 100;
A2.Item(1) := 200;
// -- or --
A2[0] := 100;
A2[1] := 200;
C++Script, C#Script
A2["Item"](0)["Value"] = 100;
A2["Item"](1)["Value"] = 200;
// -- or --
A2["Item"](0) = 100;
A2["Item"](1) = 200;
// -- or --
A2(0) = 100;
A2(1) = 200;
After that, the array can be passed to the needed DLL function as any other array. Below a full-code example:
JavaScript, JScript
function TestArrayFunction()
{
var DefArr, Arr, Def_DLL, Lib;
DefArr = DLL.DefineType("tmpArrayType", vt_ui4, "Value");
Arr = DLL.New("tmpArrayType", 4);
Arr.Item(0).Value = 100;
Arr.Item(1).Value = 200;
Arr.Item(2).Value = 300;
Arr.Item(3).Value = 400;
Def_DLL = DLL.DefineDLL("MyDLL");
Def_DLL.DefineProc("MyArrayFunction", vt_byref | DefArr, vt_void);
Lib = DLL.Load("C:\\MyDLL.dll");
Lib.MyArrayFunction(Arr);
}
Python
def TestArrayFunction():
DefArr = DLL.DefineType("tmpArrayType", vt_ui4, "Value")
Arr = DLL.New("tmpArrayType", 4)
Arr.Item(0).Value = 100
Arr.Item(1).Value = 200
Arr.Item(2).Value = 300
Arr.Item(3).Value = 400
Def_DLL = DLL.DefineDLL("MyDLL")
Def_DLL.DefineProc("MyArrayFunction", VT_BYREF | DefArr, VT_VOID)
Lib = DLL.Load("C:\\MyDLL.dll")
Lib.MyArrayFunction(Arr)
VBScript
Sub TestArrayFunction
Dim DefArr, Arr, Def_DLL, Lib
DefArr = DLL.DefineType("tmpArrayType", vt_ui4, "Value")
Set Arr = DLL.New("tmpArrayType", 4)
Arr.Item(0).Value = 100
Arr.Item(1).Value = 200
Arr.Item(2).Value = 300
Arr.Item(3).Value = 400
Set Def_DLL = DLL.DefineDLL("MyDLL")
Def_DLL.DefineProc "MyArrayFunction", vt_byref Or DefArr, vt_void
Set Lib = DLL.Load("C:\MyDLL.dll")
Lib.MyArrayFunction Arr
End Sub
DelphiScript
var
DefType, Def_DLL, Lib, Arr;
begin
DefType := DLL.DefineType('tmpArrayType', vt_ui2, 'Value');
Arr := DLL.New('tmpArrayType', 4);
Arr[0].Value := 100;
Arr[1].Value := 200;
Arr[2].Value := 300;
Arr[3].Value := 400;
Def_DLL := DLL.DefineDLL('MyDLL');
Def_DLL.DefineProc('MyArrayFunction', vt_byref or DefType, vt_void);
Lib := DLL.Load('C:\MyDLL.dll');
Lib.MyArrayFunction(Arr);
end;
C++Script, C#Script
function TestArrayFunction()
{
var DefArr, Arr, Def_DLL, Lib;
DefArr = DLL["DefineType"]("tmpArrayType", vt_ui4, "Value");
Arr = DLL["New"]("tmpArrayType", 4);
Arr["Item"](0)["Value"] = 100;
Arr["Item"](1)["Value"] = 200;
Arr["Item"](2)["Value"] = 300;
Arr["Item"](3)["Value"] = 400;
Def_DLL = DLL["DefineDLL"]("MyDLL");
Def_DLL["DefineProc"]("MyArrayFunction", vt_byref | DefArr, vt_void);
Lib = DLL["Load"]("C:\\MyDLL.dll");
Lib["MyArrayFunction"](Arr);
}
Note: | Use the DLL.DefineType , DLL.New , DLL.DefineDLL and DLL.Load methods of the DLL object if you do not create an environment for loading DLLs and calling routines from them (see Specifics of Using 32- and 64-bit DLLs for more information on this). However, if you explicitly create and use an environment for DLLs (for instance, if you use both 32-bit and 64-bit DLLs in your script and create appropriate environments for them), you should call the corresponding methods from an IDLLAccessProcess object that represents an environment for DLLs with certain “bitness”.
For instance, if a 32-bit environment is used for 32-bit DLLs, the above-mentioned example will look like this: JavaScript, JScript function TestArrayFunction() Python
VBScript Sub TestArrayFunction DelphiScript var C++Script, C#Script function TestArrayFunction() |
Creation of arrays that contain pointers to structures is similar to creation of arrays of ordinary data types. You just need to define a helper structure that contains only one member and this member should refer to the desired structure, that is --
JavaScript, JScript
var Def_TmpStruct2 = DLL.DefineType("TmpStruct2", vt_byref | MyStructID, "Value");
var A3 = DLL.New("TmpStruct2", 100);
Python
Def_TmpStruct2 = DLL.DefineType("TmpStruct2", VT_BYREF | MyStructID, "Value")
A3 = DLL.New("TmpStruct2", 100)
VBScript
Def_TmpStruct2 = DLL.DefineType("TmpStruct2", vt_byref Or MyStructID, "Value")
Set A3 = DLL.New("TmpStruct2", 100)
DelphiScript
var
Def_TmpStruct2, A3 : OleVariant;
begin
...
Def_TmpStruct2 := DLL.DefineType('TmpStruct2', vt_byref or MyStructID, 'Value');
A3 := DLL.New('TmpStruct2', 100);
end;
C++Script, C#Script
var Def_TmpStruct2 = DLL["DefineType"]("TmpStruct2", vt_byref | MyStructID, "Value");
var A3 = DLL["New"]("TmpStruct2", 100);
See Also
Calling DLL Functions From Tests
Calling DLL Functions From Tests - Overview
Calling DLL Functions From Tests - Tutorial