CANoe DLL编程—— 创建CANoe适用的DLL以及调用
Posted 蚂蚁小兵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CANoe DLL编程—— 创建CANoe适用的DLL以及调用相关的知识,希望对你有一定的参考价值。
相关文章
CANoe DLL编程(一)—— Visual Studio 创建DLL以及动态调用
前言
-
上一节我们已经掌握了怎么用VS创建一个DLL以及在VS中调用使用。
-
本节我们通过
Vector
的官方Demo
来学习下CANoe中DLL的规则和语法.
-
软件环境:
win10 x64
visual studio 2019
CANoe 11 x64
Vector Demo 工程理解
①,Vector Demo的路径如下C:\\Users\\Public\\Documents\\Vector\\CANoe\\Sample Configurations 11.0.55\\Programming
,因为我们在学习时有可能会对源码造成破坏,所以我们先copy一份
②,打开CANoe工程之后,什么都不做,先Run下,看下打印信息,明白这个工程干什么的,大致意思就是DLL里面定义了很多函数,然后按不同按键,调用不同函数。
③,打开capldll.can 看下源码,在includes
中它有个编译预处理,判断canoe是 x64 位还是 32位,然后选择不同的DLL
这就很离谱的是:我的window系统是64位的 ,CANoe软件是64的,但是根据打印结果,可以看出脚本打印的却是32位的,不知什么原因,所以我们用VS生成DLL,也应该选择32位平台
④,我想尝试下我自己生成的DLL,能不能正常使用;因为我用的是VS2019,我就打开VS 2017 Project
,不添加任何代码,然后将输出平台改成X86平台的
⑤,直接点击build
有可能报错如下图,如果报了这个错误,那就按下图设置下。
然后再点击build
生成 Debug\\capldll.dll
,将这个dll copy到 canoe工程 CAPLdll - Copy\\EXAMPLE\\EXEC32
路径下替换掉原来的capldll.dll,然后关闭重启CANoe,RUN下如果不报错就说明我们自己生成的DLL也是没问题。
源码赏析
代码初步理解
为了更好的理解CAN DLL的内容,CAPL脚本,C++脚本,帮助文档缺一不可
① 我们先了解下 on preStart
和 on start
中的代码,除了一些打印,就有两个重要函数
registerCAPLDLL
这个函数的作用是初始化CAPL DLL;并返回一个引用dword了类型的句柄,- 它还说了,这是考虑到你有可能再其它的node脚本中也引用了相同的DLL,为了不干扰,就分配了不同的句柄
- 而且这个句柄值还将作为回调函数的参数(下章将细说回调函数)
dllInit(gHandle)
初始化
②下图是源码中最为关键,也是和一般CANoe 自己为DLL创立的规则
CAPL_DLL_INFO4
是一个结构体类型,有九个参数CAPL_DLL_INFO4 table[]
结构体数组,table中配置了多少函数,那么再CANoe中引用这个DLL时就可以使用多少函数;也许你在C++脚本中写了100个函数,但是你在table中就定义了10个函数,那么你在CANoe中就只能使用这10个
③ 下图这九个参数的具体含义解释
typedef struct CAPL_DLL_INFO4{
char cdlName[MAX_CDL_NAME2]; // 在CAPL中调用时显示的函数名
CAPL_FARCALL adr; // 函数地址,即vs工程中函数定义时的函数名
const char* categoryName; // 函数在CAPL中的所属目录,可以用于对函数的分类
const char* hintText; // 对该函数功能的描述介绍(在CAPL中显示)
char resultType; // 函数的返回值类型,用CAPL中的类型的首字母大写去表示
int parCount; // 函数的参数个数
char parTypes[MAXCAPLFUNCPARS_8_1]; // 函数的参数类型,用CAPL中的类型的首字母大写去表示
unsigned char array[MAXCAPLFUNCPARS_8_1]; // 函数的参数是否是数组:\\001表示是1维数组;\\002表示2维数组。默认则为\\000,可省略,表示常量
const char* parNames[MAXCAPLFUNCPARS_8_1]; // 函数显示的参数名(在CAPL中的声明介绍时)
} CAPL_DLL_INFO4;
累了困了。。。
table的九个参数细说
①,我们在table中新增一行,让它仍然指向appAdd
这个函数,但是我们改了三个参数,待会重新build一下,去CANoe工程中看下有什么区别
- 参数1: // 在CAPL中调用时显示的函数名
- 参数2: // 函数地址,即vs工程中函数定义时的函数名
- 参数3: // 函数在CAPL中的所属目录,可以用于对函数的分类
- 参数4: // 对该函数功能的描述介绍(在CAPL中显示)
{"dllAdd", (CAPL_FARCALL)appAdd, "CAPL_DLL","This function will add two values. The return value is the result",'L', 2, "LL", "", {"x","y"}},
{"dll_test_Add", (CAPL_FARCALL)appAdd, "TEST_DLL","just for test",'L', 2, "LL", "", {"x","y"}},
②,我们把刚才重新build的dll从新copy到 CANoe工程 CAPLdll - Copy\\EXAMPLE\\EXEC32
路径下替换掉原来的capldll.dll,然后关闭重启CANoe
和CAPL Browser
- 在layout 菜单栏中调出
CAPL Function
,可以看到我们刚才添加的一行代码,和之前有什么不同 - 函数的分类多了一个新建的
TEST_DLL
- 多了一个函数
dll_test_Add
,可以在capl脚本中尝试下,和dllAdd
功能是一样的 - 函数的解释说明
②,参数5-9主要是函数参数的问题,下面列出了主要可能出现的参数类型
- 参数5: //函数的返回值类型,用CAPL中的类型的首字母大写去表示
- 参数6: // 函数的参数个数
- 参数7: // 函数的参数类型,用CAPL中的类型的首字母大写去表示
- 参数8: // 函数的参数是否是数组:\\001表示是1维数组;\\002表示2维数组。默认则为\\000,可省略,表示常量
- 参数9: // 函数显示的参数名(在CAPL中的声明介绍时)
- 下图是CAPL的数据类型和C++的数据类型对比,然后再
table
中用大写首字母表示 - 函数参数最多支持64个参数,没人能用那么多吧。。。
- 下面的代码很重要,很重要,很重要,基本包括了参数的所有类型。
/***************************参数是常量的情况***********************************/
long CAPLEXPORT far CAPLPASCAL appAdd(long x, long y)
{
long z = x + y;
return z;
}
'L', 2, "LL", "", {"x","y"} //参数都是常量,可以省略\\000
/***************************参数是一维数组的情况***********************************/
void CAPLEXPORT far CAPLPASCAL appPutDataTwoPars( unsigned long numberBytes,const unsigned char dataBlock[] )
{
unsigned int i;
for (i = 0; i < numberBytes; i++)
{
dlldata[i] = dataBlock[i];
}
}
'V', 2, "DB", "\\000\\001", {"noOfBytes","datablock"}
/***************************参数是二维数组的情况***********************************/
void CAPLEXPORT far CAPLPASCAL appPutDataTwoPars_2( unsigned long numberBytes,const unsigned char dataBlock[],const unsigned char dataBlock_2[][] )
{
unsigned int i;
for (i = 0; i < numberBytes; i++)
{
dlldata[i] = dataBlock[i];
}
}
'V', 3, "DBB", "\\000\\001\\002", {"noOfBytes","datablock",dataBlock_2}
/***************************参数是指针的情况***********************************/
void CAPLEXPORT far CAPLPASCAL appSum(long i, long j, long* s)
{
*s = i + j;
}
'V', 3, {'L', 'L', 'L' - 128}, "", {"i", "j", "s"}
③,因为官方demo中没有传递指针的情况,下面我们添加一个实例函数
//添加一个 求和函数
void CAPLEXPORT far CAPLPASCAL appSum(long i, long j, long* s)
{
*s = i + j;
}
//table中定义
{"dll_test_Sum", (CAPL_FARCALL)appSum, "TEST_DLL","Sum via reference parameter",'V', 3, {'L', 'L', 'L' - 128}, "", {"i", "j", "s"} },
//重新build之后,再capl中添加代码,可以打印sum的值。
on key '2'
{
long sum ;
writeLineEx(1,1,"");
writeLineEx(1,1,"<2> Sum via reference parameter");
dll_test_Sum(10,20,sum);
writeLineEx(1,1,"Call CAPL DLL Function dll_test_Sum() Result = %d ",sum);
}
总结
- 要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!
- 如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。
以上是关于CANoe DLL编程—— 创建CANoe适用的DLL以及调用的主要内容,如果未能解决你的问题,请参考以下文章
CANoe DLL编程——通过VS 生成 SendKey.dll