Using String Parameters in DLL Function Calls

Applies to TestComplete 14.20, last modified on September 11, 2019

Functions declared in dynamic link libraries may use parameters of different data types, including parameters of string types like char*, LPSTR, LPWSTR, AnsiString, PChar, etc. Passing string values through a DLL function’s parameters from TestComplete tests has some specifics. This topic explains how you can properly create string variables and use them in parameters of a DLL function to be called from your test.

The main specifics of using string parameters when calling DLL functions from TestComplete tests is that you must create helper objects representing string values and pass them to DLL functions instead of using native string variables declared somewhere in script code. To create such a helper object, you should call the DLL.New method in your test. The method allows creating a new variable of a certain data type (mainly, a custom structure) defined by the DLL.DefineType method or an array of such variables (see Using Custom Data Structures in DLL Function Calls and Using Arrays in DLL Function Calls). However, TestComplete provides two special data types, LPSTR and LPWSTR, that are used to create helper objects for string values to be passed through parameters of DLL functions. These data types are predefined in TestComplete, thus, there is no need to define them with the DLL.DefineType method. You just need to call the DLL.New method and specify the predefined LPSTR constant (or LPWSTR for Unicode strings) as the data type of the variable to be created.

In case of creating a string variable with DLL.New, the second parameter of the method (the Count parameter) is used to specify the maximum number of characters that can be contained in the string to be created.

To initialize the created string variable, you can set the needed string value to the Text property of a helper object returned by DLL.New.

The following example demonstrates how you can create a string variable that can contain up to 128 characters and initialize it with the needed string value:

JavaScript, JScript

var MyStr = DLL.New("LPSTR", 128);
MyStr.Text = "The quick brown fox jumps over the lazy dog.";

Python

MyStr = DLL.New("LPSTR", 128)
MyStr.Text = "The quick brown fox jumps over the lazy dog."

VBScript

Set MyStr = DLL.New("LPSTR", 128)
MyStr.Text = "The quick brown fox jumps over the lazy dog."

DelphiScript

MyStr := DLL.New('LPSTR', 128);
MyStr.Text := 'The quick brown fox jumps over the lazy dog.';

C++Script, C#Script

var MyStr = DLL["New"]("LPSTR", 128);
MyStr.Text = "The quick brown fox jumps over the lazy dog.";

Note: The DLL.New method is used if you are going to work with 32-bit DLLs or with 64-bit DLLs only and do not create an environment for loading DLLs of certain “bitness” and calling routines from them (see Specifics of Using 32- and 64-bit DLLs). However, if you explicitly create and use such an environment for DLLs, you need to call the IDLLAccessProcess.New method of an IDLLAccessProcess object that represents an environment for DLLs.

For instance, if you create a 32-bit environment for 32-bit DLLs, you should create string variables in the following way:

JavaScript, JScript

var MyEnvironment = DLL.DefineEnvironment(true);
var MyStr = MyEnvironment.New("LPSTR", 128);

Python

MyEnvironment = DLL.DefineEnvironment(True)
MyStr = MyEnvironment.New("LPSTR", 128)

VBScript

Set MyEnvironment = DLL.DefineEnvironment(True)
Set MyStr = MyEnvironment.New("LPSTR", 128)

DelphiScript

MyEnvironment := DLL.DefineEnvironment(True);
MyStr := MyEnvironment.New('LPSTR', 128);

C++Script, C#Script

var MyEnvironment = DLL.DefineEnvironment(true);
var MyStr = MyEnvironment["New"]("LPSTR", 128);

After you created and initialized an LPSTR or LPWSTR variable, you can pass it like a variable of any other type to the needed function declared in an external DLL. Note that you must first define the needed function in your test by calling the IDefineDLL.DefineProc method if your DLL was compiled without debug information (see the description of the method for more information about this).

Do not pass native strings through a DLL function’s parameters. You should always create an appropriate variable of the LPSTR or LPWSTR type. The following example demonstrates correct and wrong usage of strings when calling a DLL function:

JavaScript, JScript

// A native string variable
var s = "The quick brown fox jumps over the lazy dog.";

// An LPSTR variable
var MyStr = DLL.New("LPSTR", 64);
MyStr.Text = s;

// Call a DLL routine
MyLib.MyDLLFunction(MyStr); // Correct
MyLib.MyDLLFunction(s); // Incorrect

Python

# A native string variable
s = "The quick brown fox jumps over the lazy dog."

# An LPSTR variable
MyStr = DLL.New("LPSTR", 64)
MyStr.Text = s

# Call a DLL routine
MyLib.MyDLLFunction(MyStr) # Correct
MyLib.MyDLLFunction(s) # Incorrect

VBScript

' A native string variable
s = "The quick brown fox jumps over the lazy dog."

' An LPSTR variable
Set MyStr = DLL.New("LPSTR", 64)
MyStr.Text = s

' Call a DLL routine
Call MyLib.MyDLLFunction(MyStr) ' Correct
Call MyLib.MyDLLFunction(s) ' Incorrect

DelphiScript

var
  s, MyStr: OleVariant;
begin
  // A native string variable
  s := 'The quick brown fox jumps over the lazy dog.';

  // An LPSTR variable
  MyStr := DLL.New('LPSTR', 64);
  MyStr.Text := s;

  // Call a DLL routine
  MyLib.MyDLLFunction(MyStr); // Correct
  MyLib.MyDLLFunction(s); // Incorrect
end;

C++Script, C#Script

// A native string variable
var s = "The quick brown fox jumps over the lazy dog.";

// An LPSTR variable
var MyStr = DLL["New"]("LPSTR", 64);
MyStr.Text = s;

// Call a DLL routine
MyLib["MyDLLFunction"](MyStr); // Correct
MyLib["MyDLLFunction"](s); // Incorrect

Like variables of any other data types, string variables can be passed through in, out or in-out parameters of a DLL function. In case of out (in-out) string parameters, the caller of the function determines the end of the returned string by itself (for instance, it waits for the termination null symbol that indicates the end of the string). Since the called DLL function may return a corrupted string with the incorrectly specified length or end through an out parameter, TestComplete may receive a huge memory block until it finds the end of such a corrupted string. For such cases, TestComplete uses a special property, IDLLAccessProcessOptions.StringParameterMaxLength, that specifies the maximum length of a string that can be received by TestComplete from a DLL function via an out parameter (the default value of the property is 1024). If the length of the returned string exceeds the StringParameterMaxLength value, TestComplete considers only the first StringParameterMaxLength characters as the returned string and does not receive the rest of the characters. This allows TestComplete to avoid receiving huge memory blocks with useless data in case of corrupted out strings.

Variables of the LPSTR type can only be passed from TestComplete tests through parameters of DLL functions. They cannot be used for function results. So, if a function returns a string value (for instance, a char* value in Visual C++ or an AnsiString value in Delphi), you will not be able to obtain the function’s result in your test.

Note for Delphi users: the string type is not supported (either as function parameters or as result values).

See Also

Calling DLL Functions From Tests - Tutorial
Calling DLL Functions From Tests
Using Custom Data Structures in DLL Function Calls

Highlight search results