文章目录  
 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)