程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 【技術·水】淺談Dism++清理插件開發,淺談dism

【技術·水】淺談Dism++清理插件開發,淺談dism

編輯:C++入門知識

【技術·水】淺談Dism++清理插件開發,淺談dism



前言

昨天我發布了NCleaner,一款Dism++清理插件(地址:http://bbs.pcbeta.com/viewthread-1692182-1-1.html)

有些人想要我開源NCleaner;我只能說很遺憾,鑒於國內環境,是不可能的。我就說個真實故事吧(其實很悲哀)

曾經,一位大牛寫了一個充滿了黑科技的軟件,在論壇發布並公布了源代碼
某天,那位大牛發現某些人修改他的源代碼用於商業用途,更可氣的是某些人只修改了軟件的名字
最終,那位大牛改掉了他的軟件名,從此再也不公布主程序源代碼
那個軟件就是Dism管理器,即Dism++前身


雖然NCleaner閉源,但是我可以寫一篇Dism++插件開發教程作為補償(笑)

雖然我不能保證該教程寫的多麼生動;但是我會盡力(笑)

Dism++,我只能說這軟件真的是非常強大(這只是我個人看法);至於可靠性,你只要不作死開啟專家模式那就沒問題(笑)

說到Dism++插件開發,其實以前作者提供過SDK(但是很長世間就再也沒提供過);上次和作者談了談我想開發插件的想法(希望作者可以提供SDK);最終如願以償,並發布了NCleaner(用游戲相關話語來說,我也是過了一周目的人)

開發環境

1.  Dism++ 10.1.5.3及以後版本的Dism++(沒有Dism++開發Dism++插件是不可能的)
2. 一個可以編譯dll的C++編譯器,我推薦使用Visual Studio 2015
3. 如果可以的話,最好安裝Windows SDK 10.0.10586


Dism++清理插件相關內容科普

首先說下Dism++清理插件函數定義(參考Dism++幫助文檔.pdf 68頁)

//一個清理插件函數定義
HRESULT WINAPI CleanupPlugin(
_In_ DismSession Session,
  _Reserved_ DWORD Flags,
  _In_opt_ UINT64 *CleanUpSpace,
  _In_ DismCallBack CallBack,
_In_ LPVOID UserData);

DismSession Session
映像會話,可以使用此獲取映像的各種信息(可以看作映像會話的句柄)

DWORD Flags
保留,Dism++現在不使用此參數,請忽略

UINT64 *CleanUpSpace
如果 CleanUpSpace 為空,那麼函數需要執行清理。
如果不為空,說明僅要預估可清理的空間。最後將預估大小用此變量返回

DismCallBack CallBack
Dism++清理回調函數,用於展示進度,文件路徑等信息。
如果此參數為 NULL,則表示沒有回調。
回調函數定義參考下一段介紹

LPVOID UserData
回調函數的 UserData 部分,請務必傳入 CallBack 中。


返回值: 如果函數執行成功,請返回 S_OK,其他任何值都表示錯誤

回調函數定義

typedef DWORD(WINAPI *DismCallBack)(
DWORD dwMessageId,
WPARAM wParam,
LPARAM lParam,
PVOID UserData);


回調函數支持以下消息:

DISM_MSG_PROGRESS – 用於反饋處理進度
wParam =當前完成百分比
lParam = 0

DISM_MSG_PROCESS  – 用於在狀態欄中展示正在處理的文件路徑
wParam = (PWSTR) pszFullPath
lParam = 0

DISM_MGS_RemoveInfo
報告 UI 需要刪除的文件,此消息僅掃描時可用,清理時將無視此消息
wParam = 0
lParam = (LPCWSTR) 需要刪除的文件路徑
Dism++收到此消息後,會將文件路徑展示在詳細信息中。

我經常使用的Dism++ API介紹(希望對其他人有用)


HRESULT WINAPI DismGetSystemInfoBySession(
DismSession Session,
DismSystem** Info);
該API作用是獲取當前映像信息;你會得到DismSystem結構的指針(看Dism++作者對於該結構的說明,我想你們應該都能理解)

HRESULT WINAPI DismFreeMemory(void* pStruct);
切記通過Dism++獲得的結構指針需要用該API釋放

HRESULT WINAPI DismRegOpenKeyEx(
DismSession Session,
HKEY hKey,
LPCWSTR lpSubKey,
REGSAM samDesired,
PHKEY phkResult);
獲取注冊表鍵值,用法類似RegOpenKeyEx

HRESULT WINAPI DismWriteLog(
DWORD LogLevel,
LPCWSTR LogName,
LPCWSTR LogValue);
寫入日志,LogLevel定義如下,LogName是日志類別,LogValue是日志內容
DismLogLevelSilent 不輸出任何信息
DismLogLevelFailure 僅錯誤
DismLogLevelWarning 錯誤和警告
DismLogLevelInformation 錯誤、警告和信息
DismLogLevelDebug 以上所有內容和調試輸出

插件開發注意事項


1. Dism++基於CBS,而CBS是一個COM組件;所以在啟動時會自動進行COM初始化;你不需要在清理插件函數中執行COM初始化;切記不要在清理插件函數中調用COM反初始化,否則後果我和Dism++的作者們都不敢想(當然不敢試)
2. 注意DismSystem結構的RootPath的路徑類似"C:","D:\Image"這樣的(在寫文件操作代碼時需要注意)
3. Dism++的展開環境變量API在離線下會受限
4. Dism++的打開注冊表API不支持打開離線映像的HKEY_USERS(Dism++舊版本支持;只是作者在某個版本移除了);HKEY_CURRENT_USER打開的是Default User的注冊表

插件開發教程


配置好環境,打開Visual Studio;首先新建一個Win32動態鏈接庫項目
接著把Dism++SDK(Dism++目錄\Dism++SDK目錄中的內容)復制到你的項目目錄,並加入你的解決方案

然後你可以在cpp文件中根據前文內容編寫你要編寫的代碼(下面舉個例子)

#include <Windows.h>

#include "Dism++API.h"
#include "Plugin.h"
#ifdef _AMD64_
#pragma comment(lib,"Dism++x64.lib")
#else
#pragma comment(lib,"Dism++x86.lib")
#endif

// Dism++清理插件開發入門
HRESULT WINAPI TestCleanup(
        _In_ DismSession Session,
        _Reserved_ DWORD Flags,
        _In_ UINT64 *CleanUpSpace,
        _In_ DismCallBack CallBack,
        _In_ LPVOID UserData)
{        
        MessageBoxW(nullptr, L"Hello Dism++", L"HelloWorld", MB_ICONINFORMATION);

        return S_OK;
}


順便你需要建立一個def文件導出你的符號(同樣舉個例子)

LIBRARY

EXPORTS
TestCleanup


還有你需要編寫Dism++的插件配置文件(需要命名為Custom.xml,下面舉個例子)

<?xml version="1.0" encoding="utf-8"?>
<Data>
  <CleanCollection4>
    <Item Name="清理項目名" Level="2">
      <Discription>清理項目描述 </Discription>
      <Warning>警告對話框要顯示的內容</Warning>
      <Group>清理項目所屬組</Group>
      <ScanCollection>  
        <Scan Type="Custom">
          <Activate>
            <Custom ProcName="插件dll對應的導出符號"/>
          </Activate>
        </Scan>
      </ScanCollection>
    </Item>
  </CleanCollection4>
</Data>


和Dism++插件信息文件(需要命名為Info.xml)

<?xml version="1.0" encoding="utf-8"?>
<Data>
  <Plugin>
    <Name>插件名稱</Name>
    <Version>填寫插件的版本號,例如1.0.0.0</Version>
  </Plugin>
  <Languages>
    <zh>
      <FriendlyName>插件名稱(中文)</FriendlyName>
      <Decription>插件注釋(中文)</Decription>
    </zh>
    <en>
      <FriendlyName>插件名稱(英文)</FriendlyName>
      <Decription>插件注釋(英文)</Decription>
    </en>
  </Languages>
</Data>


編譯
64位dll需要命名為Plugin.amd64.dll;32位dll需要命名為Plugin.x86.dll

Plugin.amd64.dll , Plugin.x86.dll , Custom.xml , Info.xml這四個文件需要放在一個以 [插件名]_[發布者名稱Base64加密密文;發布者名稱要求16個字符]目錄中,並把該目錄復制入Dism++目錄\Config\Plugin目錄即可

然後開啟Dism++就可以進行調試了(VisualStudio->調試->附加到進程)

Demo項目下載(要求VS2015)
http://pan.baidu.com/s/1o8znY7w


結語

最後我得提醒想開發Dism++清理插件的開發者,雖然插件寫起來是容易的,但要注意的細節是很多(寫本教程時,樓主的體會越發深刻)

如果想獲取更多信息,建議加入Dism++官方群(200783396)討論

毛利

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved