Description
When calling routines from a dynamic link library, you may need to use data types incompatible with OLE. For instance, you may need to call a function that takes a pointer to a structure as a parameter. The DLL.DefineType
method "registers" a new data type (normally, a structure) in TestComplete and returns the ID of the new data type. Later, you can use this ID to specify the type of function parameters or structure members.
Declaration
DLL.DefineType(TypeName, MemberType1, MemberName1, MemberType2, MemberName2, ..., MemberTypeN, MemberNameN)
TypeName | [in] | Required | String | |
MemberType1 | [in] | Required | Integer | |
MemberName1 | [in] | Required | String | |
MemberType2 | [in] | Optional | Integer | |
MemberName2 | [in] | Optional | String | ... |
MemberTypeN | [in] | Optional | Integer | |
MemberNameN | [in] | Optional | String | |
Result | Integer |
Applies To
The method is applied to the following object:
Parameters
The method uses a variable number of parameters.
All parameters of the DefineType
method, except for the TypeName parameter, specify the types and names of structure members. These parameters can be divided into pairs: MemberType-MemberName. Only the first pair is required, other pairs are optional.
TypeName
A required parameter that designates the name of the data type to be defined. TypeName can include any characters. For instance, if you define a structure, this parameter holds the structure name. Later, this name is used to create the structure and fill it with data.
MemberType
An integer that specifies the member’s data type. It can be one of predefined constants or an ID created by the previous call to DefineType
.
If a member is passed by a reference, you must use the vt_byref constant when you declare its type (see the example below). |
Note that currently it is impossible to call DLL routines that use structures containing array-type members (for instance, string or array fields):
Delphi
// A definition of structure in the DLL source
type
TMyStruct1 = record
FInteger:Integer;
CharArray: array[0..9] of Char; // The array is used
end;
...
// This routine will not operate properly when it is called from TestComplete
procedure AcceptStructure(const AValue: TMyStruct1); stdcall;
When you try to do this, you will not get an error, but the array-type field will be undefined even if you assign a value to it.
You can workaround this limitation by using pointer-type members:
Delphi
// A definition of structure in the DLL source
type
TMyStruct2 = record
FInteger:Integer;
CharArrPtr: PChar; // The pointer is used
end;
...
// This routine will function correctly in TestComplete
procedure AcceptStructure(const AValue: TMyStruct2); stdcall;
Make sure that you specified the member types correctly. Incorrect definition of data types may cause TestComplete to shut down when passing such structures to DLL functions from tests (this happens because erroneous definitions may cause incorrect stack processing). |
MemberName
The name of the structure member. This name is used to access the structure member from scripts. That is why it must comply with the naming rules of the used scripting language. Besides that, members must have unique names in the structure.
Result Value
The integer value that denotes the identifier of the created data type.
Remarks
DefineType
registers a new data type, but it does not create variables of this type. To create variables, call DLL.New
.
If the method registers the data type that was registered earlier in the current test or in a previous test (if the ClearSettingsBeforeEach
run option is enabled), it posts a warning message to the test log.
Compilers can align structure members at certain addresses multiplied by 1, 2, 4 or more bytes. For instance, often an application uses the double word alignment (4 byte). The alignment may enlarge the actual size of structure members that take less memory than the alignment value. You should keep that in mind when using this method, as TestComplete does not align structure members.
By default, the compilers use alignment for structures that are defined by default, that is, without the use of the #pragma pack(...)
statement in C++ code or packed record
in Delphi. When creating a data type for these structures in scripts, pay attention to the size of structure members.
To control alignment, use the DefineTypeWithAlignment method.
Example
The following example illustrates defining structures in TestComplete:
JavaScript, JScript
DefType = DLL.DefineType("MyStruct", // name of the new structure
vt_i4, "Value", // integer
vt_byref | vt_i4, "ValueByRef", // pointer to integer
vt_byref | myID, "MyStruct2"); // pointer to structure MyStruct2
Python
DefType = DLL.DefineType("MyStruct", # name of the new structure
vt_i4, "Value", # integer
vt_byref | vt_i4, "ValueByRef", # pointer to integer
vt_byref | myID, "MyStruct2") # pointer to structure MyStruct2
VBScript
' The 1st parameter is the structure name
' The 2nd parameter is an integer value
' The 3rd parameter is a pointer to an integer value
' The 4th parameter is a pointer to structure
DefType = DLL.DefineType("MyStruct", _
vt_i4, "Value", _
vt_byref or vt_i4, "ValueByRef", _
vt_byref or myID, "MyStruct2")
DelphiScript
DefType := DLL.DefineType('MyStruct', // name of the new structure
vt_i4, 'Value', // integer
vt_byref or vt_i4, 'ValueByRef', // pointer to integer
vt_byref or myID, 'MyStruct2'); // pointer to structure MyStruct2
C++Script, C#Script
DefType = DLL["DefineType"]("MyStruct", // name of the new structure
vt_i4, "Value", // integer
vt_byref | vt_i4, "ValueByRef", // pointer to integer
vt_byref | myID, "MyStruct2"); // pointer to structure MyStruct2
See Also
Calling DLL Functions From Tests - Tutorial
IDefineDLL Object
DLL.DefineTypeWithAlignment Method