CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件

2024-01-13 02:44

本文主要是介绍CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件
    • 说明
    • 环境
    • 项目结构
    • 配置编译环境
    • 编码-直接调用 dll
    • 编码-生成tlh文件,便于提示

CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件

说明

  • 网上有一种使用方式是:利用QTdumpcpp.exe工具对dm.dll处理,生成xxx.hxxx.cpp文件再使用。
  • 不过我发现这种使用时有些问题,同时生成的文件也不太通用(只能QT用),所以换了另一种方式。
  • 方法参考自 Visual C++免注册调用大漠插件-CSDN博客

环境

版本/规范备注
平台win32操作系统为Windows10
CMake3.27.8CLion自带
C++1711也行
ToolchainVisualStudio 2022只用其工具链,记先安装好
DM7.2353大漠插件
CLion2023.3.2你也可以用其他IDE工具
  • 启动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

image

image.png

  • CMakeLists.txt 文件
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.cppdmutil.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.hdmutils.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// 设置dm.dll的绝对路径;或者配置相对路径,等下将dm.dll拷贝到生成的执行程序旁
// #define DM_LIB_PATH L"C:/Users/xxx/projects/dm/dm_demo/external/dm.dll"
#define DM_LIB_PATH L"./external/dm.dll"using namespace std;/*** 注册dm.dll,获取大漠实例* @return 大漠实例*/
Idmsoft *GetDmObject();/*** 初始化大漠插件,并注册用户VIP* @return 大漠实例*/
Idmsoft *initialDMAndRegVIP();/*** 截图* @param pDm 大漠实例* @param hwnd 窗口句柄*/
void doCaptureWindow(Idmsoft &pDm, long hwnd);#endif //DM_DEMO_X_DMUTIL_H
  • dmutils.cpp
#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;}// 注册dm.dll成功,打印版本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;// long releaseRes = pDm->ReleaseRef();// cout << "===> ReleaseCode = " << releaseRes << 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();
}
  • main.cpp
#include <iostream>#include "dmutil.h"int main() {std::cout << "Hello, World!" << std::endl;Idmsoft *pDm = initialDMAndRegVIP();// 查询标题包含dm的窗口_bstr_t hwnds = pDm->EnumWindow(0, L"dm", L"", 1 + 4 + 8 + 16);std::cout << (char *)hwnds << std::endl;// 对句柄为263684的窗口截图doCaptureWindow(*pDm, 263684);return 0;
}
  • 直接编译运行即可

编码-生成tlh文件,便于提示

  • 前面的方式,虽然能直接调用dll虽然能通过编译和使用,但IDE没有提示,不太方便。
  • 我们可以利用#import生成的 dm.tlhdm.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.tlhdm.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 文件
// #import "file:./external/dm.dll" no_namespace
#include "./cmake-build-debug-visual-studio/CMakeFiles/dm_demo.dir/dm.tlh"
  • 等一会儿,代码中便不再出现红色的警告,并且调用大漠的方法时也有了提示
  • 现在已经可以正常使用了。
  • 不过为了后续方便其他项目使用(不用每次都用#import处理 dm.dll 文件),我们可以将 dm.tlhdm.tli 文件单独拿出来和 dm.dll 放一起,例如
--|external					     # 引入第三方库文件的所在的文件夹
--|--|dm.dll                     # 大漠插件的dll
--|--|dm.tlh
--|--|dm.tli
  • 另外,需要注意的是:生成的 dm.tlh 文件的最后有对 dm.tli 文件的#include,写的是绝对路径,需要我们改成相对路径,方便以后直接一起拿到其他项目使用
//
// Wrapper method implementations
//// #include "C:\Users\xxx\projects\dm\dm_demo\cmake-build-debug-visual-studio\CMakeFiles\dm_demo.dir\dm.tli"
#include ".\dm.tli"#pragma pack(pop)

这篇关于CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/599978

相关文章

Python+PyQt5开发一个Windows电脑启动项管理神器

《Python+PyQt5开发一个Windows电脑启动项管理神器》:本文主要介绍如何使用PyQt5开发一款颜值与功能并存的Windows启动项管理工具,不仅能查看/删除现有启动项,还能智能添加新... 目录开篇:为什么我们需要启动项管理工具功能全景图核心技术解析1. Windows注册表操作2. 启动文件

Python datetime 模块概述及应用场景

《Pythondatetime模块概述及应用场景》Python的datetime模块是标准库中用于处理日期和时间的核心模块,本文给大家介绍Pythondatetime模块概述及应用场景,感兴趣的朋... 目录一、python datetime 模块概述二、datetime 模块核心类解析三、日期时间格式化与

一文带你搞懂Redis Stream的6种消息处理模式

《一文带你搞懂RedisStream的6种消息处理模式》Redis5.0版本引入的Stream数据类型,为Redis生态带来了强大而灵活的消息队列功能,本文将为大家详细介绍RedisStream的6... 目录1. 简单消费模式(Simple Consumption)基本概念核心命令实现示例使用场景优缺点2

Java调用Python的四种方法小结

《Java调用Python的四种方法小结》在现代开发中,结合不同编程语言的优势往往能达到事半功倍的效果,本文将详细介绍四种在Java中调用Python的方法,并推荐一种最常用且实用的方法,希望对大家有... 目录一、在Java类中直接执行python语句二、在Java中直接调用Python脚本三、使用Run

使用Python开发Markdown兼容公式格式转换工具

《使用Python开发Markdown兼容公式格式转换工具》在技术写作中我们经常遇到公式格式问题,例如MathML无法显示,LaTeX格式错乱等,所以本文我们将使用Python开发Markdown兼容... 目录一、工具背景二、环境配置(Windows 10/11)1. 创建conda环境2. 获取XSLT

Python如何调用指定路径的模块

《Python如何调用指定路径的模块》要在Python中调用指定路径的模块,可以使用sys.path.append,importlib.util.spec_from_file_location和exe... 目录一、sys.path.append() 方法1. 方法简介2. 使用示例3. 注意事项二、imp

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

电脑找不到mfc90u.dll文件怎么办? 系统报错mfc90u.dll丢失修复的5种方案

《电脑找不到mfc90u.dll文件怎么办?系统报错mfc90u.dll丢失修复的5种方案》在我们日常使用电脑的过程中,可能会遇到一些软件或系统错误,其中之一就是mfc90u.dll丢失,那么,mf... 在大部分情况下出现我们运行或安装软件,游戏出现提示丢失某些DLL文件或OCX文件的原因可能是原始安装包