文章目录
- CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件
-
- 简介
- 环境
- 项目结构
- 配置编译环境
- 编码-直接调用 dll
- 编码-生成tlh文件,便于提示
CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件
简介
- 网上有一种使用方式是:利用QT的dumpcpp.exe工具对dm.dll处理,生成xxx.h和xxx.cpp文件再使用。
- 不过我发现这种使用时有些问题,同时生成的文件也不太通用(只能QT用),所以换了另一种方式。
- 方法参考自 Visual C++免注册调用大漠插件-CSDN博客
- 在下一篇CMake+QT+大漠插件的桌面应用开发中将会给出利用QT和大漠插件结合开发桌面应用的例子
环境
|
版本/规范 |
备注 |
平台 |
win32 |
操作系统为Windows10 |
CMake |
3.27.8 |
CLion自带 |
C++ |
17 |
11也行 |
Toolchain |
VisualStudio 2022 |
只用其工具链,记先安装好 |
DM |
7.2353 |
大漠插件 |
CLion |
2023.3.2 |
你也可以用其他IDE工具 |
项目结构
- 新建一个项目 dm_demo
- 将下载好的 dm.dll 文件放置到项目的 external 目录下
dm_demo # 项目目录
--|cmake-build-debug-visual-studio # 工程构建目录,存临时生成的文件
--|--|...
--|external # 引入第三方库文件的所在的文件夹
--|--|dm.dll # 大漠插件的dll
--CMakeLists.txt # CMake脚本文件
--dmutil.cpp # 大漠的功能封装工具
--dmutil.h # 大漠的功能封装工具
--main.cpp # 程序入口
配置编译环境
- 配置工具链
- Toolchain: VisualStudio 2022
- Generator: Use default Ninja
cmake_minimum_required(VERSION 3.27)
project(dm_demo)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
add_executable(dm_demo main.cpp
dmutil.cpp dmutil.h
)
target_compile_definitions(${PROJECT_NAME} PRIVATE
-DWIN32
# -D_DEBUG
-D_WINDOWS
-D_UNICODE
-DUNICODE
)
# 拷贝资源文件 dm.dll
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/external DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
编码-直接调用 dll
- 首先,新建文件 dmutils.h 和 dmutils.cpp
- 在 dmutils.h 中使用
#import
导入dll文件
#import "file:./external/dm.dll" no_namespace
- 接下来便可以在文件内编写大漠相关的函数调用代码,如下
- 这种方式能通过编译,以及正常执行生成的程序
- 但是IDE没有提示,会报红。你需要看着大漠插件的文档写调用的方法。
- dmutils.h
#ifndef DM_DEMO_X_DMUTIL_H
#define DM_DEMO_X_DMUTIL_H
#import "file:./external/dm.dll" no_namespace
#define DM_LIB_PATH L"./external/dm.dll"
using namespace std;
Idmsoft *GetDmObject();
Idmsoft *initialDMAndRegVIP();
void doCaptureWindow(Idmsoft &pDm, long hwnd);
#endif
- dmutils.cpp(记得填入自己的 注册码 和 附加码)
#include
#include
#include "dmutil.h"
using namespace std;
Idmsoft *GetDmObject() {
Idmsoft *m_dm = nullptr;
bool m_bInit = false;
typedef HRESULT(_stdcall
*pfnGCO)(REFCLSID, REFIID, void**);
pfnGCO fnGCO = nullptr;
HINSTANCE hdllInst = LoadLibrary(DM_LIB_PATH);
if (hdllInst == nullptr) {
cout << "Load library 'dm.dll' failed ! DM_LIB_PATH = " << DM_LIB_PATH << endl;
return nullptr;
}
fnGCO = (pfnGCO) GetProcAddress(hdllInst, "DllGetClassObject");
if (fnGCO != nullptr) {
IClassFactory *pcf = nullptr;
HRESULT hr = (fnGCO)(__uuidof(dmsoft), IID_IClassFactory, (void **) &pcf);
if (SUCCEEDED(hr) && (pcf != nullptr)) {
hr = pcf->CreateInstance(nullptr, __uuidof(Idmsoft), (void **) &m_dm);
if ((SUCCEEDED(hr) && (m_dm != nullptr)) == FALSE) {
cout << "Create instance 'Idmsoft' failed !" << endl;
return nullptr;
}
}
pcf->Release();
m_bInit = true;
}
return m_dm;
}
Idmsoft *initialDMAndRegVIP() {
Idmsoft *pDm = GetDmObject();
if (pDm == nullptr) {
cout << "===> dm.dll registration failed !" << endl;
return nullptr;
}
cout << "===> DM version: " << (char *) pDm->Ver() << endl;
long regResult = pDm->Reg(L"注册码", L"版本附加信息(附加码)");
if (regResult != 1) {
cout << "===> Account registration failed ! code = " << regResult << endl;
return nullptr;
}
cout << "===> Account registration successful ! " << endl;
return pDm;
}
void doCaptureWindow(Idmsoft &pDm, long hwnd) {
long dmBind = pDm.BindWindowEx(
hwnd,
"normal",
"normal",
"normal",
"",
0
);
if (dmBind == 1) {
pDm.SetWindowState(hwnd, 12);
pDm.SetWindowState(hwnd, 8);
pDm.delay(600);
wstring filename = wstring(L"./capture_window_").append(std::to_wstring(hwnd)).append(L".bmp");
long retCap = pDm.Capture(0, 0, 2000, 2000, filename.c_str());
if (retCap != 1) {
cout << "capture failed" << endl;
} else {
cout << "capture success" << endl;
}
pDm.SetWindowState(hwnd, 9);
} else {
cout << "DM BindWindow failed" << endl;
}
pDm.UnBindWindow();
}
#include
#include "dmutil.h"
int main() {
std::cout << "Hello, World!" << std::endl;
Idmsoft *pDm = initialDMAndRegVIP();
_bstr_t hwnds = pDm->EnumWindow(0, L"dm", L"", 1 + 4 + 8 + 16);
std::cout << (char *)hwnds << std::endl;
doCaptureWindow(*pDm, 263684);
return 0;
}
编码-生成tlh文件,便于提示
- 前面的方式,虽然能直接调用dll虽然能通过编译和使用,但IDE没有提示,不太方便。
- 我们可以利用
#import
生成的 dm.tlh 和 dm.tli文件,便于IDE做提示。
#import "file:./external/dm.dll" no_namespace
- 说明:大漠插件是COM组件
- https://blog.csdn.net/qq_36633275/article/details/108442867
- https://learn.microsoft.com/zh-cn/cpp/preprocessor/hash-import-directive-cpp?view=msvc-170
- https://blog.csdn.net/ghgui008/article/details/9090713
- 在编译后生成的文件中可以找到 dm.tlh 和 dm.tli文件,例如
- 项目目录/cmake-build-debug-visual-studio/CMakeFiles/dm_demo.dir/dm.tlh
- 项目目录/cmake-build-debug-visual-studio/CMakeFiles/dm_demo.dir/dm.tli
- 再注释掉 dmutils.h 中的
#import ./external/dm.dll
,导入 dm.tlh 文件
#include "./cmake-build-debug-visual-studio/CMakeFiles/dm_demo.dir/dm.tlh"
- 等一会儿,代码中便不再出现红色的警告,并且调用大漠的方法时也有了提示
- 现在已经可以正常使用了。
- 不过为了后续方便其他项目使用(不用每次都用
#import
处理 dm.dll 文件),我们可以将 dm.tlh 和 dm.tli 文件单独拿出来和 dm.dll 放一起,例如
--|external # 引入第三方库文件的所在的文件夹
--|--|dm.dll # 大漠插件的dll
--|--|dm.tlh
--|--|dm.tli
- 另外,需要注意的是:生成的 dm.tlh 文件的最后有对 dm.tli 文件的
#include
,写的是绝对路径,需要我们改成相对路径,方便以后直接一起拿到其他项目使用
#include ".\dm.tli"
#pragma pack(pop)