用自删除dll实现应用程序的安装/卸载代码

c++ 文件自删除 程序自删除 文件自删除一般用于卸载程序 实现:设置本进程为实时执行,快速退出。调用cmd传入参数以删除自己。 立即下载
 

[译者]:本文译自 Alex Tilles 在 Windows Developer Network (2003 第12期)发表的一篇文章:“Writing Your Own Install and Uninstall Code”。这是一篇具有一定技术含量的文章,相信许多开发人员都需要本文介绍的技术,其中包括几个重要的技术点:

  1. Rundll32.exe 实用程序的使用方法;
  2. DLL 或 EXE 的自删除技术;
  3. 嵌入资源的处理技巧;
  4. LZCOPY API 使用示范;
  5. 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 filenameDLL[MAX_PATH];
	GetModuleFileName(g_hmodDLL, filenameDLL, sizeof(filenameDLL));

	__asm
	{
		lea eax, filenameDLL
		push 0
		push 0
		push eax
		push ExitProcess
		push g_hmodDLL
		push DeleteFile
		push FreeLibrary
		ret
	}
}      
  上面这段代码首先删除某个文件,然后自删除。DllMain 是DLL的入口函数,当首次加载动态链接库时该函数被调用,此时将模块句柄赋值给全局变量 g_hmodDLL,以便梢后使用它来获取 DLL 本身的文件名。在 MagicDel 函数中,lpCmdLine 是DLL要删除的可执行文件的名称(如:卸载程序的文件名)。要删除它很容易——用 Sleep 做一个延时,以便可执行程序的进程有时间退出并调用 DeleteFile。为了掌握 MagicDel 的实现细节,你可以将可执行程序的进程句柄传给MagicDel并在调用 DeleteFile 之前做一个等待,看看会发生什么?
  要让 DLL 进行自删除需要一点诀窍。rundll32 调用 LoadModule 将 DLL 加载到它的地址空间。如果 DLL 函数可以返回的话,rundll32 将会退出,从而导致 DLL 被释放(不是被删除)。为了解决这个问题,我们可以执行下面的代码:
      FreeLibrary(DLL module handle);
      DeleteFile(DLL filename);
      ExitProcess(0);      
  MagicDel 函数是不能按这样的顺序进行直接调用的,因为 FreeLibary 会使代码页无效。为此, MagicDel 采用将等效的汇编指令压入堆栈,然后执行它们,后跟一个 ret 指令,最后调用 ExitProccess 以防止进程继续往下执行。我参考 Gary Nebbit 在 Windows 开发杂志(WDJ)“ Tech Tips”栏目发表的文章编写了一个汇编代码块。如果你用 Visual Studio 以默认选项生成DLL,最终的二进制文件大约为 40K。由于我们打算将 DLL 作为可执行程序的资源,它的体积越小越好,为此,我们必须对它进行瘦身处理。思路是将无用的 C 运行时代码从DLL中删除掉,具体方法如下:
  1. 本文例子使用 Visual Studio.NET 2003 中文版编译生成 DLL,先设置项目的编译/链接选项:
    项目(P)| [项目名称] 属性(P)... | 链接器 | 输入 | 忽略所有默认库:是(/NODEFAULTLIB),此设置将 /NODEFAULTLIB 选项传给链接器以便过滤掉运行时代码。
  2. 由于 DLL 入口点(Entry Point)通常是由运行时库提供(默认为 DllMain),所以完成上述第一步设置之后,还必须显式地将 DLL入口点设置为 DllMain:
    项目(P)| [项目名称] 属性(P)... | 链接器 | 高级 | 入口点:DllMain。
    如果此时编译生成 DLL,编译器会报如下两个 无法解析的外部符号( unresolved externals ) 错误:
    error LNK2019: 无法解析的外部符号 ___security_cookie ,该符号在函数 _MagicDel@16 中被引用
    error LNK2019: 无法解析的外部符号 @__security_check_cookie@4 ,该符号在函数 _MagicDel@16 中被引用
    解决方法是进行下一步设置。

  3. 项目(P)| [项目名称] 属性(P)... | C/C++ | 代码生成 | 缓冲区安全检查:否,
    该设置不会将 /GS 标志传给编译器,从而摆脱 unresolved externals 错误。
好了,现在编译生成 DLL,最终的 DLL 大小为 3K,实际的文件大小只有 2.5K。

实现能自删除的可执行程序
  这里所用的主要思路是将一个能自删除的 DLL 作为资源保存在拟实现自删除的可执行程序中,然后在需要时重新创建它,同时,启动一个 rundll32.exe 进程实现删除行为。
  下面是用于将DLL存储为资源的头文件和资源文件。资源类型值只要大于 256 都可以,这是为用户定义类型预留的。此外还有一种可选方法是将 DLL 二进制文件以字节数组的形式直接存储在源中:
在资源中包含一个文件

// SelfDelete.h
#define RC_BINARYTYPE 256
#define ID_MAGICDEL_DLL 100

// SelfDelete.rc
#include "SelfDelete.h"
ID_MAGICDEL_DLL RC_BINARYTYPE MagicDel.dll
下面是可执行程序关键代码:
#include <windows.h>
#include "SelfDelete.h"
void WriteResourceToFile(HINSTANCE hInstance,
		 int idResource,
		 char const *filename)
{
	// 存取二进制资源
	HRSRC hResInfo = FindResource(hInstance, MAKEINTRESOURCE(idResource),
		MAKEINTRESOURCE(RC_BINARYTYPE));
	HGLOBAL hgRes = LoadResource(hInstance, hResInfo);
	void *pvRes = LockResource(hgRes);
	DWORD cbRes = SizeofResource(hInstance, hResInfo);

	// 将二进制资源写到文件
	HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL, 0);
	DWORD cbWritten;
	WriteFile(hFile, pvRes, cbRes, &cbWritten, 0);
	CloseHandle(hFile);
}

void SelfDelete(HINSTANCE hInstance)
{
	WriteResourceToFile(hInstance, ID_MAGICDEL_DLL, "magicdel.dll");

	// 生成命令行
	// 1. 查找 rundll32.exe
	char commandLine[MAX_PATH * 3];
	GetWindowsDirectory(commandLine, sizeof(commandLine));
	lstrcat(commandLine, "//rundll32.exe");
	if (GetFileAttributes(commandLine) == INVALID_FILE_ATTRIBUTES)
	{
		GetSystemDirectory(commandLine, sizeof(commandLine));
		lstrcat(commandLine, "//rundll32.exe");
	}
	// 2. 添加 rundll32.exe 参数
	lstrcat(commandLine, " magicdel.dll,_MagicDel@16 ");
	// 3. 添加本文件名
	char thisName[MAX_PATH];
	GetModuleFileName(hInstance, thisName, sizeof(thisName));
	lstrcat(commandLine, thisName);
	// 执行命令行 
	PROCESS_INFORMATION procInfo;
	STARTUPINFO startInfo; 
	memset(&startInfo, 0, sizeof(startInfo));
	startInfo.dwFlags = STARTF_FORCEOFFFEEDBACK;
	CreateProcess(0, commandLine, 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, 0,
		&startInfo, &procInfo);
}

int WINAPI WinMain(HINSTANCE hInstance, 
		   HINSTANCE hPrevInstance,
		   LPSTR lpCmdLine, 
		   int nCmdShow)
{
	SelfDelete(hInstance);
}      
  WriteResourceToFile 的功能是存取二进制资源,以便能在磁盘中重建 DLL。Windows 资源 API 提供了一个指向原始数据的指针。
SelfDelete 的作用是重新创建DLL并生成如下命令行启动 rundll32.exe:
      path/rundll32.exe magicdel.dll,_MagicDel@16 path/executableName      
  rundll32.exe 位于 Windows 目录或者 System 目录中,所以 SelfDelete 检查它的位置是否正确。当 CreateProcess 被调用执行命令行时,必须设置
STARTF_FORCE-OFFFEEDBACK 标志以防止 Windows 在运行 rundll32.exe 时显示表示忙的沙漏或光标。这样做以后用户不会感觉到有新的进程正在运行。在这个新进程退出之后,DLL 和原来的可执行文件都不见了。
  为了让自删除的可执行程序不依赖于 C 运行时DLL,可执行程序必须静态链接到运行时库代码。为此修改项目编译选项即可:
项目(P)| [项目名称] 属性(P)... | C/C++ | 代码生成 | 运行时库:[单线程(/ML)] 或者 [多线程(/MT)](或者任何不包含此DLL的选项值)
  此自删除技术在所有 Windows 版本中都工作得很稳定。在实际运用中,卸载程序首先将自己的拷贝放到 Windows 临时(Temp)目录,以便能删除所有程序文件和相关目录,最后它用自删除的 DLL 把自己删掉。

编写安装程序
  确定了安装程序要做些什么事情之后,接着是制作安装程序。现在很多的安装程序都是由用户从Internet上下载,然后在本地运行。那么下载的文件体积越小越好,为此最有效的方法是对文件进行压缩处理。如何让用户最先看到的画面是我的程序画面而不是其它公司的安装程序画面呢,好在Windows提供了这样的支持。
  首先创建一个交互式的 Setup 程序,它显示软件许可协议,提示用户安装选项,拷贝文件,然后进行其余的设置工作。然后将 Setup 程序的压缩版本作为资源保存在安装程序(installer)中。这个安装程序要做的只是将 Setup 程序二进制资源重建后写回磁盘,解压缩,然后用一个新进程启动它。保存和读写二进制资源并不难——本文前面已经描述了处理细节和代码。
  自从 Windows 95 开始的每个 Windows 平台都带一组解压缩文件的 API——LZCopy。下面是安装程序使用这个 API 的示例代码:
/ install.h
//
#define RC_BINARYTYPE 256
#define ID_COMPRESSED_SETUP 100
//
// install.rc
//
#include "install.h"
ID_COMPRESSED_SETUP RC_BINARYTYPE AppSetup.ex_
//
// install.cpp
//
#include <windows.h>
#include "install.h"
void WriteResourceToFile(HINSTANCE hInstance,
			 int idResource,
			 char const *filename)
{
	// 参见前述代码
}
void DecompressFile(char const *source, char const *dest)
{
	OFSTRUCT ofs;
	ofs.cBytes = sizeof(ofs);
	int zhfSource = LZOpenFile(const_cast<char *>(source), &ofs, OF_READ);
	int zhfDest = LZOpenFile(const_cast<char *>(dest), &ofs,
		OF_CREATE | OF_WRITE);
	LZCopy(zhfSource, zhfDest);
	LZClose(zhfSource);
	LZClose(zhfDest);
}
int WINAPI WinMain(HINSTANCE hInstance, 
		HINSTANCE hPrevInstance,
		LPSTR lpCmdLine, int nCmdShow)
{
	WriteResourceToFile(hInstance, ID_COMPRESSED_SETUP, "AppSetup.ex_");
	DecompressFile("AppSetup.ex_", "AppSetup.exe");
	DeleteFile("AppSetup.ex_");

	// 启动 AppSetup.exe
	PROCESS_INFORMATION procInfo;
	STARTUPINFO startInfo; 
	memset(&startInfo, 0, sizeof(startInfo));
	CreateProcess(0, "AppSetup.exe", 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, 0,
		&startInfo, &procInfo);
}      
  从代码中可以看到压缩的 Setup 程序是如何作为安装程序的资源保存的。按照本文前面讨论的思路。DecompressFile 函数示范了 LZCopy API 的使用方法。安装程序重新创建 AppSetup.exe,然后运行它。为了顺利编译和生成安装程序,需要将 lz32.lib 添加到项目的编译选项中,通常这个文件在 Visual Studio 的安装目录中,如:
Visual Studio .NET 2003:
C:/Program Files/Microsoft Visual Studio .NET 2003/Vc7/PlatformSDK/Lib

Visual C++ 6.0:
C:/Program Files/Microsoft Visual Studio/VC98/Lib     
在 Visual Studio.NET 中的添加方法是:
项目(P)| [项目名称] 属性(P)... | 链接器 | 附加库目录:[添加上述路径之一]

  此外,为了摆脱对 C运行时DLL的依赖,必须用静态链接到运行库代码:
项目(P)| [项目名称] 属性(P)... | C/C++ | 代码生成 | 运行时库:[单线程(/ML)] 或者 [多线程(/MT)](或者任何不包含此DLL的选项值)

  注意这里安装程序不必等待 Setup 程序完成工作,因为 AppSetup.exe 可以在完成工作后用自删除 DLL 来进行自我删除。
  使用 LZCopy API 最具技巧性的部分是它只能解压缩由 compress.exe 压缩的文件。compress.exe是微软公司的一款压缩文件命令行实用程序,它随 SDK 一起提供。也可以在微软的官方FPT站点下载:ftp://ftp.microsoft.com/softlib/mslfiles/CP0982.EXE。运行EXE后会有几个解包文件,其中包括 compress.exe,其它的文件可以忽略或删除。compress.exe 的使用方法如下:
      compress SourceName DestinationName      

  所有 Windows 版本都内建了解压缩支持,利用它很容易编写安装程序。此外,所有 Windows 版本也都包含了另一个实用程序:expand.exe。用它可以在命令行进行解压缩处理。

总结
  借助自删除 DLL,二进制资源以及 Windows 内建的解压缩支持可以创建自己的安装程序和卸载程序,从而轻松控制用户安装和卸载程序时屏幕的每一个方面....

 

 

VC++ 服务程序编写及安装与卸载 本文共涉及3个工程:beep、install、uninstall。 1) beep工程用于新服务的实现,工程中包含beep.cpp。编译并生成beep.exe,将其拷贝至c:\目录下,供安装程序调用。当安装完毕后,SCM也将调用beep.exe来执行该服务。 2) install工程用于新服务的安装,工程中包含install.cpp。编译并生成install.exe,将其拷贝至:c:\目录中,然后在Windows NT中单击“开始”,再单击“运行”,使用“运行”命令执行带3个参数的installl.exe程序。输入以下命令行进行安装:c:\install.exe BeepService "Beeper" c:\Beep.exe 。其中BeepService是供SCM内部使用的服务名,Beeper是显示在控制面板的服务程序中的名称,"c:\Beep.exe"是服务所在的可执行文件的路径。安装完毕后,你可以在控制面板的服务程序中看到新增的服务Beeper,点击右键选择“属性”,你就可以设置服务的启动类型、服务的状态和启动参数。 3) uninstall工程用于新服务的卸载,工程中包含uninstall.cpp。编译并生成uninstall.exe,将其拷贝至:c:\目录中,然后在Windows NT中单击“开始”,再单击“运行”,使用“运行”命令执行带1个参数的uninstall.exe程序。输入以下命令行进行卸载:c:\uninstall.exe BeepService。其中BeepService就是在安装服务是生成的供SCM内部使用的服务名。 立即下载

相关推荐

通用定时器脉冲计数实验(STM32CubeMx配置)

通用定时器脉冲计数实验

a1169511636的博客 5510

实现DLL的注入与卸载

在Windows系统下,为了避免各个进程相互影响,每个进程的地址空间都是被隔离的。在执行DLL注入时需要通过创建“远程线程”来实现。所谓“远程线程”,并不是跨计算机,而是跨进程的。简而言之,就是进程A在进程B中创建一个线程,这个线程就叫“远程线程”。 要向其它进程中“注入”DLL就需要在目标进程中调用相应的API函数(LoadLibrary),可是目标进程不会自己“乖乖地”调用加载函数,这时候要

其疾如风 其徐如林 侵略如火 不动如山 9845

基于wxWidgets框架,使用DialogBlocks建立OpenGL界面

前言 之前公司要求使用wxWidgets做GUI,基于OpenGL图形内核,开发三维可视化工具。目前初步开发工作基本已经完成,剩下都是完善了。这里记录一下最开始的框架搭建过程(当然是简化版啦)。wxWidgets结合OpenGL开发可以实现跨平台应用,再结合CMake和VS Code,整体开发工具用习惯了会感觉非常顺手。 界面编辑 首先,使用DialogBlocks新建一个工程,这里工程目录...

cyberobot的博客 2751

dll文件的注册与删除

regsvr32 dllname.dllregsvr32/u dllname.dllupFunction RegisterDll(strDllFileName As String, strProgID As String, strClsID As String, Optional bVerify As Boolean = True) As Long 函数说明     注册 Ac

tyronewj的专栏 2310

MySQL 8.0数据库崩了别慌!手把手教你仅凭一个.ibd文件找回数据(附Go工具包)

本文详细介绍了在MySQL 8.0数据库崩溃后,如何仅凭.ibd文件恢复数据的完整流程。通过使用Go语言工具包和ALTER TABLE技巧,即使没有备份也能实现数据重生。文章包含从环境准备到数据验证的全方位指导,帮助DBA和开发者应对紧急数据恢复场景。

weixin_29235923的博客 421

计算文本相似度的常用算法

NLP、数据挖掘领域中,文本分析是一个很重要的领域,这有助于我们去让计算机理解语言的作用和使用。文本分析是数据挖掘的重要手段,利用文本分析,我们将很快的读取到一本书、一篇文章、一段话中的关键词和核心思想,而文本相似度就是我们用来剔除无用信息或者重复信息的重要手段,让计算机去找文本中的不同。 在生活中,信息检索、数据挖掘、机器翻译、文档复制检测等领域都应用到“文本相似度”。文本不仅仅是文字,文本相似度的应用更广,除了文字的匹配,还可以是图片、音频等,因为它们的实质都是在计算机中都是以二进制的方式存在的。相.

氧小氢的博客 2万+

c++ DLL注入与卸载

#include<Windows.h> #include<stdio.h> void UnInjectDLL(int PID) { HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID); //使用CE找到的想要卸载的DLL的地址 LPVOID pRetAddress = (LPVOID)0x544B0000; //HMODULE hModule = LoadLibrary("KERNEL32.DLL")

EEEEEEcho的博客 1986

ABB AC500 系列 PLC 与上位机iFix 的通讯配置

在 软件中,有 3 种方式可以进入 IP config tool 的配置界面 双击 IP_settings,点击 IP config tool,即可进入 IP config tool 界面点击菜单栏的 Tool→IP config如果单独安装了 ABB IP Configration,则可以通过开始→程序→ABB→ABB IPConfigration 启动 IP 配置工具启动 IP config tool 后,即可进入 IP 配置界面。

xdpcxq的专栏 4032

两种方法删除顽固的DLL文件。

DLL文件是Windows系统中一种比较特殊的二进制文件,不少病毒、木马的生成的DLL文件可以具有无进程、不可删除、启动方式多样、隐蔽性高等特点。很多时候我们是通过杀毒软件的提示知道某个DLL文件感染了病毒,但不论是在杀毒软件中选择删除该文件还是手工删除该文件都始终提示出错(图1)。 图1 无法删除   我们之所以无法删除可恶的DLL文件,是因为它依附到了其他进程之中,而这些进

奔跑的快乐的专栏 5万+

DataX对接数据如何在ODS加密脱敏数据(插件开发)

datax对接mysql数据,对姓名只保留姓,名变成**。对这种简单的脱敏,可以不用修改datax源码,直接在配置文件上实现。

大模型大数据攻城狮的专栏 997

Agent 智能体学习指南:从入门到求职的完整路线

AI Agent 不是更长的 prompt,而是一类系统设计——模型在受控环境里观察状态、选择动作、调用工具、接收反馈。本文系统梳理 Agent 的 5 个核心概念、7 个关键模块(Goal/State/Context/Tools/Loop/Guardrails/Eval)、三条学习路线(工程落地/研究算法/求职作品)、框架选型策略(LangGraph/OpenAI Agents SDK/Pydantic AI 等场景推荐),以及可执行的 7 天最小项目计划(从概念到简历 bullet)。

program哲学 231

用自删除dll实现应用程序的安装

实用程序 ? rundll32.exe ? 介绍 ? ? ? ? ? ?    从所周知,DLL的代码通常需要先加载到内存之后才能执行,那么如何执行某个DLL导出的代码而不用创建加载和调用该 ? DLL ? 的 ? EXE ? 文件呢?方法如下:从 ? Windows ? 95 ? 开始的每个 ? Windows ? 操作系统版本都附带一个系统实用程序:rundll32.exe。利用它可以象下面这

wrq147的专栏 656

DeepSeek在实时计算与流处理系统中的突破性实践

对于技术决策者而言,现在正是将DeepSeek实时计算技术纳入企业架构蓝图的关键时机,那些能够率先构建实时智能能力的企业,将在数据驱动的商业竞争中赢得决定性优势。DeepSeek通过创新的流处理架构,成功将复杂事件处理(CEP)的延迟降低到亚秒级,同时保证了计算结果的精确性。DeepSeek研发的神经架构搜索(NAS)与知识蒸馏联合优化框架,可在保持模型精度的前提下,将参数量压缩至原始模型的1/100,实现边缘设备的实时AI推理。随着5G和物联网技术的普及,对实时处理能力的需求将呈指数级增长。

Programming Talk 291

使用duilib开发简单的Window安装包

一、具体思路 安装过程:安装包的制作包括资源文件的打包,资源文件打包到安装包exe中,安装的时候需要从exe中提取出对应的资源文件, 然后解压文件安装到指定目录,然后就是对安装的可执行程序进行注册表的注册,以及快捷方式的注册。 卸载过程:安装包安装时,通常会带有一个卸载程序,此程序的功能就是执行对安装程序目录文件的删除和注册表的清除。 二、实现 安装过程分为三部分实现,安装配置...

208

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

上一篇: 仿真WINDOWS PE加载器的程序
下一篇: 分享比较完整的ROOTKIT DEMO!
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值