本来有些犹豫,要不要写dll调用方法的,因为两个原因,一则已经见到有类似的文章,二则新版本的TestComplete改变了调用方法,我的这个法子是版本7.52的。后来看完了网上的文章,觉得还是写一写,因为网上的文章都基本上是描述的TestComplete的帮助文档的例子,虽然很详细,但是缺点是平常人可能用不到那么复杂的结构,越简单的往往越有生命力。所以这篇文章是从dll编写开始入手写的,重点就只讲了数值和字符串两种类型的调用方法,只要你够倔,日常工作中足够对付了。
好吧,那我们就开工吧。
先上传一个delphi编写的程序,是用来生成dll的:
http://download.csdn.net/source/3515429
包含了一个delphi程序和编译出来的ProjectDLL.dll,还有程序calldll.txt
文件的内容也非常简单,即便您没做过delphi,也能看个八九不离十,dll随便哪种语言都行,即便VB都可以有法子做的出标准dll,这部分大家看看就好了:
library ProjectDLL;
{ ... }
uses
SysUtils, Classes;
{$R *.res}
{----编写---}
function INC(X,Y double) double;stdcall;
begin
Result:= X+Y;
end;
function TestStr(pin,pout:pchar):Integer;stdcall;
const
Title = ' +Title';
var
str1:string;
begin
str1:=strpas(pin);
str1:='modify '+str1+Title;
strcat(pout,pchar(str1));
result:=1;
end;
exports INC,TestStr;
{----编写---}
begin
end.
编译后生成了ProjectDLL.dll,创建一个TestComplete的项目,然后建立一个dll目录,把这个文件拷贝进去。
先看看如何调用double的函数,两个大的步骤:定义和调用
定义部分
dim x,y,z
dim Def_DLL,Def_Proc,Lib
Set Def_DLL = DLL.DefineDLL("ProjectDLL")
Def_Proc=Def_DLL.DefineProc("INC",vt_r8,vt_r8,vt_r8)
调用部分:
Set Lib = DLL.Load(ProjectSuite.Path & "dll\ProjectDLL.dll", "ProjectDLL")
x=1.0
y=2.0
z=Lib.INC(x,y)
再看看string的函数,步骤一样的:
定义部分:
dim Lppin
dim Lppout
dim Def_DLL,Def_Proc,Lib
Set Def_DLL = DLL.DefineDLL("ProjectDLL")
Def_Proc=Def_DLL.DefineProc("TestStr",vt_lpstr,vt_lpstr,vt_i4 )
调用部分:
Set Lib = DLL.Load(ProjectSuite.Path & "dll\ProjectDLL.dll", "ProjectDLL")
Set Lppin = DLL.New("LPSTR", 1024)
Lppin.Text = "pin"
Set Lppout = DLL.New("LPSTR", 1024)
call Lib.TestStr(Lppin,Lppout)
Log.Message("Lppout:" & Lppout.Text)
需要注意的有两点:
1. 数据类型,这个很麻烦,需要您仔细看看帮助
在帮助的章节:Parameter Types for C++ Routines and Structures
详细说明了参数类型
还加上了一句恐怖的注释:
Make sure you specified the parameter types correctly. Incorrect definition of parameter types may crash TestComplete (this happens because erroneous definitions cause incorrect stack processing).
确信你的参数声名了正确的数据类型,否则可能你的TestComplete会挂掉。
Type Constant
bool vt_b1
BSTR vt_bstr (see also Calling Functions That Return String Values or Interface References)
BSTR * vt_byref | vt_bstr
Byte vt_ui1
Byte * vt_byref | vt_ui1
char vt_i1
char * vt_lpstr or vt_byref | vt_i1 This type is supported for function parameters only. The char * result type is not supported.
CY vt_cy
CY * vt_byref | vt_cy
DATE vt_date
DATE * vt_byref | vt_date
DECIMAL * vt_bstr | vt_decimal
double vt_r8
double * vt_byref | vt_r8
float vt_r4
float * vt_byref | vt_r4
IDispatch * vt_dispatch
IDispatch ** vt_byref | vt_dispatch
int vt_int
int * vt_byref | vt_int
long vt_i4
long * vt_byref | vt_i4
SCODE vt_error
short vt_i2
short * vt_byref | vt_i2
unsigned int vt_uint
unsigned int * vt_byref | vt_uint
unsigned long vt_ui4
unsigned long * vt_byref | vt_ui4
unsigned short vt_ui2
unsigned short * vt_byref | vt_ui2
VARIANT vt_variant
VARIANT * vt_byref | vt_variant
VARIANT_BOOL vt_bool
VARIANT_BOOL * vt_byref | vt_bool
void * vt_byref | vt_void
wchar_t vt_ui2
wchat_t * vt_byref | vt_ui2 or vt_lpwstr This type is supported for function parameters only. The wchar_t * result type is not supported.
看了看,哎哟,我的double应该声名为vt_r8,还好还好,我的TestComplete没挂掉,还执行正确了,这个要看人品的,开玩笑的,其实是要看类型的宽度。我的建议是怎么简单怎么用。另外这个是C++的类型哈,别以为就是你编写语言的。有个类型转换的问题。没事,蒙吧,没挂掉就行了。
2. 注意什么时候必须使用函数,而不是过程
'vt_lpstr:This type is only supproted for function parameters. The PChar result values are not supported
vt_lpstr:这个数据类型只能做为函数参数,而且函数的返回值不可以是PChar类型的。知道为啥我的函数定义是:
function TestStr(pin,pout:pchar):Integer;stdcall;
为啥要使用pin传入,pout传出,而不是用函数值直接传出了吧,没法子,TestComplete不支持那种方式。
不可以写成:
function TestStr(pin,pout:pchar): pchar;stdcall;
或者
Procedure TestStr(pin,pout:pchar);stdcall;
好了,大功告成了,大家就依葫芦画瓢吧,能抄是福呀。