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;
}