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头文件里添加
#ifdef __cplusplus extern "C" { #endif //你原来的导出函数 #ifdef __cplusplus } #endif用上面的语句判断下是不是c++环境, 是就执行C格式导出, 其实就是添加了一对大括号
extern "C" { //你原来的导出函数 }然后,保存, 重新生成dll
再次用dll函数查看器查看函数
现在对应起来了
至于上面的那些看着像是乱码的函数, 嗯... 删除cpp里面的导出类和h文件里面的导出类即可