📄 用自删除dll实现应用程序的安装.htm
字号:
WriteFile(hFile, pvRes, cbRes, &cbWritten, 0); <br>
CloseHandle(hFile); <br>
} <br>
<br>
void SelfDelete(HINSTANCE hInstance) <br>
{ <br>
WriteResourceToFile(hInstance, ID_MAGICDEL_DLL, "magicdel.dll"); <br>
<br>
// </span>生成命令行<span lang=EN-US> <br>
// 1. </span>查找<span lang=EN-US> rundll32.exe <br>
char commandLine[MAX_PATH * 3]; <br>
GetWindowsDirectory(commandLine, sizeof(commandLine)); <br>
lstrcat(commandLine, "\\rundll32.exe"); <br>
if (GetFileAttributes(commandLine) == INVALID_FILE_ATTRIBUTES) <br>
{ <br>
GetSystemDirectory(commandLine, sizeof(commandLine)); <br>
lstrcat(commandLine, "\\rundll32.exe"); <br>
} <br>
// 2. </span>添加<span lang=EN-US> rundll32.exe </span>参数<span lang=EN-US> <br>
lstrcat(commandLine, " magicdel.dll,_MagicDel@16 "); <br>
// 3. </span>添加本文件名<span lang=EN-US> <br>
char thisName[MAX_PATH]; <br>
GetModuleFileName(hInstance, thisName, sizeof(thisName)); <br>
lstrcat(commandLine, thisName); <br>
// </span>执行命令行<span lang=EN-US> <br>
PROCESS_INFORMATION procInfo; <br>
STARTUPINFO startInfo; <br>
memset(&startInfo, 0, sizeof(startInfo)); <br>
startInfo.dwFlags = STARTF_FORCEOFFFEEDBACK; <br>
CreateProcess(0, commandLine, 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, 0, <br>
&startInfo, &procInfo); <br>
} <br>
<br>
int WINAPI WinMain(HINSTANCE hInstance, <br>
HINSTANCE hPrevInstance, <br>
LPSTR lpCmdLine, <br>
int nCmdShow) <br>
{ <br>
SelfDelete(hInstance); <br>
} <br>
</span> <span lang=EN-US> WriteResourceToFile </span>的功能是存取二进制资源,以便能在磁盘中重建<span
lang=EN-US> DLL</span>。<span lang=EN-US>Windows </span>资源<span lang=EN-US>
API </span>提供了一个指向原始数据的指针。<span lang=EN-US> <br>
SelfDelete </span>的作用是重新创建<span lang=EN-US>DLL</span>并生成如下命令行启动<span
lang=EN-US> rundll32.exe</span>:<span lang=EN-US> path\rundll32.exe
magicdel.dll,_MagicDel@16 path\executableName <br>
</span> <span lang=EN-US> rundll32.exe </span>位于<span lang=EN-US> Windows </span>目录或者<span
lang=EN-US> System </span>目录中,所以<span lang=EN-US> SelfDelete </span>检查它的位置是否正确。当<span
lang=EN-US> CreateProcess </span>被调用执行命令行时,必须设置<span lang=EN-US> <br>
STARTF_FORCE-OFFFEEDBACK </span>标志以防止<span lang=EN-US> Windows </span>在运行<span
lang=EN-US> rundll32.exe </span>时显示表示忙的沙漏或光标。这样做以后用户不会感觉到有新的进程正在运行。在这个新进程退出之后,<span
lang=EN-US>DLL </span>和原来的可执行文件都不见了。<span lang=EN-US> <br>
</span> 为了让自删除的可执行程序不依赖于<span lang=EN-US> C </span>运行时<span lang=EN-US>DLL</span>,可执行程序必须静态链接到运行时库代码。为此修改项目编译选项即可:<span
lang=EN-US> <br>
</span>项目(<span lang=EN-US>P</span>)<span lang=EN-US>| [</span>项目名称<span
lang=EN-US>] </span>属性(<span lang=EN-US>P</span>)<span lang=EN-US>... | C/C |
</span>代码生成<span lang=EN-US> | </span>运行时库:<span lang=EN-US>[</span>单线程(<span
lang=EN-US>/ML</span>)<span lang=EN-US>] </span>或者<span lang=EN-US> [</span>多线程(<span
lang=EN-US>/MT</span>)<span lang=EN-US>]</span>(或者任何不包含此<span lang=EN-US>DLL</span>的选项值)<span
lang=EN-US> <br>
</span> 此自删除技术在所有<span lang=EN-US> Windows </span>版本中都工作得很稳定。在实际运用中,卸载程序首先将自己的拷贝放到<span
lang=EN-US> Windows </span>临时(<span lang=EN-US>Temp</span>)目录,以便能删除所有程序文件和相关目录,最后它用自删除的<span
lang=EN-US> DLL </span>把自己删掉。<span lang=EN-US> <br>
<br>
*</span>编写安装程序<span lang=EN-US> <br>
</span> 确定了安装程序要做些什么事情之后,接着是制作安装程序。现在很多的安装程序都是由用户从<span lang=EN-US>Internet</span>上下载,然后在本地运行。那么下载的文件体积越小越好,为此最有效的方法是对文件进行压缩处理。如何让用户最先看到的画面是我的程序画面而不是其它公司的安装程序画面呢,好在<span
lang=EN-US>Windows</span>提供了这样的支持。<span lang=EN-US> <br>
</span> 首先创建一个交互式的<span lang=EN-US> Setup </span>程序,它显示软件许可协议,提示用户安装选项,拷贝文件,然后进行其余的设置工作。然后将<span
lang=EN-US> Setup </span>程序的压缩版本作为资源保存在安装程序(<span lang=EN-US>installer</span>)中。这个安装程序要做的只是将<span
lang=EN-US> Setup </span>程序二进制资源重建后写回磁盘,解压缩,然后用一个新进程启动它。保存和读写二进制资源并不难<span
lang=EN-US>——</span>本文前面已经描述了处理细节和代码。<span lang=EN-US> <br>
</span> 自从<span lang=EN-US> Windows 95 </span>开始的每个<span lang=EN-US>
Windows </span>平台都带一组解压缩文件的<span lang=EN-US> API——LZCopy</span>。下面是安装程序使用这个<span
lang=EN-US> API </span>的示例代码:<span lang=EN-US> / install.h <br>
// <br>
#define RC_BINARYTYPE 256 <br>
#define ID_COMPRESSED_SETUP 100 <br>
// <br>
// install.rc <br>
// <br>
#include "install.h" <br>
ID_COMPRESSED_SETUP RC_BINARYTYPE AppSetup.ex_ <br>
// <br>
// install.cpp <br>
// <br>
#include <windows.h> <br>
#include "install.h" <br>
void WriteResourceToFile(HINSTANCE hInstance, <br>
int idResource, <br>
char const *filename) <br>
{ <br>
// </span>参见前述代码<span lang=EN-US> <br>
} <br>
void DecompressFile(char const *source, char const *dest) <br>
{ <br>
OFSTRUCT ofs; <br>
ofs.cBytes = sizeof(ofs); <br>
int zhfSource = LZOpenFile(const_cast<char *>(source), &ofs,
OF_READ); <br>
int zhfDest = LZOpenFile(const_cast<char *>(dest), &ofs, <br>
OF_CREATE | OF_WRITE); <br>
LZCopy(zhfSource, zhfDest); <br>
LZClose(zhfSource); <br>
LZClose(zhfDest); <br>
} <br>
int WINAPI WinMain(HINSTANCE hInstance, <br>
HINSTANCE hPrevInstance, <br>
LPSTR lpCmdLine, int nCmdShow) <br>
{ <br>
WriteResourceToFile(hInstance, ID_COMPRESSED_SETUP,
"AppSetup.ex_"); <br>
DecompressFile("AppSetup.ex_", "AppSetup.exe"); <br>
DeleteFile("AppSetup.ex_"); <br>
<br>
// </span>启动<span lang=EN-US> AppSetup.exe <br>
PROCESS_INFORMATION procInfo; <br>
STARTUPINFO startInfo; <br>
memset(&startInfo, 0, sizeof(startInfo)); <br>
CreateProcess(0, "AppSetup.exe", 0, 0, FALSE,
NORMAL_PRIORITY_CLASS, 0, 0, <br>
&startInfo, &procInfo); <br>
} <br>
</span> 从代码中可以看到压缩的<span lang=EN-US> Setup </span>程序是如何作为安装程序的资源保存的。按照本文前面讨论的思路。<span
lang=EN-US>DecompressFile </span>函数示范了<span lang=EN-US> LZCopy API </span>的使用方法。安装程序重新创建<span
lang=EN-US> AppSetup.exe</span>,然后运行它。为了顺利编译和生成安装程序,需要将<span lang=EN-US> lz32.lib
</span>添加到项目的编译选项中,通常这个文件在<span lang=EN-US> Visual Studio </span>的安装目录中,如:<span
lang=EN-US>Visual Studio .NET 2003: <br>
C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Lib <br>
<br>
Visual C 6.0: <br>
C:\Program Files\Microsoft Visual Studio\VC98\Lib <br>
</span>在<span lang=EN-US> Visual Studio.NET </span>中的添加方法是:<span lang=EN-US> <br>
</span>项目(<span lang=EN-US>P</span>)<span lang=EN-US>| [</span>项目名称<span
lang=EN-US>] </span>属性(<span lang=EN-US>P</span>)<span lang=EN-US>... | </span>链接器<span
lang=EN-US> | </span>附加库目录:<span lang=EN-US>[</span>添加上述路径之一<span lang=EN-US>]
<br>
<br>
</span> 此外,为了摆脱对<span lang=EN-US> C</span>运行时<span lang=EN-US>DLL</span>的依赖,必须用静态链接到运行库代码:<span
lang=EN-US> <br>
</span>项目(<span lang=EN-US>P</span>)<span lang=EN-US>| [</span>项目名称<span
lang=EN-US>] </span>属性(<span lang=EN-US>P</span>)<span lang=EN-US>... | C/C |
</span>代码生成<span lang=EN-US> | </span>运行时库:<span lang=EN-US>[</span>单线程(<span
lang=EN-US>/ML</span>)<span lang=EN-US>] </span>或者<span lang=EN-US> [</span>多线程(<span
lang=EN-US>/MT</span>)<span lang=EN-US>]</span>(或者任何不包含此<span lang=EN-US>DLL</span>的选项值)<span
lang=EN-US> <br>
<br>
</span> 注意这里安装程序不必等待<span lang=EN-US> Setup </span>程序完成工作,因为<span
lang=EN-US> AppSetup.exe </span>可以在完成工作后用自删除<span lang=EN-US> DLL </span>来进行自我删除。<span
lang=EN-US> <br>
</span> 使用<span lang=EN-US> LZCopy API </span>最具技巧性的部分是它只能解压缩由<span
lang=EN-US> compress.exe </span>压缩的文件。<span lang=EN-US>compress.exe</span>是微软公司的一款压缩文件命令行实用程序,它随<span
lang=EN-US> SDK </span>一起提供。也可以在微软的官方<span lang=EN-US>FPT</span>站点下载:<span
lang=EN-US>ftp://ftp.microsoft.com/softlib/mslfiles/CP0982.EXE</span>。运行<span
lang=EN-US>EXE</span>后会有几个解包文件,其中包括<span lang=EN-US> compress.exe</span>,其它的文件可以忽略或删除。<span
lang=EN-US>compress.exe </span>的使用方法如下:<span lang=EN-US> compress SourceName
DestinationName <br>
</span> 所有<span lang=EN-US> Windows </span>版本都内建了解压缩支持,利用它很容易编写安装程序。此外,所有<span
lang=EN-US> Windows </span>版本也都包含了另一个实用程序:<span lang=EN-US>expand.exe</span>。用它可以在命令行进行解压缩处理。<span
lang=EN-US> <br>
<br>
*</span>总结<span lang=EN-US> <br>
</span> 借助自删除<span lang=EN-US> DLL</span>,二进制资源以及<span lang=EN-US> Windows </span>内建的解压缩支持可以创建自己的安装程序和卸载程序,从而轻松控制用户安装和卸载程序时屏幕的每一个方面<span
lang=EN-US>....<o:p></o:p></span></span></p>
</td>
<td style='padding:0cm 0cm 0cm 0cm'>
<p class=MsoNormal align=left style='text-align:left;mso-pagination:widow-orphan'><span
lang=EN-US style='font-size:10.0pt;mso-font-kerning:0pt'><o:p> </o:p></span></p>
</td>
<td style='padding:0cm 0cm 0cm 0cm'>
<p class=MsoNormal align=left style='text-align:left;mso-pagination:widow-orphan'><span
lang=EN-US style='font-size:10.0pt;mso-font-kerning:0pt'><o:p> </o:p></span></p>
</td>
</tr>
</table>
</div>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
</div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -