博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DotNet4应用程序打包工具->升级版【二】安装工具分析
阅读量:5977 次
发布时间:2019-06-20

本文共 6766 字,大约阅读时间需要 22 分钟。

在本系列的中,

我们给出了这个工具的具体的思路。

得到了很多朋友的反馈!

综合朋友的意见,

在没有改变工具原理的基础上

我对这个程序做了升级

如下图:

如你所见,

现在这个打包工具可以打包dotNet2.0  3.5  4

乃至所有在注册表中添加过注册表项的应用程序

下面我们就开始分析安装工具(也就是上面你看到的那个图片)

--------------------------

入口函数:

int WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int nCmdShow){		DialogBox(hInstance,MAKEINTRESOURCE(MainWinDL),0,DlgProc);	return 0;}
 

好吧,入口函数很简单,只是创建了一个窗体,并注册了窗口过程函数

-----------------------------

窗口过程

//窗口过程BOOL CALLBACK DlgProc (HWND hDlg, UINT message,WPARAM wParam, LPARAM lParam){    switch (message)    {		case WM_INITDIALOG :			OnInitDlg(hDlg);			return TRUE ;		case WM_COMMAND :			switch (LOWORD(wParam))			{				case IDC_STATIC_Name:					ShellExecute(hDlg,"open","http://www.cnblogs.com/liulun",NULL,NULL,SW_SHOWNORMAL); 					break;				case IDC_BUTTON1:						GetFile(hDlg,IDC_EDIT1);					break;				case IDC_BUTTON3:					GetFile(hDlg,IDC_EDIT3);					break;				case IDC_RADIO1:					CheckRadio(hDlg,IDC_RADIO1,"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v2.0.50727");					break;				case IDC_RADIO2:					CheckRadio(hDlg,IDC_RADIO2,"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5");					break;				case IDC_RADIO3:					CheckRadio(hDlg,IDC_RADIO3,"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4");					break;				case IDC_RADIO_ELSE:					CheckRadio(hDlg,IDC_RADIO_ELSE,"");					break;				case IDOK:					ReleaseTar(hDlg);					ReplaceICO(hDlg);					BagTar(hDlg,IDC_EDIT3);					BagTar(hDlg,IDC_EDIT1);					BagStr(hDlg);					Alert("打包成功");					break;				case IDCANCEL:					EndDialog (hDlg, 0) ;					return TRUE ;			}		break;    }    return FALSE ;}
 

在这个过程函数里

接收到的每个消息都执行了一个或几个函数

那么,我们就一个函数一个函数的讲

-------------------------------------------------------

窗口初始化消息里

我们默认选中了dotNet4的单选按钮

void OnInitDlg(HWND hwnd){	HWND cld = ::GetDlgItem(hwnd,IDC_RADIO3);	::SendMessage(cld,BM_SETCHECK,1,0);	::SetDlgItemText(hwnd,IDC_EDIT2,"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4");	LastCheckRdioId = IDC_RADIO3;}
 

---------------------------------------------------------

四个单选按钮的单击事件

设置了文本框的内容,

并记录了当前选中的是哪个单选按钮

void CheckRadio(HWND hwnd,int rdioID,LPCSTR val){	if(rdioID == LastCheckRdioId)	{		return;	}	::SetDlgItemText(hwnd,IDC_EDIT2,val);	LastCheckRdioId = rdioID;}
 

------------------------------------------------------------

选择文件

把选中的文件路径赋值给相应的文本框

//得到文件void GetFile(HWND hwnd,int EDITId){	char szFile[MAX_PATH] = {0};	OPENFILENAME ofn;	memset(&ofn, 0, sizeof(OPENFILENAME));   	ofn.lStructSize = sizeof(OPENFILENAME);     	ofn.lpstrFile = szFile;   	ofn.nMaxFile = MAX_PATH;   	ofn.lpstrFilter = "应用程序 (.exe)\0*.exe\0\0";	ofn.lpstrDefExt = "exe";   	ofn.lpstrTitle = "选择exe文件";	ofn.nFilterIndex = 1;   	ofn.lpstrFileTitle = NULL;   	ofn.nMaxFileTitle = 0;   	ofn.lpstrInitialDir = NULL;	if(GetOpenFileName(&ofn))	{		SetDlgItemText(hwnd,EDITId,szFile);	}}
 

--------------------------------------------------------------------

从资源中读取宿主程序,并按指定的文件名,释放到当前目录下

//释放资源int ReleaseTar(HWND hwnd){		::GetDlgItemText(hwnd,IDC_EDIT1,szFilePath,MAX_PATH);	::strcat(szFilePath,".bag.exe");	HMODULE hInstance = ::GetModuleHandle(NULL);    HRSRC hResID = ::FindResource(hInstance,(LPCSTR)IDR_BIN1,"bin");     HGLOBAL hRes = ::LoadResource(hInstance,hResID);    LPVOID pRes = ::LockResource(hRes);    DWORD dwResSize = ::SizeofResource(hInstance,hResID);	if(!dwResSize)	{		return 0;	}    HANDLE hResFile = CreateFile(szFilePath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);        DWORD dwWritten = 0;    WriteFile(hResFile,pRes,dwResSize,&dwWritten,NULL);    CloseHandle(hResFile);    if(dwResSize == dwWritten);	{		return 1;	}	return 0;}
 

---------------------------------------------------------------------------

替换宿主程序的ICO图标资源

这里需要重点说明一下:

要想更新一个应用程序的资源

必须先知道这个资源的ID

GetIcoIndex函数的工作就是获取资源ID的

因为一般的应用程序图标资源都会有两个

所以获取了两个图表资源的ID

其他的WINAPI就不多解释了~~

int GetIcoIndex(HMODULE hExe,int index[]){	HRSRC hRes;	int iLoop;	int i = 0;	for(iLoop = 1;;iLoop++)    {        hRes = FindResource(hExe, MAKEINTRESOURCE(iLoop), RT_ICON); 		if (NULL == hRes)		{			if(iLoop == 60)			{				break;			}			continue ; 		}        else		{			index[i]  = iLoop;			i +=1;			if(i == 2)			{				break;			}		}    }	return 1;}int ReplaceICO(HWND hwnd){	HMODULE hSrcExe,hDestExe;	HANDLE hUpdateRes;	HRSRC hRes;	HRSRC hResLoad;	char *lpResLock;	int result;	char szFile[MAX_PATH+1] = {0};	int hSrcIndex[2] = {0};	int hDestIndex[2] = {0};	::GetDlgItemText(hwnd,IDC_EDIT1,szFile,MAX_PATH);	hSrcExe = LoadLibrary(szFile);	hDestExe = LoadLibrary(szFilePath);	GetIcoIndex(hSrcExe,hSrcIndex);	GetIcoIndex(hDestExe,hDestIndex);	for(int i=0;i<2;i++)	{		hRes = FindResource(hSrcExe, MAKEINTRESOURCE(hSrcIndex[i]), RT_ICON); 		hResLoad=(HRSRC)LoadResource(hSrcExe,hRes);		lpResLock=(char*)LockResource(hResLoad);		FreeLibrary(hDestExe);		hUpdateRes=BeginUpdateResource(szFilePath,FALSE);		result=UpdateResource(hUpdateRes,RT_ICON,MAKEINTRESOURCE(hDestIndex[i]),MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),lpResLock,SizeofResource(hSrcExe,hRes));		EndUpdateResource(hUpdateRes, FALSE);	}	FreeLibrary(hSrcExe);	return result;}
 

---------------------------------------

为宿主程序增加目标程序资源和dotNet安装包资源

增加的资源也是需要标明ID的

因为宿主程序会根据约定好的ID来得到这些资源

EditId参数就是这些资源的ID

int BagTar(HWND hwnd,int EditId){	HANDLE hFile;	DWORD dwFileSize,dwBytesRead;	LPBYTE lpBuffer;	char szFile[MAX_PATH+1] = {0};	::GetDlgItemText(hwnd,EditId,szFile,MAX_PATH);	hFile = CreateFile(szFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);	dwFileSize = GetFileSize(hFile, NULL);	lpBuffer = new BYTE[dwFileSize];	ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL);	HANDLE hResource = BeginUpdateResource(szFilePath, FALSE);	UpdateResource(hResource,RT_RCDATA,MAKEINTRESOURCE(EditId),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPVOID)lpBuffer,dwFileSize);		EndUpdateResource(hResource, FALSE);		delete [] lpBuffer; 	CloseHandle(hFile);	return 1;}
 

--------------------------------------------------------

把注册表项的路径也当作资源打包进宿主程序

我们约定这个资源的ID为1039

int BagStr(HWND hwnd){	char szFile[MAX_PATH+1] = {0};	::GetDlgItemText(hwnd,IDC_EDIT2,szFile,MAX_PATH);	HANDLE hUpdateRes=BeginUpdateResource(szFilePath,FALSE);	int result=UpdateResource(hUpdateRes,RT_RCDATA,MAKEINTRESOURCE(1039),MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),(LPVOID)szFile,::strlen(szFile));	EndUpdateResource(hUpdateRes, FALSE);	return 0;}
 

-------------------------------------------------------------

其他的一些代码如下

#include 
#include
#include "resource.h"TCHAR szFilePath[MAX_PATH + 1];int LastCheckRdioId;//提示void Alert(LPCSTR msg){ MessageBox(NULL,msg,"系统提示",MB_OK); }
 

---------------------------------------------------------------

后记:

没有写容错的代码~

也没有遵循命名规范~

大家见谅~

请各位推荐我的文章

因为你们的支持才是我的动力->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->

此工具编译后的可执行文件下载地址:

(因为不在需要把dotNet4安装程序打包进来,所以只有几十K了!多轻便啊!)

你可能感兴趣的文章
有点烦,不知道如何开始准备评测师考试?
查看>>
Struts2核心工作原理解析
查看>>
我的友情链接
查看>>
利用命令清除和设定静态IP地址
查看>>
ERROR 1201 (HY000): Could not initialize master info structure
查看>>
深挖BAT内部级别和薪资待遇
查看>>
利用 Android Studio 和 Gradle 打包多版本APK
查看>>
hdu1208
查看>>
struct 类型指针技巧
查看>>
POJ 1321 棋盘问题 题解
查看>>
js实现购物车数量的增加与减少,js实现购物车数量的自增与自减
查看>>
gitlab部署步骤+汉化
查看>>
linux清理缓存的命令
查看>>
jquery文本折叠
查看>>
验证码
查看>>
springmvc请求参数获取(自动绑定)的几种方法
查看>>
对导航条的改造
查看>>
python 异常处理
查看>>
程序局部性原理的一些思考
查看>>
AKOJ-2037-出行方案
查看>>