[译者]:本文译自 Alex Tilles 在 Windows Developer Network (2003 第12期)发表的一篇文章:“Writing Your Own Install and Uninstall Code”。这是一篇具有一定技术含量的文章,相信许多开发人员都需要本文介绍的技术,其中包括几个重要的技术点:
Rundll32.exe 实用
程序的使用方法;
DLL 或 EXE 的自删除技术;
嵌入资源的处理技巧;
LZCOPY API 使用示范;
compress.exe,expand.exe 使用说明;
摘要
当我在编写“What To Do”程序(这是作者编写的一个应用程序,小巧玲珑,很实用——译者注)时,就想写一个自己的安装和卸载代码,主要目的是想随心所欲地控制整个安装/卸载过程中用户所看到的画面。本文我们就来讨论如何利用自删除的动态
链接库(DLL)实现自删除的可执行程序,从而实现程序的安装/卸载。相信很多朋友在编写 Windows
程序时都想这么做,本文还将展示一些非常有用的相关技术,一定让你大开眼界
实现自删除卸载
程序的难点
编写卸载程序最具挑战性的部分是如何让卸载程序在删除完目标程序文件和相关目录之后自己删除自己。此外,卸载
程序还必须能在所有 Windows 操作系统平台(Windows 9x、Windows NT、Windows 2000、Windows XP..)上运行,不需要用户
下载任何附加组件。我在网上
搜索了一番,找到一些相关的
资料介绍如何自删除可执行程序文件,但是大多数所建议的解决方案都存在一个问题,那就是只能在某个版本的 Windows 上工作。有些方法通过修改线程属性来实现,这样做一般都会导致定时
问题。还有一些方法运行时出现严重错误,根本就不能用。我琢磨着寻求一种更好的解决方法来实现可执行程序的自删除功能:用自删除的 DLL 实现自删除的可执行
程序,从而突破上述诸方法的局限。
实用
程序 rundll32.exe 介绍
从所周知,DLL的代码通常需要先加载到内存之后才能执行,那么如何执行某个DLL导出的代码而不用创建加载和调用该 DLL 的 EXE 文件呢?方法如下:从 Windows 95 开始的每个 Windows 操作系统版本都附带一个系统实用
程序:rundll32.exe。利用它可以象下面这样执行某些 DLL(但不是所有)输出的任何函数:
rundll32.exe DllName,ExportedfnName args
ExportedfnName 是DLL输出的函数名。在编写供 rundll32 使用的 DLL时,可以象下面这样来声明输出函数:
extern "C" __declspec(dllexport) void CALLBACK FunctionName (
HWND hwnd,
HINSTANCE hInstance,
LPTSTR lpCmdLine,
int nCmdShow
)
{ }
rundll32.exe 根据函数参数列表对函数进行调用,但根据经验,实际上用得上的参数值只有一个,那就是 lpCmdLine,该参数接收运行 rundll32.exe 时传入的参数值;__declspec(dllexport)的目的是输出函数;extern "C" 使输出的函数名有修饰符,如:_FunctionName@16 (函数名中被强制包含函数参数的大小,详细信息请参见 MSDN 中有关DLL输出函数调用规范说明)。rundll32.exe 加载指定的 DLL 并调用通过 args 参数传入的 lpCmdLine 的值指定的输出函数。有关 rundll32.exe 的正式文档参见 MSDN 库相关
资料(Q164787):
http://support.microsoft.com/default.
aspx?scid=kb;en-us;164787
实现能自删除的 DLL
下面是实现自删除DLL的示范代码:
#include <windows.h>
HMODULE g_hmodDLL;
extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH)
g_hmodDLL = hinstDLL;
return TRUE;
}
extern "C" __declspec(dllexport) void CALLBACK MagicDel(HWND,
HINSTANCE,
LPTSTR lpCmdLine,
int)
{
// 延时2秒
Sleep(2000);
// 删除创建该进程的可执行文件
DeleteFile(lpCmdLine);
// 删除DLL自己
char