在CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件中已经说明了如何免注册调用大漠插件,以及做了几个简单的功能调用(查找窗口、截图) 下面来利用QT做一个简单的窗口查找、截图的桌面工具应用,功能点如下 点击“注册”选项完成大漠插件的注册。 用户在文本框输入窗口标题后,点击“查询”按钮,可对包含该标题的窗口进行查询。 提供表格展示查询到的窗口信息。 点击“截图”按钮,对选中的窗口进行截图并保存。  界面如下 
 
目前主窗口的UI操作和大漠的调用是在一个线程里面的,当大漠调用时间过长时会出现UI界面卡顿的现象,下一篇将会给出如何处理这种问题的示例。 版本/规范 备注 平台 win32 操作系统为Windows10 CMake 3.27.8 CLion自带 C++ 17 Toolchain VisualStudio 2022 只用其工具链,记得先安装好 QT 5.12.12 安装时选择msvc2017,不要64位的 DM 7.2353 CLion 2023.3.2 你也可以用其他IDE工具 
 
 
新建一个项目 qt_dm_demo_x_01 将下载好的 dm.dll  文件以及处理好的 dm.tlh、dm.tli  文件放置到项目的 external  目录下 注:dm.tlh、dm.tli 文件的生成请参考 CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件  qt_dm_demo_x_01					     # 项目目录
--|cmake-build-debug-visual-studio	 # 工程构建目录,存临时生成的文件
--|--|...
--|external					         # 引入第三方库文件的所在的文件夹
--|--|dm.dll                         # 大漠插件的dll
--|--|dm.tlh
--|--|dm.tli
--CMakeLists.txt		             # CMake脚本文件
--dmutil.cpp                         # 大漠的功能封装工具
--dmutil.h                           # 大漠的功能封装工具
--main.cpp					         # 程序入口
--mymainwindow.cpp                   # 主窗口
--mymainwindow.h                     # 主窗口
--mymainwindow.ui                    # 主窗口的UI文件
--strutils.cpp                       # 字符串工具
--strutils.h                         # 字符串工具
配置工具链 和CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件中保持一致即可  CMakeLists.txt 文件 cmake_minimum_required(VERSION 3.27)
project(qt_dm_demo_x_01)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)# QT安装的msvc地址
set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.12/5.12.12/msvc2017")
# 查找QT组件包
find_package(Qt5 COMPONENTSCoreGuiWidgetsREQUIRED)
# 生成可执行文件
add_executable(${PROJECT_NAME} main.cppstrutils.cpp strutils.hdmutil.cpp dmutil.hmymainwindow.cpp mymainwindow.h mymainwindow.ui
)
# 链接需要的QT库
target_link_libraries(${PROJECT_NAME}Qt5::CoreQt5::GuiQt5::Widgets
)target_compile_definitions(${PROJECT_NAME} PRIVATE-DWIN32# -D_DEBUG-D_WINDOWS-D_UNICODE-DUNICODE
)message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
# 拷贝库文件到生成的可执行文件旁边
if (WIN32 AND NOT DEFINED CMAKETOOLCHAIN_FILE)set(DEBUG_SUFFIX)if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")set(DEBUG_SUFFIX "d")endif ()set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")if (NOT EXISTS "${QT_INSTALL_PATH}/bin")set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")if (NOT EXISTS "${QT_INSTALL_PATH}/bin")set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")endif ()endif ()if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E make_directory"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy"${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll""$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")endif ()foreach (QT_LIB Core Gui Widgets)add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy"${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll""$<TARGET_FILE_DIR:${PROJECT_NAME}>")endforeach (QT_LIB)
endif ()# 拷贝资源文件 dm.dll
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/external DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
# ifndef  DM_DEMO_X_DMUTIL_H # define  DM_DEMO_X_DMUTIL_H # include  <string> # include  <vector> # include  "./external/dm.tlh" # define  DM_LIB_PATH  L "./external/dm.dll" ; struct  MyWindow  { long  hwnd; wstring title; long  processId; 
} ; 
Idmsoft * GetDmObject ( ) ; 
Idmsoft * initialDMAndRegVIP ( ) ; 
void  getMatchedWindows ( vector< MyWindow> &  baseVec,  Idmsoft * pDm,  const  wstring&  title,  const  wstring&  processName =  L"" ) ; # endif  dmutil.cpp(记得填入自己的 注册码  和 附加码 ) # include  <iostream> # include  <sstream> # include  <string_view> # include  <vector> # include  "dmutil.h" # include  "strutils.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  getMatchedWindows ( vector< MyWindow> &  baseVec,  Idmsoft * pDm,  const  wstring&  title,  const  wstring&  processName)  { _bstr_t hwnds; if  ( ! processName. empty ( ) )  { hwnds =  pDm-> EnumWindowByProcess ( processName. c_str ( ) ,  title. c_str ( ) ,  L"" ,  1  +  8  +  16 ) ; }  else  { hwnds =  pDm-> EnumWindow ( 0 ,  title. c_str ( ) ,  L"" ,  1  +  4  +  8  +  16 ) ; } string content ( hwnds) ; vector< string_view>  hwndStrVec =  splitSV ( content,  "," ) ; baseVec. reserve ( hwndStrVec. size ( ) ) ; for  ( const  string_view&  element :  hwndStrVec)  { long  curHwnd =  viewToInt ( element) ; const  _bstr_t & curTitle =  pDm-> GetWindowTitle ( curHwnd) ; long  processId =  pDm-> GetWindowProcessId ( curHwnd) ; baseVec. push_back ( { curHwnd,  { curTitle} ,  processId} ) ; } } 
# ifndef  DM_DEMO_X_STRUTILS_H # define  DM_DEMO_X_STRUTILS_H # include  <string> # include  <string_view> # include  <iostream> # include  <vector> ; 
vector< string_view>  splitSV ( string_view content,  string_view delim =  " " ) ; 
int  viewToInt ( string_view content) ; # endif  # include  <sstream> # include  <string> # include  <vector> # include  <charconv> # include  "strutils.h" < string_view>  splitSV ( string_view content,  string_view delim)  { vector< string_view>  output; size_t first =  0 ; while  ( first <  content. size ( ) )  { const  auto  second =  content. find_first_of ( delim,  first) ; if  ( first !=  second) output. emplace_back ( content. substr ( first,  second -  first) ) ; if  ( second ==  string_view:: npos) break ; first =  second +  1 ; } return  output; 
} int  viewToInt ( string_view content)  { int  num; auto  result =  std:: from_chars ( content. data ( ) ,  content. data ( )  +  content. size ( ) ,  num) ; if  ( result. ec ==  std:: errc:: invalid_argument)  { throw  std:: runtime_error ( "Could not convert." ) ; } return  num; 
} <?xml version="1.0" encoding="UTF-8"?> 
< uiversion = " 4.0" > < class> </ class> < widgetclass = " QMainWindow" name = " MyMainWindow" > < propertyname = " geometry" > < rect> < x> </ x> < y> </ y> < width> </ width> < height> </ height> </ rect> </ property> < propertyname = " windowTitle" > < string> </ string> </ property> < widgetclass = " QWidget" name = " centralwidget" > < layoutclass = " QVBoxLayout" name = " verticalLayout" > < item> < layoutclass = " QHBoxLayout" name = " horizontalLayout" > < item> < spacername = " horizontalSpacer" > < propertyname = " orientation" > < enum> </ enum> </ property> < propertyname = " sizeHint" stdset = " 0" > < size> < width> </ width> < height> </ height> </ size> </ property> </ spacer> </ item> < item> < widgetclass = " QLabel" name = " label" > < propertyname = " font" > < font> < weight> </ weight> < bold> </ bold> </ font> </ property> < propertyname = " text" > < string> </ string> </ property> </ widget> </ item> < item> < widgetclass = " QLineEdit" name = " edtTitle" > < propertyname = " minimumSize" > < size> < width> </ width> < height> </ height> </ size> </ property> </ widget> </ item> < item> < widgetclass = " QPushButton" name = " btnQuery" > < propertyname = " text" > < string> </ string> </ property> </ widget> </ item> < item> < spacername = " horizontalSpacer_3" > < propertyname = " orientation" > < enum> </ enum> </ property> < propertyname = " sizeHint" stdset = " 0" > < size> < width> </ width> < height> </ height> </ size> </ property> </ spacer> </ item> < item> < widgetclass = " QPushButton" name = " btnCapture" > < propertyname = " text" > < string> </ string> </ property> </ widget> </ item> < item> < spacername = " horizontalSpacer_2" > < propertyname = " orientation" > < enum> </ enum> </ property> < propertyname = " sizeHint" stdset = " 0" > < size> < width> </ width> < height> </ height> </ size> </ property> </ spacer> </ item> </ layout> </ item> < item> < widgetclass = " QTableWidget" name = " tableWidget" /> </ item> </ layout> </ widget> < widgetclass = " QMenuBar" name = " menubar" > < propertyname = " geometry" > < rect> < x> </ x> < y> </ y> < width> </ width> < height> </ height> </ rect> </ property> < widgetclass = " QMenu" name = " menuOperation" > < propertyname = " title" > < string> </ string> </ property> < addactionname = " actionReg" /> </ widget> < addactionname = " menuOperation" /> </ widget> < widgetclass = " QStatusBar" name = " statusbar" /> < actionname = " actionReg" > < propertyname = " text" > < string> </ string> </ property> </ action> </ widget> < resources/> < connections/> </ ui> # ifndef  QT_DM_DEMO_X_MYMAINWINDOW_H # define  QT_DM_DEMO_X_MYMAINWINDOW_H # include  <QMainWindow> # include  "dmutil.h" {  class MyMainWindow;  } 
QT_END_NAMESPACEclass MyMainWindow :  public QMainWindow { 
Q_OBJECT
public: explicit MyMainWindow ( QWidget * parent =  nullptr) ; ~ MyMainWindow ( )  override; public: void  showInfo ( const  QString & message,  const  QString & title =  "提示" ) ; void  showWarn ( const  QString & message,  const  QString & title =  "告警" ) ; void  doRegDM ( Idmsoft * * pDm) ; void  doFindWindow ( Idmsoft * pDm,  const  QString & title) ; void  doCaptureWindow ( Idmsoft * pDm,  long  hwnd) ; public slots: void  showMessageBox ( bool result,  const  QString & message) ; void  showTableView ( bool result,  const  QString & msg,  const  vector< MyWindow>  & windowVec) ; private: Ui:: MyMainWindow * ui; Idmsoft * pCommonDm =  nullptr; 
} ; # endif  
# include  <QFont> # include  <QHeaderView> # include  <QMessageBox> # include  <QPushButton> # include  <QAction> # include  <QString> # include  <QTableWidgetItem> # include  <QObject> # include  <QVector> # include  <iostream> # include  "mymainwindow.h" # include  "ui_MyMainWindow.h" using  namespace  std; MyMainWindow :: MyMainWindow ( QWidget * parent)  : QMainWindow ( parent) ,  ui ( new  Ui:: MyMainWindow)  { ui-> setupUi ( this ) ; setFixedSize ( 1280 ,  720 ) ; ui-> tableWidget-> setColumnCount ( 3 ) ; ui-> tableWidget-> setHorizontalHeaderLabels ( QStringList ( )  <<  "进程ID"  <<  "句柄"  <<  "标题" ) ; ui-> tableWidget-> horizontalHeader ( ) -> setStretchLastSection ( true ) ;  ui-> tableWidget-> horizontalHeader ( ) -> setHighlightSections ( false ) ; ui-> tableWidget-> horizontalHeader ( ) -> setStyleSheet ( "QHeaderView::section{background:gray;}" ) ; ui-> tableWidget-> setSelectionMode ( QAbstractItemView:: SingleSelection) ; QFont font =  ui-> tableWidget-> horizontalHeader ( ) -> font ( ) ; font. setBold ( true ) ; ui-> tableWidget-> horizontalHeader ( ) -> setFont ( font) ; ui-> tableWidget-> setStyleSheet ( "QTableWidget::item:hover { background-color: lightblue; }" ) ; ui-> tableWidget-> setEditTriggers ( QAbstractItemView:: NoEditTriggers) ;  ui-> tableWidget-> setSelectionBehavior ( QAbstractItemView:: SelectRows) ;  connect ( ui-> actionReg,  & QAction:: triggered,  [ this ] ( )  { ui-> actionReg-> setEnabled ( false ) ; this -> doRegDM ( & this -> pCommonDm) ; ui-> actionReg-> setEnabled ( true ) ; } ) ; connect ( ui-> btnQuery,  & QPushButton:: clicked,  [ this ] ( )  { ui-> btnQuery-> setEnabled ( false ) ; this -> doFindWindow ( this -> pCommonDm,  ui-> edtTitle-> text ( ) ) ; ui-> btnQuery-> setEnabled ( true ) ; } ) ; connect ( ui-> btnCapture,  & QPushButton:: clicked,  [ this ] ( )  { ui-> btnCapture-> setEnabled ( false ) ; const  QList< QTableWidgetItem * >  & selectedItems =  ui-> tableWidget-> selectedItems ( ) ; if  ( selectedItems. size ( )  >=  2 )  { QTableWidgetItem * item =  selectedItems. at ( 1 ) ; const  QString & hwnd =  item-> data ( Qt:: DisplayRole) . toString ( ) ; bool  res =  false ; long  hwndL =  hwnd. toLong ( & res,  0 ) ; cout <<  res <<  endl; if  ( res)  { this -> doCaptureWindow ( this -> pCommonDm,  hwndL) ; }  else  { this -> showWarn ( "选中行的窗口句柄解析异常!" ) ; } }  else  { this -> showWarn ( "请选中列表中的其中一行!" ) ; } ui-> btnCapture-> setEnabled ( true ) ; } ) ; } MyMainWindow :: ~ MyMainWindow ( )  { delete  ui; 
} void  MyMainWindow :: showInfo ( const  QString & message,  const  QString & title)  { QMessageBox :: information ( this ,  title,  message) ; 
} void  MyMainWindow :: showWarn ( const  QString & message,  const  QString & title)  { QMessageBox :: critical ( this ,  title,  message) ; 
} void  MyMainWindow :: showMessageBox ( const  bool  result,  const  QString&  message)  { if  ( result)  { this -> showInfo ( message) ; }  else  { this -> showWarn ( message) ; } 
} void  MyMainWindow :: showTableView ( bool  result,  const  QString & msg,  const  vector< MyWindow>  & windowVec)  { if  ( result)  { auto  rowNum =  windowVec. size ( ) ; ui-> tableWidget-> setRowCount ( rowNum) ; for  ( int  i =  0 ;  i <  rowNum;  ++ i)  { const  MyWindow & item =  windowVec[ i] ; ui-> tableWidget-> setItem ( i,  0 ,  new  QTableWidgetItem ( QString :: number ( item. processId) ) ) ; ui-> tableWidget-> setItem ( i,  1 ,  new  QTableWidgetItem ( QString :: number ( item. hwnd) ) ) ; ui-> tableWidget-> setItem ( i,  2 ,  new  QTableWidgetItem ( QString :: fromStdWString ( item. title) ) ) ; } }  else  { this -> showWarn ( msg) ; } 
} void  MyMainWindow :: doRegDM ( Idmsoft * * pDm)  { cout <<  "========== Initial DM ............ =========="  <<  endl; * pDm =  initialDMAndRegVIP ( ) ; if  ( * pDm ==  nullptr )  { cout <<  "========== Initial DM <Failed>     =========="  <<  endl; showMessageBox ( false ,  "DM 注册失败!" ) ; return ; } cout <<  "========== Initial DM <Successful> =========="  <<  endl; cout <<  endl; showMessageBox ( true ,  "DM 注册完成!" ) ; 
} void  MyMainWindow :: doFindWindow ( Idmsoft * pDm,  const  QString & title)  { vector< MyWindow>  windowVec; if  ( pDm ==  nullptr )  { cout <<  "this->pCommonDm == nullptr"  <<  endl; this -> showTableView ( false ,  "请先在菜单中完成注册!" ,  windowVec) ; return ; } getMatchedWindows ( windowVec,  pDm,  title. toStdWString ( ) ) ; if  ( windowVec. empty ( ) )  { cout <<  "can not find such window"  <<  endl; this -> showTableView ( false ,  "没有找到包含该标题的窗口!" ,  windowVec) ; return ; } this -> showTableView ( true ,  "成功!" ,  windowVec) ; 
} void  MyMainWindow :: doCaptureWindow ( Idmsoft * pDm,  long  hwnd)  { if  ( pDm ==  nullptr )  { cout <<  "this->pCommonDm == nullptr"  <<  endl; this -> showMessageBox ( false ,  "请先在菜单中完成注册!" ) ; return ; } 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; this -> showMessageBox ( false ,  "截图失败!" ) ; }  else  { cout <<  "capture success"  <<  endl; this -> showMessageBox ( true ,  QString :: fromStdWString ( L"截图成功,保存地址为: "  +  filename) ) ; } pDm-> SetWindowState ( hwnd,  9 ) ; }  else  { cout <<  "DM BindWindow failed"  <<  endl; this -> showMessageBox ( false ,  "绑定窗口异常!" ) ; } pDm-> UnBindWindow ( ) ; 
} 
# include  <QApplication> # include  <iostream> # include  "mymainwindow.h" using  namespace  std; int  main ( int  argc,  char  * argv[ ] )  { setlocale ( LC_ALL,  "chs" ) ; QApplication a ( argc,  argv) ; MyMainWindow mainWindow; mainWindow. show ( ) ; return  QApplication :: exec ( ) ; 
}