Declares functions in a DLL so that they can be called from a 4Test script.
dll dllname.dll prototype [prototype]...
|dllname||The name of the DLL file that contains the functions you want to call.|
|prototype||The function prototype of a DLL function you want to call. Each prototype has the syntax shown below.|
[return-type] func-name ( [arg-list]) [alias dll-fname]
|return-type||Optional: The data type of the return value, if there is one.|
|func-name||An identifier that specifies the name of the function.|
|dll-fname||Optional: A string that specifies the name of the function within the DLL. If specified, func-name is the alias name to be used in 4Test. See the example below.|
|arg-list||Optional: A comma-delimited list of arguments. Each argument in arg-list has the syntax shown below.|
[pass-mode] data-type arg-name
|pass-mode||Optional: Whether the argument is passed into the function, passed out of the function, or both. pass-mode can be in, out, or inout. The default is in. See Function Declaration for a description of pass modes.|
|data-type||The C data type of the argument. See the information on C data types below.|
|arg-name||An identifier specifying the name of the argument.|
If a DLL function has the same name as a 4Test reserved word, or the function does not have a name but an ordinal number, rename the function within your 4Test declaration and use the alias keyword to map the declared name to the actual name. The second example below defines an alias name for the DLL function exit.
Since DLL functions are written in C, the arguments you pass to these functions must have C data types or be records containing fields of these types. For a list of these data types, see C data types for DLL functions.
When a DLL function uses a string as the return type, Silk Test Classic does not assume ownership of that string. The reason for this is that buffers must be de-allocated in the same C-Runtime as they were allocated. Otherwise, the application might crash. Therefore, Silk Test Classic looks for a function called FreeDllMemory which accepts a pointer in the DLL's interface. If available, Silk Test Classic calls that function with the buffer as argument, and gives the DLL a chance to clean up its memory. Otherwise, Silk Test Classic leaves the buffer as it is (leaking memory) because it has no way of freeing the memory without risking a crash.
If the user calls a DLL function with an output string buffer that is less then the minimum size of 256 characters, the original string buffer is resized to 256 characters and a warning is printed. This warning, "String buffer size was increased from x to 256 characters" (where x is the length of the given string plus one) alerts the user to a potential problem where the buffer used might be shorter than necessary.
The table below provides additional information about passing certain types of arguments to DLL functions:
|Variable Type||How to Pass|
|Pointer to a character||Pass a 4Test string variable to a DLL which requires a pointer to a character (null terminated).|
|Pointer to a numerical array||Pass a 4Test array or list of the appropriate type to a DLL which requires a pointer to a numerical array.|
|Pointer to a record||Pass a 4Test record to a DLL which requires a pointer to a record. If the record has a dwSize field, then you must set it to the size of the record. 4Test records are always passed by reference to a DLL.|
|Pointer to a function||You cannot pass a pointer to a function to a DLL function.|
|Null string pointer||To pass a null pointer to a string, use the null keyword in 4Test.|
|Window handle||Use the hWnd property or the GetHandle method of the AnyWin class to get the window handle you need.|
A few special rules apply for declaring arguments that can be passed by reference by the DLL function:
Declare an argument whose value will be passed by reference by a DLL function using the out keyword.
Declare an argument that is sometimes passed by reference and sometimes not using the in keyword. In the call to the DLL function, preface the argument with the out keyword, enclosed in brackets.
Typically, when you make a DLL function call, the DLL gets loaded into the Agent and called from there. However, if you specify that a function is "inprocess", it uses the first argument (which has to be a window handle - not the window id) and loads the DLL into that application's process. If the DLL's function's first argument is not a window handle, you must write a wrapper so that it is. For example, your DLL declaration might say: inprocess SendMessage(HWND ......
and then when you call SendMessage, it is loaded into the application that contains the window handle you provided.
If there is a return type, the return type comes after the inprocess keyword.
You can have DLL functions that are both inprocess and not inprocess by using aliases.
The ansicall keyword converts all string parameters (return type, string arguments, strings in record structures that are used as arguments) from W (wide-character, Unicode) to A (ANSI) character format before calling the DLL function internally. Return values and pass-mode variables set to inout that are strings or contain strings within record structures get converted back from A (ANSI) format to W (wide-character) format after calling the DLL. Using the ansicall keyword makes an ANSI call transparent, as the conversion is done internally.
You can use the inprocess and ansicall keywords together in the same DLL call:
inprocess ansicall INT MessageBoxIPA (HWND hWndParent, LPCSTR sText, LPCSTR sTitle, UINT fuFlags) alias "MessageBoxA"