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

文章目录

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

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

简介

  • 网上有一种使用方式是:利用QTdumpcpp.exe工具对dm.dll处理,生成xxx.hxxx.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工具
  • 启动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+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件_第1张图片

CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件_第2张图片

  • 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.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.hdmutils.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

// 设置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 
#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;
    }
    // 注册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 

#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)

你可能感兴趣的:(C++,CMake,COM,大漠插件,C++,免注册)