模拟精灵支持标准的DLL动态链接库,您可以使用其他编程语言轻松扩展模拟精灵的功能,也可以在模拟精灵中调用其他标准DLL提供的接口函数,如调用系统提供的WinAPI函数。
下面以调用user32.dll中的MessageBoxA函数举例说明:
1、首先,使用dll.open函数导入函数并赋值给messageBox变量。
2、然后就可以象使用普通函数一样使用messageBox函数了。
3、当确认不再使用messageBox函数时,使用dll.close释放函数。(可以省略这句代码,交由模拟精灵自动释放)
dll.open函数说明:
在模拟精灵中使用的函数名字 = dll.open("dll文件名或路径","api函数名字","声明函数原形", "调用约定,可省略")
第一个参数指定dll路径,也可以仅指定文件名或相对路径(可以省略.dll后缀),
如果指定文件名或相对路径,模拟精灵首先在默认的插件目录Fairy_Ape\import下搜寻dll文件。
如果没有找到,将按以下顺序搜索:
1、模拟精灵所以目录。
2、当前目录。
3、Windows 系统目录。win.getSysDir() 函数检索此目录的路径。
4、Windows 目录。win.getWinDir() 函数检索此目录的路径。
5、PATH 环境变量中列出的目录。
最后一个参数指定调用约定,这个参数是可以省略的,默认的调用方式为stdcall.
在使用WinAPI时默认的调用约定也是stdcall,所以在调用WinAPI时最后一个参数也可以省略。
如果您在导入其他一些DLL中的函数时出现错误,可以尝试指定cdecl调用通常能解决问题。
最后我们说一下如何声明函数原形,这是最复杂也是最重要的一部份。
好在本手册中已经有了相关WinAPI函数的声明,直接复制即可使用,但是了解一下仍然是有用的。
首先,在模拟精灵LAScript中,所有数字都是number类型,因为模拟精灵是高级动态语言,对于类型是自动适应自动转换的。
但是在DLL中的类型相对就复杂的多,这就需要我们指定API函数中的参数类型及字节长度,这样模拟精灵才能自动的进行转换。
这个指定函数的参数、返回值的变量类型及字节长度的过程就称为声明函数原形。
例如上面messageBox 的函数原形为V(I,S,S,I),参数及返回值的类型都用一个类型标记来指定。
括号内部表示参数,括号前面用一个字符标记返回值的类型。
[P标记:有输出值的参数]
我们再来看一个完整示例 --用Win API检测是否上网和上网类型(通过局域网、广域网)
dll.open 函数调用其他语言编写的DLL动态链接库时,参数支持自定义类型(struct)
以面以GetCursorPos举例说明,注意下面的代码稍有点复杂,仅作为声明struct的一个例子,实际上用 x,y = mouse.getPos() 即可方便的取得鼠标当前位置.
win.consoleOpen()
--GetCursorPos 的参数是一个struct POINT自定义类型的按引用传递方式,相应的参数标记为P(即传递类型指针)
GetCursorPos = dll.open("user32.dll", "GetCursorPos", "n(P)")
--[[在调用动态链接库时如何声明struct自定义类型呢?
例如,在GetCursorPos中需要用到的自定义类型POINT,在C语言中如下声明
struct POINT
{
LONG x;
LONG y;
}
--]]
--那么我们在LAScript中可以如下声明 struct POINT
point ={
x=0;
y=0;
};
--[[
因为table字典是无序的,而struct是有序的,我们还要在table中添加数组声明元素的顺序
并且在每个键名前附加一个字符标记相应元素的类型,
这些标记基本与dll.open的参数类型标记相同。
唯一的区别是声明struct时小写的s表示char[]数组,而dll.open中小写的s与大写的S都表示字符串指针。
--]]
point[1]= "ix"; --i表示x是一个32位整数(long)
point[2]= "iy";--i表示x是一个32位整数(long)
--上面的代码也可以写在一起
point={
x=0;y=0; --定义结构
"ix";"iy"; --定义结构中元素的类型、顺序
};
re,pt = GetCursorPos(point);
--point的值是按引用传递的,所以返回值pt等于参数point ,所以这里的pt返回值是可以不要的
print("GetCursorPos取得的坐标",point.x,point.y);
如果dll.open的第二个参数是字符串则通过函数名导入。
如果dll.open的第二个参数是数字则通过函数序号导入。
在模拟精灵中使用的函数名字 = dll.open("dll文件名或路径",api函数序号,"声明函数原形", "调用约定,可省略")
dll.close(外部DLL函数)
立即释放外部DLL函数。并不会删除函数变量量(函数变量指向无效的外部DLL函数)。
外部DLL函数 = nil;
立即删除函数变量,等待垃圾收集释放函数变量引用的外部DLL函数。
1、dll.open函数对于同一个dll函数使用一次性加载。
即重复调用dll.open加载同一个dll中的同一个函数时直接返回已加载的函数.
而不会重复的从dll中导入相同的函数。
2、dll.open函数自动搜索dll文件的规则。
如果指定相对路径,将按以下顺序搜索dll:
1、小精灵插件目录、
2、模拟精灵插件目录,
3、按DLL常规搜索当前目录、系统目录。