文章目录
CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件 说明 环境 项目结构 配置编译环境 编码-直接调用 dll 编码-生成tlh文件,便于提示
CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件
说明
网上有一种使用方式是:利用QT 的dumpcpp.exe 工具对dm.dll 处理,生成xxx.h 和xxx.cpp 文件再使用。 不过我发现这种使用时有些问题,同时生成的文件也不太通用(只能QT用),所以换了另一种方式。 方法参考自 Visual C++免注册调用大漠插件-CSDN博客
环境
版本/规范 备注 平台 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 使用#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
# include <iostream>
# include <sstream>
# 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 <iostream>
# 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)