Win32 提取图标 _修改标题

1.在应用程序中使用图标

在上节课中我们已经使用过资源文件了,今天学习使用图标的资源文件

首先

我们鼠标右键点击插入,然后在插入资源框点击Icon,再点击引入

插入我们事先准备好的图标,插入后我们需要修改属性,对于不同位置的图标我们要定义好名字

因为对于每一个图标到时候都会定义一个宏,给我们的图标赋值编号(后面会用)

此时我们在资源文件中引入了我们的图标,但是系统却不知道

因此我们需要做一些事,让系统知道去使用我们的图标

1.加载图标

因为我们的图标是在对话框创建后才能显示

所以对于图标的创建我们需要放在创建了对话框之后

即,放在case  WM_INITDIALOG : 消息选项中

因为只有对话框创建了才能显示我们的图标

1.首先我们创建图标的句柄指针:

HICON hBigIcon;
HICON hSmallIcon;

这里我们可以查一下资料,对于各种句柄的书写

HWND:窗口句柄
HINSTANCE:当前实列句柄,代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址。当你启动一个程序时,操作系统会将这个程序装载到某个内存空间,这个空间的起始地址就是HInstance。在 NT 系统这个 HInstance 一般都是 400000h。

HCURSOR:光标句柄
HFONT:字体句柄
HPEN:画笔句柄
HBRUSH:画刷句柄
HDC:设备环境句柄
HBITMAP:位图句柄
HICON:图标句柄
HMENU:菜单句柄
HFILE:文件句柄
————————————————
版权声明:本文为CSDN博主「顺其自然~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fuhanghang/article/details/118514072

2.使用LOadIcon函数给图标指针赋值

 HICON LoadIcon(
                                HINSTANCE hInstance, // handle to application instance
                                应用程序的句柄
                                LPCTSTR lpIconName // name string or resource identifier);
                                图标的编号或名称(前面定义属性时定义的名称,只不过在这里我们要使用系统定义的宏MAKENTRESOURCE来强转类型)

3.使用SendMessage函数

我们已经引入图标和创建图标的指针,接下来就是要告诉系统,系统就知道去使用了

LRESULT SendMessage(
                                          HWND hWnd,      // handle to destination window
                                          回调函数的句柄
                                          UINT Msg,       // message
                                          消息类型(这里使用WM_SETICON)
                                          WPARAM wParam,  // first message parameter

                                         这里传参的是ICON_SMALL,没搞懂,为啥既不是图标名称也不是指针

                                         LPARAM lParam   // second message parameter
                                        这里传参的是图标指针
);
// Dialog.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include"resource.h"

HINSTANCE hAppInstance=NULL;

BOOL CALLBACK DialogProc(									
						 HWND hwndDlg,  // handle to dialog box			
						 UINT uMsg,     // message			
						 WPARAM wParam, // first message parameter			
						 LPARAM lParam  // second message parameter			
						 )			
{									
	HWND User=NULL;
	HWND Pass=NULL;

	HICON hBigIcon;
	HICON hSmallIcon;
	switch(uMsg)								
	{								
	case  WM_INITDIALOG :								
									
		//MessageBox(NULL,TEXT("WM_INITDIALOG"),TEXT("INIT"),MB_OK);
		
		hBigIcon = LoadIcon (hAppInstance,MAKEINTRESOURCE(IDI_ICON_BIG));
		hSmallIcon = LoadIcon (hAppInstance,MAKEINTRESOURCE(IDI_ICON_SMALL));
		
		SendMessage(hwndDlg,WM_SETICON,ICON_BIG,(DWORD)hBigIcon);		
		SendMessage(hwndDlg,WM_SETICON,ICON_SMALL,(DWORD)hSmallIcon);		
					
		return TRUE;							
									
	case  WM_COMMAND :								
								
		switch (LOWORD (wParam))							
		{							
		case   IDC_BUTTON_OK:							
									
			User=GetDlgItem(hwndDlg,IDC_EDIT_USER);	
			Pass=GetDlgItem(hwndDlg,IDC_EDIT_PASS);

			TCHAR UserBuffer[0x50];
			TCHAR PassBuffer[0x50];
			GetWindowText(User,UserBuffer,0x50);
			GetWindowText(Pass,PassBuffer,0x50);

			MessageBox(NULL,TEXT("IDC_BUTTON_OK"),TEXT("OK"),MB_OK);						
					
			return TRUE;						
									
		case   IDC_BUTTON_ERROR:							
									
			MessageBox(NULL,TEXT("IDC_BUTTON_ERROR"),TEXT("OUT"),MB_OK);						
									
			EndDialog(hwndDlg, 0);						
									
			return TRUE;						
		}							
		break;							
    }									
									
	return FALSE;	
						

}									
									

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{	
	hAppInstance=hInstance;

 	DialogBox(hInstance, MAKEINTRESOURCE (IDD_DIALOG_MAIN),NULL,DialogProc);					
	

	return 0;
}






2.资源表

前面我们已经学过了好几种表,现在我们学习资源表

资源表是所有表当中最复杂的一个,在可选PE头表目录的第三个位置

我们通过image_data_directory->VirtualAddress转FOA+fileBufferp得到资源表的位置

图中绿色部分叫做资源目录

在这里NumberOfNamedEntries+NumberOfIdEntries等于下面黄色部分的数量

即资源的数量

但是每种资源的类型又有所不同,因此在第一层中我们需要资源项来判断类型

1.当Name最高1位是1时,剩下的31位表示一个地址,指向一个结构体(字符串表类型)

Length:表示该子字符串的长度

NameString:表示Unicode的起始地址

在平常中,我们通过内存中00表示结束,但是在这里我们需要Length来判断是否结束

2.当Name最高位1是0时,Name表示一个数字(数字表示类型)

如何来到第二层

在资源项的结构体中有一个成员OffsetOfData

当它最高位是1时,下一层的地址=第一层资源目录地址+OffsetOfData的低31位

#include<stdio.h>
#include<Windows.h>
 
char* File_to_FileBuffer(char* FilePath)
{
	FILE* fp=fopen(FilePath,"rb");
	if(fp==NULL)
	{
		printf("文件打开失败\n");
		exit(0);
	}
	fseek(fp,0,2);//将指针指向末尾
	DWORD size=ftell(fp);
	char* FileBufferp=(char*)malloc(size);
	if(FileBufferp==NULL)
	{
		printf("分配FileBUfferp空间失败\n");
		fclose(fp);
		exit(0);
	}
	memset(FileBufferp,0,size);
	fseek(fp,0,0);
	if(!fread(FileBufferp,size,1,fp))
	{
		printf("文件读取失败\n");
		fclose(fp);
		free(FileBufferp);
		FileBufferp=NULL;
		exit(0);
	}
	return FileBufferp;
}
DWORD RVA_TO_FOA(DWORD RVA,char* FileBufferp)
{
	PIMAGE_DOS_HEADER image_dos_header=NULL;
	PIMAGE_FILE_HEADER image_file_header=NULL;
	PIMAGE_OPTIONAL_HEADER image_optional_header=NULL;
	PIMAGE_SECTION_HEADER image_section_header=NULL;
 
	image_dos_header=(PIMAGE_DOS_HEADER)FileBufferp;
	image_file_header=(PIMAGE_FILE_HEADER)(FileBufferp+image_dos_header->e_lfanew+4);
	image_optional_header=(PIMAGE_OPTIONAL_HEADER)((char*)image_file_header+20);
	image_section_header=(PIMAGE_SECTION_HEADER)((char*)image_optional_header+image_file_header->SizeOfOptionalHeader);
 
	//首先判断是否再头内
	if(RVA<image_section_header->VirtualAddress)
		return RVA;
 
	//判断是否在空白区
	int flag=0;
	for(int i=0;i<image_file_header->NumberOfSections;i++)
	{
		if(RVA>=image_section_header->VirtualAddress && RVA<=image_section_header->VirtualAddress+image_section_header->SizeOfRawData)
		{
			flag=1;
			break;
		}
		image_section_header++;
	}
	if(flag=1)
	{
		DWORD offset=RVA-image_section_header->VirtualAddress;
		return offset+image_section_header->PointerToRawData;
	}
	return 0;
}
 
void Print_ResourceTable(char* FileBufferp)
{
	PIMAGE_DOS_HEADER image_dos_header=NULL;
	PIMAGE_FILE_HEADER image_file_header=NULL;
	PIMAGE_OPTIONAL_HEADER image_optional_header=NULL;
	PIMAGE_DATA_DIRECTORY image_data_directory=NULL;
	PIMAGE_RESOURCE_DIRECTORY image_resource_directory=NULL;
	PIMAGE_RESOURCE_DIRECTORY_ENTRY image_resource_directory_entry=NULL;
 
	image_dos_header=(PIMAGE_DOS_HEADER)FileBufferp;
	image_file_header=(PIMAGE_FILE_HEADER)(FileBufferp+image_dos_header->e_lfanew+4);
	image_optional_header=(PIMAGE_OPTIONAL_HEADER)((char*)image_file_header+20);
	image_data_directory=(PIMAGE_DATA_DIRECTORY)(image_optional_header->DataDirectory);
	image_resource_directory=(PIMAGE_RESOURCE_DIRECTORY)(FileBufferp+RVA_TO_FOA((image_data_directory+2)->VirtualAddress,FileBufferp));//得到资源目录的文件地址
	image_resource_directory_entry=(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((char*)image_resource_directory+16);//得到资源项的地址
	
	DWORD size=image_resource_directory->NumberOfIdEntries + image_resource_directory->NumberOfNamedEntries;
	
	PIMAGE_RESOURCE_DIRECTORY pZero=image_resource_directory;
	for(int i=0;i<size;i++)
	{
		if(image_resource_directory_entry->NameIsString==0 && image_resource_directory_entry->Name==3)
		{
			printf("图标类型:%d\n",image_resource_directory_entry->Name);

			PIMAGE_RESOURCE_DIRECTORY Resource2=(PIMAGE_RESOURCE_DIRECTORY)
				((image_resource_directory_entry->OffsetToData&32767)+(DWORD)pZero);//资源目录指针

			PIMAGE_RESOURCE_DIRECTORY_ENTRY Resource_entry2=(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((char*)Resource2+16);//资源项指针

			DWORD size2=Resource2->NumberOfIdEntries+Resource2->NumberOfNamedEntries;
			for(int j=0;j<size2;j++)
			{
				if(Resource_entry2->NameIsString==0)
				{
					printf("图标编号:%d\n",Resource_entry2->Name);

					PIMAGE_RESOURCE_DIRECTORY Resource3=(PIMAGE_RESOURCE_DIRECTORY)
						((Resource_entry2->OffsetToData&32767)+(DWORD)pZero);//资源目录指针

					PIMAGE_RESOURCE_DIRECTORY_ENTRY Resource_entry3=(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((char*)Resource3+16);//资源项指针
				
					printf("代码页:%d\n",(Resource_entry3->Name&32767));
					PIMAGE_DATA_DIRECTORY fp=(PIMAGE_DATA_DIRECTORY)
							(Resource_entry3->OffsetToData+(DWORD)pZero);
					printf("资源地址:%08x\t资源大小:%x\n",fp->VirtualAddress,fp->Size);					
				}
				printf("\n");
				Resource_entry2++;
			}
			printf("总数量:%d\n",size2);
 
		}
		
		image_resource_directory_entry++;
	}
 
}
int main()
{
	char* FilePath="D:\\FileHistory\\PETool 1.0.0.5.exe";
 
	char* FileBufferp=File_to_FileBuffer(FilePath);
 
	Print_ResourceTable(FileBufferp);
 
	//printf("%x\n",FileBufferp);
 
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用\[1\]: WIN32_LEAN_AND_MEAN是一个宏定义,用于加速生成过程。它通过排除一些不太常用的API,减小了Win32头文件的大小。VC_EXTRALEAN定义了WIN32_LEAN_AND_MEAN和一些NOservice定义,如NOCOMM和NOSOUND。使用Visual C++应用程序向导创建的应用程序会自动使用VC_EXTRALEAN。在旧式MFC应用程序中,可以手动定义VC_EXTRALEAN以加速生成过程。非MFC应用程序可以定义WIN32_LEAN_AND_MEAN和适用的NOservice定义以减少生成时间。\[1\] 引用\[2\]: WIN32_LEAN_AND_MEAN这句话可能会导致编译时的include冲突。当屏蔽了#define WIN32_LEAN_AND_MEAN后,编译就能够正常进行。\[2\] 引用\[3\]: WIN32_LEAN_AND_MEAN的作用是不加载MFC所需的模块。如果工程不使用MFC,可以加上这句宏定义,以加快编译链接速度和减小生成的文件大小。但对于较大的工程,MFC中的类仍然非常有用。\[3\] 综上所述,#define WIN32_LEAN_AND_MEAN是一个宏定义,用于加速生成过程和减小生成文件的大小。它可以排除一些不常用的API,并减小Win32头文件的大小。在编译时可能会导致include冲突,但如果工程不使用MFC,可以使用这个宏定义来加快编译链接速度和减小生成文件的大小。 #### 引用[.reference_title] - *1* [#define WIN32_LEAN_AND_MEAN作用](https://blog.csdn.net/skiing_886/article/details/8791897)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [#define WIN32_LEAN_AND_MEAN 的作用](https://blog.csdn.net/weixin_30462049/article/details/94840713)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [#define WIN32_LEAN_AND_MEAN](https://blog.csdn.net/weixin_30411239/article/details/97098979)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值