前言

昨天我发布了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的注册表

5. 只有返回S_OK,才代表Dism++ API正确执行

插件开发教程

配置好环境,打开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)讨论

毛利

【技术·水】浅谈Dism++清理插件开发的更多相关文章

  1. 技术分析 | 浅谈在MySQL体系下SQL语句是如何在系统中执行的及可能遇到的问题

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 SQL语句大家并不陌生,但某种程度上来看,我们只是知道了这条语句是什么功能,它可 ...

  2. 技术分享 | 浅谈mysql语法解析调试方法

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 本文向您介绍一种利用mysql解析器和bison的调试选项进行sql语法解析跟踪 ...

  3. 技术分享 | 浅谈MySQL闪回的实现

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 1.闪回实现原理 2.binlog文件格式初探 3.闪回实现过程 1.闪回实现原 ...

  4. 防止apk反编译的技术分析浅谈--内存修改器篇

    声明: 1.本帖转载自http://jingyan.baidu.com/article/a24b33cd509eb719fe002b94.html,仅供自用,勿喷 Apk反编译修改器有很多.拿其中的比 ...

  5. 视频基础知识:浅谈视频会议中H.264编码标准的技术发展

    浅谈视频会议中H.264编码标准的技术发展 浅谈视频会议中H.264编码标准的技术发展 数字视频技术广泛应用于通信.计算机.广播电视等领域,带来了会议电视.可视电话及数字电视.媒体存储等一系列应用,促 ...

  6. 搞懂分布式技术21:浅谈分布式消息技术 Kafka

    搞懂分布式技术21:浅谈分布式消息技术 Kafka 浅谈分布式消息技术 Kafka 本文主要介绍了这几部分内容: 1基本介绍和架构概览 2kafka事务传输的特点 3kafka的消息存储格式:topi ...

  7. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  8. 浅谈Hybrid技术的设计与实现

    前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 随着移动浪潮的兴起,各种APP层出不穷,极速的业务扩展提升了团队对开发 ...

  9. (转)浅谈Hybrid技术的设计与实现

    转载地址:https://www.cnblogs.com/yexiaochai/p/4921635.html 前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hyb ...

随机推荐

  1. PC-破解RAR软件注册问题

    打开RAR文件提示软件注册 压缩软件WinRAR并不是免费软件,用了40天后,每次解压文件时都会弹出一提示,问你是否购买(但不影响功能),下面说下最新版的WinRAR v3.71(现在有更新版了,一样 ...

  2. android 获取当前版本号/修改自定义的应用程序的版本号

    1.获取当前版本号 PackageManager pm = getPackageManager(); PackageInfo pi = pm.getPackageInfo(getPackageName ...

  3. [二]poi实践一

    1.创建时间格式的cell 2.创建不同格式的cell(字符串.布尔.数值) 3.读取遍历xls文件 4.抽取excel的内容

  4. 音频播放(iOS开发)

    音频处理 一.录音 录音应用场景 语音聊天 即时通讯软件中,都包含语音发送功能 语音备忘录 录一段音频,来记录某件事情 录音功能实现 导入AVFoundation框架 作用:一些多媒体的处理,基本上都 ...

  5. Redis与MySQL的结合

    Redis与MySQL的结合 目前大部分互联网公司使用MySQL作为数据的主要持久化存储,那么如何让Redis与MySQL很好的结合在一起呢?我们主要使用了一种基于MySQL作为主库,Redis作为高 ...

  6. 为一张PCI卡打通经络的过程

    一张PCI卡通过“一转二”的转接卡插在主板上,probe调用失败,日志显示读取配置空间的时候发生了奇偶校验错误,可是使用相同的转接卡把它插在另外一台相同机器的主板上时,却运行正常,这就说明不是转接卡的 ...

  7. cocos2dx jsb 在IOS与安卓下的一些不同之处

    cocos2dx版本 2.1.4 1:字体大小 cocosbuilder publish后应该注意IOS和安卓目录下的字体文件的规格是否齐全: 2:cc.LabelTTF 在ios下,cc.Label ...

  8. android113 自定义进度条

    MainActivity: package com.itheima.monitor; import android.os.Bundle; import android.app.Activity; im ...

  9. iostat详解

    http://www.penglixun.com/tech/system/use_iostat_analyse_linux_disks.html

  10. Cookie中的三个容器request,session,application的设置和获取

    public class SaveServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpSer ...