51Testing软件测试论坛

标题: LoadRunner下DLL的调用 [打印本页]

作者: cwj007    时间: 2005-7-27 20:18
标题: LoadRunner下DLL的调用
LoadRunner下DLL的调用

http://blog.csdn.net/cwj007/archive/2005/07/27/436466.aspx                                                                ——落叶夏日cwj.007
场景介绍       
        最近在做类似于QQ的通信工具的性能测试时发现了一些问题,现总结出来与大家分享一下。希望大家在使用LoadRunner时不仅仅停在只是录制/播放角本,而全面提升角本的编程技术,解决复杂场景。
        本次测试中碰到的问题是这样的,在消息的传送过程中遇到了DEC加密的过程,LoadRunner录制到的全是加密的消息,比如我录制了某一个用户的登陆,发送消息,退出,但由于是加密的,只能单个用户使用,但如果我想并发多少个用户就存在很多问题,最直接的一个问题就是用户名是加密的,密码是加密的,当然你可以说让程序那里注掉加密的代码进行明码的测试,当然也是一种办法。但程序组提出了要使用更真实的方法来模拟,这时就必需使用下面介绍的方法。
        一开始是直接把API移植到LoadRunner中来,不过由于加密算法异常复杂,有几层循环,而角本是解释执行的,进行一次加密运算可能需要好几分钟,当然在角本里可以把角本本身运行的时间去掉,但这样做显然没有直接调用DLL来的效率高。由于程序组比较忙,所以无法提供DLL给测试,所以测试完成了DLL的编写,并在LoadRunner中调用成功,高效的完成了用户信息加密,参数关联,成功的完成了测试。
动态链接库的编写
  在Visual C++6.0开发环境下,打开FileNewProject选项,可以选择Win32 Dynamic-Link Library建立一个空的DLL工程。
  1. Win32 Dynamic-Link Library方式创建Non-MFC DLL动态链接库

  每一个DLL必须有一个入口点,这就象我们用C编写的应用程序一样,必须有一个WINMAIN函数一样。在Non-MFC DLL中DllMain是一个缺省的入口函数,你不需要编写自己的DLL入口函数,用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。如果应用程序的DLL需要分配额外的内存或资源时,或者说需要对每个进程或线程初始化和清除操作时,需要在相应的DLL工程的.CPP文件中对DllMain()函数按照下面的格式书写。
 
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
    break;
case DLL_THREAD_ATTACH:
    break;
case DLL_THREAD_DETACH:
    break;
case DLL_PROCESS_DETACH:
    break;
default:
    break;
}
return TRUE;
}
  
        参数中,hMoudle是动态库被调用时所传递来的一个指向自己的句柄(实际上,它是指向_DGROUP段的一个选择符);ul_reason_for_call是一个说明动态库被调原因的标志,当进程或线程装入或卸载动态链接库的时候,操作系统调用入口函数,并说明动态链接库被调用的原因,它所有的可能值为:DLL_PROCESS_ATTACH: 进程被调用、DLL_THREAD_ATTACH: 线程被调用、DLL_PROCESS_DETACH: 进程被停止、DLL_THREAD_DETACH: 线程被停止;lpReserved为保留参数。到此为止,DLL的入口函数已经写了,剩下部分的实现也不难,你可以在DLL工程中加入你所想要输出的函数或变量了。

  我们已经知道DLL是包含若干个函数的库文件,应用程序使用DLL中的函数之前,应该先导出这些函数,以便供给应用程序使用。要导出这些函数有两种方法,一是在定义函数时使用导出关键字_declspec(dllexport),另外一种方法是在创建DLL文件时使用模块定义文件.Def。需要读者注意的是在使用第一种方法的时候,不能使用DEF文件。下面通过两个例子来说明如何使用这两种方法创建DLL文件。

  1)使用导出函数关键字_declspec(dllexport)创建MyDll.dll,该动态链接库中有两个函数,分别用来实现得到两个数的最大和最小数。在MyDll.h和MyDLL.cpp文件中分别输入如下原代码:
 
//MyDLL.h
extern "C" _declspec(dllexport) int desinit(int mode);
extern "C" _declspec(dllexport) void desdone(void);
extern "C" _declspec(dllexport) void des_setkey(char *subkey, char *key);
extern "C" _declspec(dllexport) void endes(char *block, char *subkey);
extern "C" _declspec(dllexport) void dedes(char *block, char *subkey);
//MyDll.cpp
#include"MyDll.h"
//这里我用了比较大小的函数代替了我要实现的函数
int desinit(int a, int b)
{
if(a>=b)return a;
else
return b;
}
int desdone(int a, int b)
{
if(a>=b)return b;
else
return a;
}
该动态链接库编译成功后,打开MyDll工程中的debug目录,可以看到MyDll.dll、MyDll.lib两个文件。LIB文件中包含DLL文件名和DLL文件中的函数名等,该LIB文件只是对应该DLL文件的"映像文件",与DLL文件中,LIB文件的长度要小的多,在进行隐式链接DLL时要用到它。读者可能已经注意到在MyDll.h中有关键字"extern C",它可以使其他编程语言访问你编写的DLL中的函数。
LoadRunner调用动态链接库
        上面完成动态链接库开发后,下面就介绍动态链接库如何被LoadRunner进行调用,其实也是很简单的。在LoadRunner中的DLL调用有局部调用与全局调用,下面介绍局部调用。
首先把你编译的DLL放在角本路径下面,这里是MyDll.dll,MyDll.lib.然后在Action中使用
lr_load_dll("MYDll.dll"),此函数可以把DLL加载进来,让你调用DLL里面的函数,而DLL中的运算是编译级的,所以效率极高,代码样例如下:
#include "lrs.h"
Action()
{
        //
        int nRet = 6;
        char srckey[129];
        memset(srckey, 'a', 128);
        lr_message(lr_eval_string(srckey));
        lr_load_dll("MyDLL.dll");
        nRet = desinit(5,8);
        lr_message("比较的结果为%d",nRet);
    return 0;
}
运行结果
        比较的结果为8

        全局的动态链接库的调用则需要修改mdrv.dat,路径在LoadRunner的安装目录下面(LoadRunner/dat directory);在里面修改如例:
        [WinSock]
ExtPriorityType=protocol
WINNT_EXT_LIBS=wsrun32.dll
WIN95_EXT_LIBS=wsrun32.dll
LINUX_EXT_LIBS=liblrs.so
SOLARIS_EXT_LIBS=liblrs.so
HPUX_EXT_LIBS=liblrs.sl
AIX_EXT_LIBS=liblrs.so
LibCfgFunc=winsock_exten_conf
UtilityExt=lrun_api
ExtMessageQueue=0
ExtCmdLineOverwrite=-WinInet No
ExtCmdLineConc=-UsingWinInet No
WINNT_DLLS=user_dll1.dll, user_dll2.dll, ...
//最后一行是加载你需要的DLL
        这样你就可以在LR中随意的调用程序员写的API函数,进行一些复杂的数据加密,准备的一些操作,进行复杂的测试。同时如果你觉的有大量高复杂的运算也可以放在DLL中进行封装,以提高效率。
作者: cwj007    时间: 2005-8-1 20:52
呵呵,自己顶一下

[ Last edited by cwj007 on 2005-8-2 at 16:37 ]
作者: bbbian    时间: 2005-8-2 14:20
标题: 支持
不错,希望继续发表,多谢
作者: ecust    时间: 2005-8-4 09:21
这个是高级应用啊!看不大懂,不过还是顶,谢谢分享
作者: hbx_303    时间: 2005-8-4 20:27
好贴,希望楼主继续发好贴!
作者: damocau    时间: 2005-8-5 14:12
标题:
不错,高。
作者: chenbaidu    时间: 2005-9-8 21:36
太高了
我丝毫看不懂
作者: BBY    时间: 2005-9-15 09:56
标题: 我也看不懂,真想象他那样写!
我刚用这个,也才是测试JAVA写的东东,原来他还可以测试VC的函数什么的,我不知道:)
作者: sendy    时间: 2005-9-15 13:21
我也一点都看不懂,不过还是顶一下,希望楼主以后多发好贴!
作者: ygwgd    时间: 2005-9-15 19:46
就是看不懂嘛:
作者: lotus    时间: 2005-9-26 14:05
创建 1. Win32 Dynamic-Link Library方式创建Non-MFC DLL动态链接库 这步就没看懂 按说明 
选择Win32 Dynamic-Link Library建立一个空的DLL工程
但没能找到DllMain() 不理解
作者: angel_test    时间: 2005-9-26 19:34
我也顶一下,虽然没太看懂,多看几遍,就差不多吧,呵呵。
作者: jing镜    时间: 2005-12-5 16:40
看不懂什么毛瞧!还是顶呀!
作者: 测试小子    时间: 2005-12-8 09:16
lz的这个太复杂了,有简单的办法啊,程序员可以把自己开发的函数封装在一个dll文件里,写脚本的时候直接在
actio()的一开始调用lr_load_dll(”文件绝对位置“)

例如:有个封装了的文件叫test.dll,包含函数testa(x,y),testb(x,y)

则在init文件中定义
atest()
{ int a;
  int b;
testa(a,b);
……
}

btest()
{ int a;
  int b;
testb(a,b);
……
}

在action()
{ lr_load_dll("c:\\test.dll“)
atest();
btest();
……
}
作者: lotus    时间: 2005-12-13 16:23
原帖由 lotus 于 2005-9-26 14:05 发表
创建 1. Win32 Dynamic-Link Library方式创建Non-MFC DLL动态链接库 这步就没看懂 按说明 
选择Win32 Dynamic-Link Library建立一个空的DLL工程
但没能找到DllMain() 不理解


楼主的这篇文章写得不错,可惜有一处错误,还有一处没有指明,
折腾了我两个多小时,汗呀,差点就放弃了

1.Win32 Dynamic-Link Library方式创建Non-MFC DLL动态链接库,向导会有个提示,询问选择那个类型,最好选择最后一项“A DLL that exports some symbols”

2.MyDLL.h中函数申明
extern "C" _declspec(dllexport) int desinit(int mode);
写得有误与定义不一样,定义时使用了两个参数,可恶的是VC编译时不报错
修改为extern "C" _declspec(dllexport) int desinit(int a,int b);
哎。。。我过去没学过VC,就这一个小错误,折腾惨了
作者: angel_test    时间: 2005-12-13 16:42
呵呵,今天我终于要用到这个了,感谢楼主,希望多发好帖!
作者: wealthtime    时间: 2005-12-19 21:49
标题: 回复 #14 测试小子 的帖子
这种方法不错,最近使用了一把!用后觉得很简单
作者: liangjz    时间: 2006-1-4 11:27
使用供loadrunner调用的dll有很多使用限制。
比如 导出函数不能返回 char * 类型。

另外,使用    VC  编译的dll性能比 loadrunner 自定义的用户函数效率高几倍乃至几十倍
作者: cwj007    时间: 2006-3-6 19:47
楼上说的不错,对于效率比较低的角本,建议不要用LR的解释型角本来写
作者: rtest    时间: 2006-3-7 15:45
标题: I think that way is very good !
非常好的一个主题,感谢作者的贡献
作者: rtest    时间: 2006-3-7 15:49
标题: 我认为13楼的方法也很好
强顶
作者: rlyan    时间: 2006-3-27 12:13
调用dll很麻烦的,还得复制到每台VG客户机上。还有个问题就是要考虑并发量增大以后,dll里并发的问题,头疼~
作者: lgwmlx    时间: 2006-4-12 22:33
不错不错。
作者: hehemeimei    时间: 2006-4-14 14:24
这个帖子太棒了,还希望有更多的类似这样的帖子,顶一下。虽说不是很明白。
作者: victorxiang    时间: 2006-6-8 18:26
ding
作者: lizzi    时间: 2006-6-12 13:24
原帖由 rlyan 于 2006-3-27 12:13 发表
调用dll很麻烦的,还得复制到每台VG客户机上。还有个问题就是要考虑并发量增大以后,dll里并发的问题,头疼~

能不能说说是怎么解决dll里并发的问题呢?
作者: 冷月    时间: 2006-6-21 12:05
标题: 找了我一上午了
呵呵,找了我一上午了,有机会试试。谢谢!
作者: zension    时间: 2006-6-21 18:39
好文章 
作者: 麦子华华    时间: 2006-6-27 12:37
做个标记,等会来学学
作者: 麦子华华    时间: 2006-6-27 14:49
则在init文件中定义
atest()
{ int a;
  int b;
testa(a,b);
……
}

btest()
{ int a;
  int b;
testb(a,b);
……
}

在action()
{ lr_load_dll("c:\\test.dll“)
atest();
btest();
……
}  


在init()中定义的2个函数atest(), btest() 是干什么用的,为什么不直接在action中调用dll中的函数testa(), testb(). 没明白
作者: lvming    时间: 2006-6-29 21:21
拜读
作者: lfy123    时间: 2006-7-20 16:41
先收藏,慢慢研究!
作者: olympic2008    时间: 2006-7-27 12:05
不是很懂
up
作者: fengniao    时间: 2006-8-11 10:27
这种解决方案在小批量的情况下是可行的,但是LZ没有想到一些其他的问题:
1.大批量调用的时候会存在并发线程访问的问题!
2.会对客户端machine带来巨大的资源开销,如果实在必要,就需要增加客户端machine数量!
作者: rsz801115    时间: 2006-10-13 16:56
好贴,正在学习中
作者: zx008    时间: 2006-10-20 12:19
标题: 协议的选择
测试类似QQ的通讯软件时,请问你选择的是什么协议,是通过DLL调用接口测试的还是通过录制完成测试的。
作者: softkk    时间: 2006-10-20 14:15
新手,很好的思路
作者: smallsophia    时间: 2006-11-2 15:47
都挺厉害的,惭愧
作者: liuyang1979    时间: 2006-11-3 15:08
好贴,虽然现在用不到!先收藏!
作者: rsz801115    时间: 2006-11-18 13:41
用JAVA开发的,C/S结构的,手机游戏请问选择什么协议录制,我们原来是调用类
作者: enjoytest    时间: 2006-12-13 10:25
好东西
作者: selon    时间: 2007-1-14 14:21
试了一下 还不错
作者: wen_zh_smile    时间: 2007-4-22 10:41
看了不太理解,不过,这是个非常好的思路.
作者: jinjing976    时间: 2007-4-26 11:08
好东西,收藏下~~~~~
作者: huangning    时间: 2007-7-2 10:03
我想知道楼主从哪里学来的这种“武林秘笈”,我辈怎么只能找到关于“花拳秀腿”的资料呢?sdlkfj3
作者: acool198391    时间: 2007-7-3 10:31
sdlkfj3 LZ太厉害了 支持
作者: huhao5403    时间: 2007-8-3 10:19
为什么我的debug文件夹中没有mydll.lib文件呢?请指教
作者: xjcool    时间: 2007-8-31 09:56
这个是高级应用啊!看不大懂,不过还是顶,谢谢分享
作者: senciya    时间: 2007-9-13 16:58
谢谢楼主
作者: mystufo    时间: 2007-9-28 12:00
这个平时用的很多吗
作者: 就是爱测试    时间: 2007-9-30 15:26
一定都看不懂呢,不过还是支持一下
作者: wanghy    时间: 2007-10-9 15:13
标题: 回复 1# 的帖子
留着以后漫漫学
作者: dengdage    时间: 2007-10-19 11:14
看不懂....慢慢来
作者: superfang    时间: 2007-12-2 09:08
要是100个人并发,应该如何编程呢!? 如何做并发处理呢? 
 
      高手给个思路吧! 我是个菜鸟,上面的代码我已经调试过了。真的很不错的。
作者: qicyt1812    时间: 2007-12-17 10:42

作者: dahe_1984    时间: 2007-12-19 12:00
标题: 回复 15# 的帖子
感谢 注释.....
作者: TEST_HUAN    时间: 2008-2-1 17:07
提供了解决问题的思路,也向测试人员提出了更高的要求,开发能力。
没有多少开发人员愿意为测试写测试dll。
我想有开发能力的测试人员不多吧。我们部门大部分是女的。机会没有开发能力
作者: chenyunjun169    时间: 2008-4-9 10:46
非常感谢楼主,内容很不错值得我学习!
作者: muyang327    时间: 2008-7-5 20:10
不错,支持。学习了。
作者: joannaready    时间: 2008-7-30 16:16
标题: 备用

作者: carry1986    时间: 2008-11-12 17:20
学习中,,看了这东西,不是很懂哦,,还是要好好学习中.....
作者: czh84063149    时间: 2009-2-11 14:55
不太懂
作者: qinxiaocang1202    时间: 2009-2-27 15:37
看的云里雾里的
作者: jashwhw    时间: 2009-3-2 10:19
太高深了  谢谢楼主!
作者: conanin    时间: 2009-7-21 22:20
不错,学习了,感谢楼主分享
作者: bluejay    时间: 2009-9-8 16:10
原来网上广为流传的DLL调用是我们的版主写的哦!~
作者: 行云流水    时间: 2009-11-17 12:49
能力有限,看不太懂,还是帮忙顶下.
作者: lubruth    时间: 2010-5-19 15:04
好贴,继续分享
作者: linyucc    时间: 2010-10-19 18:08
好东西,需要顶
作者: xinqidian123    时间: 2010-11-9 09:30
非常好···收藏了。。。
作者: xinqidian123    时间: 2010-11-9 09:42
dll的开发。。还是要靠研发的吧。。
作者: 炫彩琉璃    时间: 2010-11-22 11:29
了解到新的知识很开心~谢谢楼主积极分享
作者: wuliangye    时间: 2010-12-22 15:40
呜呜,看不懂
作者: ljj149850508    时间: 2011-2-14 21:11
先顶下,以后好查
作者: polly12052000    时间: 2011-10-21 17:01
太高深了。
作者: thirfing    时间: 2011-11-12 20:53
最近正学习dll调用,多谢楼主。
作者: thirfing    时间: 2011-12-5 16:37

作者: xiaoshi_2011    时间: 2012-4-19 13:21
很有深度,学习中,谢谢楼主
作者: lzzcs2008    时间: 2012-5-14 11:37
我就知道在用C写的方法在头文件里表面就能调用.....但是还没真正用过。。。
作者: testMA    时间: 2012-11-23 17:44
此贴已阅!!!!
作者: shotting    时间: 2013-3-11 17:30
感谢贡献,学习了
作者: 飞丶飏。的青春    时间: 2013-6-5 13:04
15楼说的没错,建立的是A DLL that exports some symbols!我们最近就在学习这个。




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2