闲谈
因为Qt封装了很多个人感觉很好用的库,所以一直想通过CAPL去调用Qt实现一些功能,但是一直没机会(网络上也没看到这方面的教程),这次自己用了两天,踩了很多坑,终于是做成了一个初步的调用方案,虽然有点麻烦,但是以后可能会让自己提高很多的效率。
之前的方案是通过Qt制作面板,然后CAPL和Qt通过tcp/udp进行通讯,实现了部分功能
现在是直接封装成dll,不需要单独打开Qt程序的界面
废话结束,进入正题
制作Qt的DLL
可以参考这个博主的博客
https://www.cnblogs.com/susiesnai-sun/p/16872488.html
我的dll是解析HEX,BIN,S19文件的,虽然这个可以capl解决,但是为了复用,还是做了一个
如下图
.pro
.h
.cpp
因为涉及公司相关的东西,.CPP不全,只当作参考,但是过程很明显
制作capl dll
打开CANoe给定的制作dll的demo,下附制作的代码,可以参考。在这里遇到一些问题,生成的dll在CANoe调用的时候,总是加载库函数失败,通过自己新建c++项目发现,因为是dll调用dll,我猜是因为项目的路径有问题,然后把对应的dll全部放到项目路径下才加载成功。切记。
cpp
HANDLE hThead;
uint16_t File_flag = 0;
char fileName[10000] = "";
typedef uint8_t(*BOOTFILERED)(char[], uint8_t*, uint64_t&); // 定义函数指针类型
HMODULE hLib = NULL;
uint8_t fileData[10000000];
uint64_t fileDataLength = 0;
DWORD _stdcall readFileThread(LPVOID p)
{
if (File_flag == 1)
{
BOOTFILERED readS19;
// 导出函数地址
readS19 = (BOOTFILERED)GetProcAddress(hLib, "readS19");
readS19(fileName, fileData, fileDataLength);
}
else if (File_flag == 2)
{
BOOTFILERED readHex;
// 导出函数地址
readHex = (BOOTFILERED)GetProcAddress(hLib, "readHex");
readHex(fileName, fileData, fileDataLength);
}
else if (File_flag == 2)
{
BOOTFILERED readBin;
// 导出函数地址
readBin = (BOOTFILERED)GetProcAddress(hLib, "readBin");
readBin(fileName, fileData, fileDataLength);
}
else {
return 4;
}
return 0;
}
uint64_t CAPLEXPORT CAPLPASCAL readFile(char file[], uint16_t flag)
{
if (hLib == NULL)//检测是否加载dll成功
{
hLib = LoadLibrary("bootloadReadFile.dll");
if (hLib == NULL)//检测是否加载dll成功
{
printf("加载DLLTest1.dll动态库失败\n");
return 1;
}
}
strncpy(fileName, file, strlen(file));
File_flag = flag;
DWORD dwThreadID;
hThead = CreateThread(NULL, 0, readFileThread, 0, 0, &dwThreadID);
return 0;
}
uint64_t CAPLEXPORT CAPLPASCAL getData(uint8_t *data)
{
for (uint64_t i = 0; i < fileDataLength; i++)
{
data[i] = fileData[i];
}
return fileDataLength;
}
// ============================================================================
// CAPL_DLL_INFO_LIST : list of exported functions
// The first field is predefined and mustn't be changed!
// The list has to end with a {0,0} entry!
// New struct supporting function names with up to 50 characters
// ============================================================================
CAPL_DLL_INFO4 table[] = {
{CDLL_VERSION_NAME, (CAPL_FARCALL)CDLL_VERSION, "", "", CAPL_DLL_CDECL, 0xabcd, CDLL_EXPORT },
{"bootloadReadFile", (CAPL_FARCALL)readFile, "BootloadFile","flag:1,s19;2,hex;3,bin",'U', 2, "CL", "\001\000", {"fileName","flag"}},
{"bootloadGetData", (CAPL_FARCALL)getData, "BootloadFile","Suggested array length is 100000000",'U', 1, "B", "\001", {"fileData"}},
{0, 0}
};
CAPL调用dll
如上一条所说,dll调用dll可能会出现问题,需要先把需要的dll加载进去
通过下图CANoe这里有一个介绍
1:我选择了第一条方案,我的路径是"C:\Program Files\Vector CANoe 15\Exec32",仅作参考。
对应的dll获取方式,自己写一个Qt窗口工程,然后选择32位的mingw的Release生成.exe文件。将此EXE文件复制粘贴到一个单独空白的文件夹里面,通过下图打开cmd窗口,进入到建立的目录下,执行windeployqt +"文件名",获取库函数,然后把.exe删掉就可以了。看下下图
2:将上面生成的dll,复制粘贴到路径(C:\Program Files\Vector CANoe 15\Exec32 这个是我的,具体看自己)
CANoe实现
c
/*@!Encoding:936*/
includes
{
#pragma library("capldll.dll")
}
variables
{
}
testcase readHEX()
{
byte hahha[10000000];
int i=0;
qword testdd=0;
write("哈哈哈 %d", bootloadReadFile("C:\\Users\\xiaoshuai\\Desktop\\test\\ED_C001_04_R2_CL_SV1.2_20221019.hex",2));
testWaitForTimeout(1000);
// bootloadGetData(hahha,testdd);
write("当前数据 %I64u",testdd=bootloadGetData(hahha));
for(i=0;i<testdd;i=i+16)
{
write("%d %02x",i/16,hahha[i]);
}
}
void MainTest ()
{
readHEX();
}
视频演示
之后加
总结
以上说明完成,记住几个踩坑点
1:vs2019中dll和sln放在同一个路径
2:CANoe的数字不能用指针
3:CANoe记得放入DLL
可能有些是没用的,可以自己尝试