DotNet4应用程序打包工具->升级版【二】安装工具分析

在本系列的上一篇中,

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

得到了很多朋友的反馈!

综合朋友的意见,

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

我对这个程序做了升级

如下图:

如你所见,

现在这个打包工具可以打包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 <Windows.h>
#include <ShlObj.h>
#include "resource.h"

TCHAR szFilePath[MAX_PATH + 1];

int LastCheckRdioId;
//提示
void Alert(LPCSTR msg)
{
	MessageBox(NULL,msg,"系统提示",MB_OK);
}

 

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

后记:

没有写容错的代码~

也没有遵循命名规范~

大家见谅~

请各位推荐我的文章

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

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

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

时间: 2024-09-20 15:52:32

DotNet4应用程序打包工具->升级版【二】安装工具分析的相关文章

DotNet4应用程序打包工具-&gt;升级版【三】宿主程序分析+全部源码下载

索引 DotNet4应用程序打包工具->升级版[三]宿主程序分析+全部源码下载 DotNet4应用程序打包工具->升级版[二]安装工具分析 DotNet4应用程序打包工具(把DotNet4安装程序打包进你的应用程序:WINAPI开发,无dotNet环境也可顺利执行)[一]整体思路   废话少说 入口函数 入口函数是所有逻辑的集合体 int WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int nCmdSho

DotNet4应用程序打包工具(把DotNet4安装程序打包进你的应用程序;WINAPI开发,无dotNet环境也可顺利执行)【一】整体思路

先说废话 很多朋友对我写的这个系列的第五篇比较感兴趣:http://www.cnblogs.com/liulun/archive/2011/12/08/2280110.html 因为我承诺第五篇就公布源码了,但是与第五篇相关的代码我还没有完成, 现在又花了一个周末的时间来写这篇文章 原谅我吧~ (如果你觉得这篇文章更有吸引力的话~那另当别论) 索引: DotNet4应用程序打包工具->升级版[三]宿主程序分析+全部源码下载 DotNet4应用程序打包工具->升级版[二]安装工具分析 DotNe

性能测试工具curl-loader二---测试分析

本文在第一篇的基础上讲解,如果你还没有安装curl-loader性能测试工具.请先参考<性能测试工具curl-loader(linux)> 这一节具体分析一下curl-loader的使用,以及各项参数的含义. 简单的性能测试与要求环境: ------- --------------------------------------------------------------------------------------------------------------- ----------

VS2012 程序打包部署图文详解_C#教程

程序编写测试完成后接下来我们要做的是打包部署程序,但VS2012让人心痛的是没有了打包工具.不知道出于什么原因微软没有将打包工具集成在开发环境中,但是我知道总会有解决办法的.     经过翻阅资料发现,VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield.网上有很多第三方的打包工具,但为什么偏要使用微软提供的呢?因为最原始的也是最高级的,万变不离其宗. 一..NET程序部署机制     上篇博客稍微总结了下.NET程序的编译机制,下面了

vs 2012自带打包工具进行部署安装

原文 http://www.cnblogs.com/javawebsoa/archive/2013/04/05/3001632.html#2667832 使用vs2012做的程序,程序做完后准备打包部署.VS有自带的部署安装工具,就像试试,然后就有了一堆问题问题,归根到底有点原因是:英文水平太低,看到满页面的英文,我就不想看.后来经过查找资料终于打包成功.下面来一步一步聊聊我打包部署的过程   一.打包前查看是否已经安装InstallShield Limit Edition Project.  

可以在eclipse运行的程序打包后 使用一些功能就会报错

问题描述 入口函数在CommandLineRunner里面,其中调用了MyCheckUnreachableCode_tijiao的MyCheckUnreachableCode方法,来检查一些不可达代码,程序在eclipse中配置好参数运行正常.但是将源码打包后(打包工具用的这个开源项目自身写好的一个build.xml文件,直接用antbuild而成),如果不加参数会提示usge()的内容,但是一旦加了一个参数就会报:D:mycoderclosure-compilerbuild>java-jarc

Advanced Installer打包工具如何做自动升级

问题描述 AdvancedInstaller打包工具确实是很好用的,不过,对于做软件的自动升级,我做出来老是报错.有没有哪位朋友做个自动升级的,麻烦请教一下,谢谢 解决方案 解决方案二:有人知道么?解决方案三:自己做一个自动升级的程序,先判断版本号再下载压缩包,解压更新解决方案四:下一个官方的ini文件,参考一下不就行了.解决方案五:官方教程,很详细http://www.advancedinstaller.com/user-guide/tutorial-updater.html#create

插件-winform程序打包的问题

问题描述 winform程序打包的问题 开发一个winform程序想打包,其中包含了几个第三方插件,在安装时,想给用户一个提示,让用户选择是否要安装插件1,插件2,如果用户勾选上,就安装,否则就不安装,推荐个安装工具,怎么做了,谢谢大家了 解决方案 InstallShield,VS2012以后,微软推荐的,具体使用我也刚开始用,不太熟悉 解决方案二: installshield或者inno setup vs自带的installshiled le可能有限制,好像最多是3个文件组,建议你用完整版 i

程序打包之后运行错误

问题描述 我用VC写了一个MFC程序,使用了Socket,用VS2008自带的打包工具打了一个安装包,安装之后可以看到程序和一些DLL但是程序运行的时候不向服务器发数据,查了很多资料都没有找到答案,请大伙帮忙... 解决方案 解决方案二:有没有建立正确的连接??解决方案三:用其他制作安装包工具试试,