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 IDLLAccessProcess.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
IDLLAccessProcessObj.DefineType(TypeName, MemberType1, MemberName1, MemberType2, MemberName2, ..., MemberTypeN, MemberNameN)
IDLLAccessProcessObj | An expression, variable or parameter that specifies a reference to an IDLLAccessProcess object | |||
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.
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 correctly specified the member types. 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). |
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 IDLLAccessProcess.New
.
If the method registers a 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 as TestComplete does not align structure members on its own.
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 = DefEnv.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
DefEnv = DLL.DefineEnvironment()
# ...
DefType = DefEnv.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 = DefEnv.DefineType("MyStruct", _
vt_i4, "Value", _
vt_byref or vt_i4, "ValueByRef", _
vt_byref or myID, "MyStruct2")
DelphiScript
...
DefType := DefEnv.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 = DefEnv["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
Specifics of Using 32- and 64-bit DLLs
Calling DLL Functions From Tests - Tutorial
IDefineDLL Object
DefineTypeWithAlignment Method