听说UiBot支持C++语言扩展,具体要怎么操作?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了听说UiBot支持C++语言扩展,具体要怎么操作?相关的知识,希望对你有一定的参考价值。
UiBot本身的部分代码就是基于微软的.Net框架,用C#语言编写的。所以,也可以用C#语言编写UiBot的插件(以下简称为.Net插件)。实际上,微软的.Net框架支持多种编程语言,包括VB.Net、C++/CLI等等,这些编程语言都遵循.Net框架的规范,它们都可以用来编写.Net插件,但因为C#是微软主推的编程语言,所以本文用C#举例,有经验的读者亦可将其移植到.Net框架上的其他语言。另外,UiBot对.Net插件的支持也是在不断升级的,本文以UiBot Creator 5.1版为例,如果在老版本的UiBot上,一些例子可能无法正常运行,请及时升级。
为了方便您用C#语言写.Net插件,我们设计了一个插件的模板,并将其源码放在GitHub上,点击这里即可获取。如果您习惯使用git,也可以从这个URL拉取:https://github.com/Laiye-UiBot/extend-example。建议您在写.Net插件的时候,直接在这个模板的基础上写,而无需从头开始。后续讲述的内容,也将围绕这个模板中的例子展开。
和Java插件类似,.Net插件也需要编译成扩展名为.dll的文件,才能被UiBot使用。微软的集成开发环境Visual Studio兼具编写和编译的功能,并且也提供了免费的社区版,推荐下载使用。我们提供的模板是基于Visual Studio 2015版本的,您可以选择这个版本,也可以选更高版本的Visual Studio,但不建议使用低于2015版本的Visual Studio。
安装了Visual Studio,并下载了我们的.Net插件模板后,可以双击UiBotPlugin.sln文件,这是一个“解决方案”,名字起得很唬人,实际上就是多个相关联的文件的集合。用Visual Studio打开这个解决方案后。可以看到,里面包含了很多内容,其中唯一需要我们动手修改的是UiBotPlugin.cs文件,其他的文件、引用、Properties等都可以不去动。如下图:
.Net插件的模板
在UiBotPlugin.cs文件里,有一个叫UiBotPlugin的命名空间,其中包含了一个接口(interface)和一个类(class)。为了避免混淆,我们推荐把这个命名空间的名字改为您的插件名。比如最终的插件文件是DotNetPlugin.dll,那么插件名就是DotNetPlugin,这个命名空间的名字也改为DotNetPlugin为宜。
从模板中可以看出:在接口里面声明了三个函数,在类里面写了这三个函数的实现。这三个函数都是例子,您随时可以把它们的声明和实现都删掉,加入您自己的插件函数。但请特别注意:在加入函数的时候,也要保持类似的写法,需要在接口中声明,在类中实现,否则,UiBot不能正常识别这个插件函数。
我们用例子中的Add函数为例,尝试编译插件,并在UiBot中调用这个函数:
选择Visual Studio的“生成”(Build)菜单项,编译这个解决方案之后,会看到在插件的目录下有个叫Release的目录,里面产生了一个叫UiBotPlugin.dll的文件。
把这个文件手动改名为您的插件名,并保留.dll的扩展名。如改名为DotNetPlugin.dll。
把这个文件放到UiBot的extend/DotNet目录下。
打开UiBot,新建一个流程,在源代码视图写入代码:
Traceprint DotNetPlugin.add(1, 1)运行此流程,结果如下所示,代表插件调用正常。
.Net插件运行结果您可能注意到了,在前面的Python插件、Java插件的例子中,都有Add这个例子函数,而除了插件名之外,UiBot调用它们的方式和运行结果都没有区别。实际上,不同的插件内部实现是有很大差异的,比如在Python语言里,默认用UTF-8编码来保存字符串,而在.Net里默认用UTF-16保存。但UiBot已经帮您抹平了这些差异,让您在使用的过程中不必关心这些细节。
9.3.2 插件API
和Python、Java插件类似,在.Net插件中,也可以使用插件API,反过来调用UiBot的一部分功能。如果要调用插件API,只需要基于UiBot提供的模板编写插件即可,无需做其他任何设置。
.Net插件中能使用的插件API的名字、参数和含义都和Java插件完全一致,例如,可以用UiBot.API.IsStop()来检测当前流程是否需要马上停下来,等等。请参考Java插件的中关于插件API的讲解,不再赘述。
在模板中,您可能会看到一个名叫DotNetAdapter.dll的文件。实际上,这个文件是UiBot每个版本都包含的。从UiBot 5.1版开始,您调用的.Net版的插件API,实际上都在这个文件里面实现。因此,当您的插件发布的时候,并不需要包含这个文件,因为UiBot已经自带了。
同时,如果您的UiBot更新到了更高的版本,DotNetAdapter.dll中也可能会包含了更多的插件API。您可以自行从UiBot中拿到新版本的DotNetAdapter.dll文件,并放在您编写的插件的源代码所在的目录下,即可使用到新版的插件API。
9.3.3 变量的传递
和Java类似,C#.Net也是静态类型的编程语言,变量在使用之前需要先定义,且定义时必须指定变量的类型。而且,数组中通常只能包含同一种类型的数据。这与UiBot的动态类型有很大的不同。
因此,在编写和使用.Net插件的时候,需要符合以下规定:
对于整数、浮点数、字符串、布尔类型等基本类型的参数,UiBot对.Net插件的类型检查不是很严格,它会尽量进行转换,即使转换不成功,也不会报错。所以,请在使用时特别留意每个参数的类型,避免传入了不正确的值,而没有及时发现。
如果需要把字典或数组类型从UiBot中传到.Net插件中,.Net插件中的参数类型只能使用Newtonsoft.Json.Linq.JArray(对应数组)或者Newtonsoft.Json.Linq.JObject(对应字典)。在模板中,由于我们已经写了using Newtonsoft.Json.Linq;,所以可以省略前缀,简写为JArray(对应数组)或JObject(对应字典),下文亦使用此简化写法。
如果需要把字典或数组类型从.Net插件中传到UiBot中,.Net插件中的返回值类型只能使用JArray(对应数组)或JObject(对应数组)。UiBot会自动把JArray类型的返回值转换成UiBot中的数组,而把 JObject类型的返回值转换成UiBot中的字典。
无论传入参数,还是返回值,这些复合类型在.Net插件和UiBot之间都采用值传递的方式,而不是引用传递的方式。
在插件模板中,有一个作为例子的Concat函数,用于演示如何把两个数组从UiBot传到.Net插件中,又如何把两个数组连接后的结果返回到UiBot中。建议读者仔细阅读。
9.3.4 插件的引用模块
UiBot本身是依赖于.Net Framework的,并且假设用户已经安装了.Net Framework 4.5.2(含)以上的版本。如果没有安装.Net Framework,或者版本不对,UiBot本身都不能运行,当然就更不能使用您编写的插件了。所以,在编写插件的时候,只要您的插件依赖的也是.Net Framework 4.5.2版本,就不必担心环境不匹配的问题。
微软已经在.Net Framework里面内置了非常丰富的功能,但难免有的功能仍然没有包含,需要引用第三方的.Net dll文件。
和Java插件类似,UiBot在加载一个.Net插件的时候,如果这个.Net插件引用了其他第三方的.Net dll文件,UiBot首先会试图到.Net插件所在的目录下去搜索被引用的dll文件。如果没有找到,还会再到<插件名>.lib这个目录下去找一次。比如,我们有个.Net插件,名为A.dll,放置在extend/DotNet目录中,且引用了B.dll。那么UiBot会先尝试找extend/DotNet/B.dll,再尝试找extend/DotNet/A.lib/B.dll。如果这两个目录下都没有找到,会抛出异常。
9.3.5 其他注意事项
JArray和JObject并不是.Net Framework里面自带的,而是使用了开源的Json.Net。在编译和运行的时候,都需要依赖一个名为Newtonsoft.Json.dll的文件。 在UiBot提供的模板中,已经包含了这个文件。同时,在每个版本的UiBot中,也会自带这个文件。因此,您可以直接使用JArray和JObject,而并不需要把这个文件包含在插件当中。
在编译插件的时候,编译器可能会警告“DotNetAdapter的处理器架构不匹配”之类的信息。实际上没有影响,无需理睬这个警告。
.Net插件中的函数支持默认参数。在调用时,如果某些参数有默认值,则可以不传值,此参数会自动取默认值。
可以在.Net插件的函数中抛出异常,异常可以由.Net插件自行捕获,也可以不捕获。如果.Net插件不捕获,那么异常会自动被传到UiBot中,UiBot可以捕获。 如果UiBot也不捕获,那么流程的运行会出错退出,并且会在出错信息中说明是由于.Net插件中的异常导致的,以便排查问题。
.Net中的变量、函数都是区分大小写的,但在UiBot中使用.Net插件时,仍然可以不区分大小写的调用其中的函数。比如,在前面的例子中,可以在UiBot中写DotNet.add(1,1),也可以写dotnet.ADD(1,1),其效果完全一样。
使用pybind11开发python扩展库
当我们使用python的类时,可以动态地添加属性到类里去,这是基本的工作机制,但是在C++语言里的类是固定的,也就是说在编译之后是固定的,不会变化。因此要想让C++里导出的类支持python这种特性,必须有一些改变才可以。现在就来搞明白怎么样让C++里导出的类支持这个特性。
这时需要引入使用py::dynamic_attr()特性,经过它处理之后,就可以让C++类导出之后具备动态添加成员变量的功能,声明如下:
py::class_<MyPet>(m, "MyPet", py::dynamic_attr())
.def(py::init<const std::string &>())
.def_property("name", &MyPet::getName, &MyPet::setName);
而类MyPet定义如下:
class MyPet {
public:
MyPet(const std::string &name) : name(name) { }
void setName(const std::string &name_) { name = name_; }
const std::string &getName() const { return name; }
private:
std::string name;
};
可见在这个类没有声明任何特别的类型,就可以在python里使用了,如下来测试一下:
#演法动态属性
p = TestAdd.MyPet
以上是关于听说UiBot支持C++语言扩展,具体要怎么操作?的主要内容,如果未能解决你的问题,请参考以下文章
UiBot无法抓取Google Chrome元素和数据抓取工具无法使用的解决方案
Eclipse CDT 编辑器支持 altivec C++ 扩展?