vs生成dll的学习
之前都是用dll , 最近可能需要提供dll给别人, 那么dll怎么生成呢?
bilibili上面有很多这类视频教程 , 以下是自己记录自己学习的路.
在打开的writedll.cpp里面, 模仿上面的写法,写add()函数
然后, 去h头文件里添加这个add函数,
右键点击头部那个 include<writedll.h> ,选择打开那个h文件
继续模仿上面给出的示例, 写入add函数
保存, 右键点击工程头,选择编译生成dll ,
生成成功提示:
我们去debug目录里找到那个dll
这样就生成了一个简单的dll , 里面有封装add()这个函数, 以后别的程序可以调用这个dll来使用这个add函数了
下面用aardio调用下这个dll中的add函数, 看看是不是能用
import win.ui; /*DSG{{*/ mainForm = win.form(text="aardio工程8";right=657;bottom=421) mainForm.add() /*}}*/ import console console.open() var dll = ..raw.loadDll("\res\Wrtiedll.dll","dllshare","cdecl"); console.log( dll.add(3,4) ) mainForm.show(); return win.loopMessage();
运行后可以看到:
同样调用示例的函数
dll中调用dll应该怎么写 ?( 封装dll为另外一个dll)
按照之前的方法, 新建一个win32的dll工程includedll
然后 , 把楼上之前生成的writedll.dll / writedll.h / writedll.Lib 这三个文件复制到刚刚新建的工程目录文件夹里面
然后在打开的includedll.cpp文件里添加
#include "Wrtiedll.h" #pragma comment(lib,"Wrtiedll.lib") // 这是导出函数的一个示例。 INCLUDEDLL_API int fadd(void) { return add(43,56); }
删掉原来的那些个声明函数, 修改后如下图
然后去includedll.h头文件那里把这个fadd()函数给声明下
保存工程, 编译,生成dll
成功了.
下面用aardio调用下这个dll试试看
把这个生成的includedll.dll复制到上面的aardio工程里面
import console console.open() var dll = ..raw.loadDll("\res\includedll.dll",,"dllshare","cdecl"); console.log( dll.fadd() )
运行后出错误了.
提示说这个dll不能被加载,,,,...................
正常的,肯定会出错, 因为这个dll里面调用了另外一个dll里面的方法函数, 那么需要把被调用的那个writedll.dll也复制到同一个目录里去
再次运行, ok了
c++编写的dll中使用多线程
需要用_beginthreadex 和_endthreadex来创建和销毁线程
用上面函数产生的句柄, 并不会自动销毁, 需要最后手动CloseHandle下.
使用上面函数需要引用 process.h 头文件
下面我再dll中声明一个函数, 里面无限循环一个变量进行自加, 另外一个函数用来获取这个变量当前值. C++的代码如下:
#include "stdafx.h" #include "process.h" INT gloablNum = 0; HANDLE hSendThread; UINT WINAPI loopInit(PVOID pM) { while (true) { gloablNum++; Sleep(1000); if (gloablNum>=5000) { break ; } } //必须加,防止内存泄漏 _endthreadex(0); //失败返回0 return 0; } void startInit(void) { //开启并返回句柄 hSendThread = (HANDLE)_beginthreadex(NULL, 0, loopInit, NULL, 0, NULL); } INT getNum(void) { return gloablNum; } void endClose(void) { //手动关闭句柄 CloseHandle(hSendThread); }
于是编译为dll之后, 在aardio中调用:
import console console.open() var dll = raw.loadDll("C:\threadTest\Debug\threadTest.dll",,"cdecl"); startInit = dll.api("startInit","void()" ); getNum = dll.api("getNum","INT()" ); endClose = dll.api("endClose","void()" ); winform.button.oncommand = function(id,event){ startInit(); } winform.button2.oncommand = function(id,event){ console.log(getNum()) } winform.onClose = function(hwnd,message,wParam,lParam){ endClose(); }
多线程中传递参数的方法:
#include "pch.h" #include "process.H" using namespace std; typedef struct touchArg { int touchChannel = 1; bool scc; }touchARG; UINT WINAPI touchloop(PVOID pM) { touchARG* pa = (touchARG*)pM; int touchChannel = pa->touchChannel; if (touchChannel>5) { pa->scc = true; } else { pa->scc = false; } pa->touchChannel = touchChannel; //必须加,防止内存泄漏 _endthreadex(0); //失败返回0 return 0; } // 端面接触 等待完成 bool test(int powerChannel) { touchARG s; s.touchChannel = powerChannel; s.scc = false; HANDLE htouchThread = (HANDLE)_beginthreadex(NULL, 0, touchloop, (LPVOID)&s, 0, NULL); WaitForSingleObject(htouchThread, INFINITE); CloseHandle(htouchThread); return s.scc; }
C++编写dll : 如何生成dll中的回调函数
首先在cpp中声明个函数指针
设置外部函数指针给上面的函数指针
使用刚刚重置后的函数
CPP代码如下:
#include "stdafx.h" int (*fcallback)(int data); void setCallback(int(*Pfcallback)(int data)) { fcallback = Pfcallback; } int getCallback(int data) { int temp = fcallback(data); temp += data; return temp; }
导出文件.def代码如下:
LIBRARY "testCallback" EXPORTS setCallback getCallback
上面把需要外部调用的两个函数给从dll中导出, 供其他软件调用
下面我用aardio来调用这个dll验证一下:
import win.ui; /*DSG{{*/ var winform = win.form(text="aardio form";right=351;bottom=208) winform.add( button={cls="button";text="Button";left=67;top=61;right=275;bottom=136;z=1} ) /*}}*/ import console; var dll = raw.loadDll("/testCallback.dll",,"cdecl"); gCallback = dll.api("getCallback","int(int)" ) scallback = dll.api("setCallback","void(pointer)" ) //声明一个准备给dll重置的函数 var fun = function(data){ var tep = 55; return 55; } //转换为函数指针 var Pfun = raw.tocdecl(fun,"int(int)"); //通过dll导出的这个函数给dll内部重置这个函数 scallback(Pfun); //调用测试下 console.log(gCallback(3)); winform.button.oncommand = function(id,event){ //改变变量再次测试 console.log(gCallback(7)); } winform.show(); win.loopMessage();
符合预期.
那么是不是可以直接把上面生成的Thraddll中多线程函数和CallbackDll联合起来使用呢?
当然也是可以的, 在aardio中示例如下:
aar里将两个dll进行关联, 然后就可以愉快的进行使用了.
import win.ui; /*DSG{{*/ var winform = win.form(text="aardio form";right=507;bottom=346) winform.add( button={cls="button";text="Button";left=300;top=272;right=508;bottom=347;z=1}; button2={cls="button";text="init";left=35;top=142;right=170;bottom=179;z=2}; button3={cls="button";text="read";left=192;top=142;right=327;bottom=179;z=3} ) /*}}*/ import console; console.open() //回调的dll var dll = raw.loadDll("/testCallback.dll",,"cdecl"); gCallback = dll.api("getCallback","int(int)" ) scallback = dll.api("setCallback","void(pointer)" ) //多线程的dll var Testdll = raw.loadDll("/threadTest.dll",,"cdecl"); startInit = Testdll.api("startInit","void()" ); getNum = Testdll.api("getNum","INT()" ); endClose = Testdll.api("endClose","void()" ); //将多线程里面的函数和回调的函数进行关联 scallback(getNum); winform.button.oncommand = function(id,event){ //调用测试一下 console.log(gCallback(7)); } winform.button3.oncommand = function(id,event){ console.log(getNum()) } winform.button2.oncommand = function(id,event){ //初始化多线程dll startInit(); } winform.onClose = function(hwnd,message,wParam,lParam){ endClose(); } winform.show(); win.loopMessage();
登录后方可回帖
用dll函数查看工具查看下刚刚生成的dll ,
这里面的add函数名字加了@@这样的乱七八糟的东西, 为什么?
据说是c++的特性导致, 编译的时候会动态修改函数名....
那么我们可以添加一些限制给编译器, 不让他修改, 在writedll.h头文件里添加
用上面的语句判断下是不是c++环境, 是就执行C格式导出, 其实就是添加了一对大括号
然后,保存, 重新生成dll
再次用dll函数查看器查看函数
现在对应起来了
至于上面的那些看着像是乱码的函数, 嗯... 删除cpp里面的导出类和h文件里面的导出类即可