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 preStarton 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,然后关闭重启CANoeCAPL 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编程—— DLL 的二次封装

CANoe DLL编程——通过VS 生成 SendKey.dll

CANoe DLL编程——DLL和回调函数

CANoe DLL编程—— Visual Studio 创建DLL以及动态调用

CANoe入门系列--用CAPL实现简单的开关灯

CANoe不能自动识别串口号?那就封装个DLL让它必须行