《Windows API每日一练》9.1.5 自定义资源

自定义资源(Custom Resources)是在 Windows 程序中使用的一种资源类型,用于存储应用程序特定的数据、图像、音频、二进制文件等。通过自定义资源,开发者可以将应用程序所需的各种资源文件集中管理和存储,便于在程序中访问和使用。

以下是一些关于自定义资源的要点:

●自定义资源的类型:

1.自定义资源可以是任何应用程序特定的数据或文件,如图像、音频、XML 配置文件、文本文件等。

2.自定义资源可以使用自定义的资源类型标识符进行标识,例如 "MY_CUSTOM_RESOURCE"。

●创建和编辑自定义资源:

1.自定义资源通常包含在应用程序的资源文件(.rc)中。

2.使用资源编辑器(如 Visual Studio 的资源视图)可以创建和编辑自定义资源。

3.在资源文件中,可以为每个资源指定唯一的资源标识符和对应的资源文件路径。

●引用和使用自定义资源:

1.在代码中引用和使用自定义资源时,可以使用资源标识符来加载或访问对应的资源。

2.使用相应的 API 函数(如 LoadResource、FindResource、LockResource 等)来加载和操作自定义资源。

3.根据自定义资源的类型,可以使用不同的 API 函数(如图像资源可以使用 GDI 函数、音频资源可以使用 DirectSound 函数)来处理自定义资源。

■下面是一个示例代码片段,展示了如何加载和使用自定义资源:

#include <Windows.h>

int main()

{

    HINSTANCE hInstance = GetModuleHandle(NULL);  // 获取当前实例句柄

    HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(IDR_MY_RESOURCE), "MY_CUSTOM_RESOURCE");  // 查找自定义资源

    HGLOBAL hResData = LoadResource(hInstance, hResource);  // 加载自定义资源

    LPVOID pData = LockResource(hResData);  // 锁定自定义资源

    // 使用自定义资源...

    return 0;

}

在上述示例中,IDR_MY_RESOURCE 是自定义资源的标识符,在资源文件中定义了对应的资源文件路径。使用 FindResource 函数查找自定义资源,然后使用 LoadResource 函数加载自定义资源,最后使用 LockResource 函数锁定自定义资源以获取指向资源数据的指针。随后,可以根据资源的类型和需求,使用指针 pData 进行后续的处理和操作。

需要注意的是,自定义资源的具体使用方式取决于资源类型和应用程序的需求。开发者可以根据实际需求选择合适的资源类型和对应的 API 函数来处理自定义资源。

自定义资源为应用程序提供了一种灵活的资源管理方式,可以将应用程序所需的各种数据和文件统一管理,并方便地在程序中访问和使用。通过使用自定义资源,可以使应用程序更加模块化、可维护和可扩展。

       ■在VS中添加自定义资源

1、添加资源

 2、点击“自定义”,填写资源类型“TEXT"

 3、导入资源,自动生成text1.bin文件,资源ID:IDR_TEXT1

 4、VS中直接在自定义编译器中输入资源文件名并修改ID报错:无法加载外部资源——可能的原因是资源未导入。

5、在资源视图框中添加资源。

6、导入外部资源文件。

7、重新填写资源文件名和ID,注意ID名称需要填写带引号的字符串"ANNABELLEE"。

8、保存设置之后就可以了

 

还有一种更简单的方法,直接修改资源文件POEPOEM.rc。TEXT下方画线处添加资源即可。

      

9.1.6 第57练:字符串资源表和自定义资源

/*------------------------------------------------------------------------

 057 WIN32 API 每日一练

     第57个例子POEPOEM.C:字符串资源表和自定义资源

     LoadString 函数   

     LoadResource 函数 

     FindResource 函数 

     LockResource 函数 

     AnsiNext 宏定义

 (c) www.bcdaren.com 编程达人

-----------------------------------------------------------------------*/

#include <windows.h>

#include "resource.h"

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

HINSTANCE hInst ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

 PSTR szCmdLine, int iCmdShow)

{   //资源文件名,标题和错误信息

     TCHAR szAppName[16], szCaption[64], szErrMsg[64];

     HWND hwnd;

     MSG msg;

     WNDCLASS wndclass;

     //加载字符串资源

     LoadString(hInstance, IDS_APPNAME, szAppName,

          sizeof(szAppName) / sizeof(TCHAR));

     LoadString(hInstance, IDS_CAPTION, szCaption,

          sizeof(szCaption) / sizeof(TCHAR));

     wndclass.style = CS_HREDRAW | CS_VREDRAW;

     wndclass.lpfnWndProc = WndProc;

     wndclass.cbClsExtra = 0;

     wndclass.cbWndExtra = 0;

     wndclass.hInstance = hInstance;

//添加图标

     wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));

     //wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

//自定义鼠标指针

     wndclass.hCursor = LoadCursor(hInstance,MAKEINTRESOURCE(IDC_CURSOR1));

     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

     wndclass.lpszMenuName = NULL;

     wndclass.lpszClassName = szAppName;

     //hInst = hInstance;//原代码中没有,且不会报错

     if (!RegisterClass(&wndclass))

     {

          //LoadStringA(hInstance, IDS_APPNAME, (char *)szAppName,

          //     sizeof(szAppName));

          LoadStringA(hInstance, IDS_ERRMSG, (char *)szErrMsg,

               sizeof(szErrMsg));

          MessageBoxA(NULL, (char *)szErrMsg,

               (char *)szAppName,

               MB_ICONERROR);

          return 0;

     }

     hwnd = CreateWindow(szAppName, szCaption,

          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,

          CW_USEDEFAULT, CW_USEDEFAULT,

          CW_USEDEFAULT, CW_USEDEFAULT,

          NULL, NULL, hInstance, NULL);

     ShowWindow(hwnd, iCmdShow);

     UpdateWindow(hwnd);

     while (GetMessage(&msg, NULL, 0, 0))

     {

          TranslateMessage(&msg);

          DispatchMessage(&msg);

     }

     return msg.wParam;

}

LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM

lParam)

{

     //static char * pText;

     static LPCSTR pText;

     static HGLOBAL hResource;//资源句柄-指向内存块的句柄

     static HWND hScroll;

     static int iPosition, cxChar, cyChar, cyClient,

          iNumLines, xScroll;

     HDC hdc;

     PAINTSTRUCT ps;

     RECT rect;

     TEXTMETRIC tm;

     switch (message)

     {

     case WM_CREATE:

          hdc = GetDC(hwnd);

          GetTextMetrics(hdc, &tm);

          cxChar = tm.tmAveCharWidth;

          cyChar = tm.tmHeight + tm.tmExternalLeading;

          ReleaseDC(hwnd, hdc);

//垂直滚动条的宽度,以像素为单位

          xScroll = GetSystemMetrics(SM_CXVSCROLL);

          //生成滚动条

          hScroll = CreateWindow(TEXT("scrollbar"), NULL,

               WS_CHILD | WS_VISIBLE | SBS_VERT,

               0, 0, 0, 0,

               hwnd, (HMENU)1, hInst, NULL);

          //获取文本句柄

          hResource = LoadResource(hInst,

               FindResource(hInst, TEXT("AnnabelLee"),//确定具有指定类型和名称

的资源在指定模块中的位置

                    TEXT("TEXT")));

          //检索指向内存中指定资源的指针

          pText = (LPCSTR)LockResource(hResource);

          iNumLines = 0;//读取文本行数

          //获取文本行数

          while (*pText != '\\' && *pText != '\0')//遇\或\0结束

          {

               if (*pText == '\n')

                    iNumLines++;

                //返回ansi字符串中的下一个位置(指针),AnsiNext为16位Windows上

//的一个宏定义,Win32使用CharNext代替(AnsiNext只能处理ansi字符

//串;而CharNext可以ansi,也可以unicode字符串)

                //pText = AnsiNext(pText);

               pText = (LPCSTR)CharNext((LPCWSTR)pText);

          }

     //*pText = '\0';//此处原代码中说明以空字符结尾---实际文本不是以空字符结尾

          //设置滚动条

          SetScrollRange(hScroll, SB_CTL, 0, iNumLines, FALSE);

          SetScrollPos(hScroll, SB_CTL, 0, FALSE);

          return 0;

     case WM_SIZE:

          MoveWindow(hScroll, LOWORD(lParam) - xScroll, 0,

               xScroll, cyClient = HIWORD(lParam), TRUE);

          SetFocus(hwnd);//设置焦点

          return 0;

     case WM_SETFOCUS:

          SetFocus(hScroll);//捕捉滚动条滑块焦点

          return 0;

     case WM_VSCROLL:

          switch (LOWORD(wParam))  //须加LOWORD,因为通知码在低位字

          {

          case SB_TOP:

               iPosition = 0;

               break;

          case SB_BOTTOM:

               iPosition = iNumLines;

               break;

          case SB_LINEUP:

               iPosition -= 1;

               break;

          case SB_LINEDOWN:

               iPosition += 1;

               break;

          case SB_PAGEUP:

               iPosition -= cyClient / cyChar;

               break;

          case SB_PAGEDOWN:

               iPosition += cyClient / cyChar;

               break;

          case SB_THUMBTRACK:

               iPosition = HIWORD(wParam);

               break;

          }

          iPosition = max(0, min(iPosition, iNumLines));

          if (iPosition != GetScrollPos(hScroll, SB_CTL))

          {

               SetScrollPos(hScroll, SB_CTL, iPosition, TRUE);

               InvalidateRect(hwnd, NULL, TRUE);

          }

          return 0;

     case WM_PAINT:

          hdc = BeginPaint(hwnd, &ps);

          pText = (char *)LockResource(hResource);

          GetClientRect(hwnd, &rect);

          rect.left += cxChar;//从第2列开始显示

          rect.top += cyChar * (1 - iPosition);

          //包括字体外部行首高度。通常,外部行首不包括在一行文本的高度中。

          DrawTextA(hdc, pText, -1, &rect, DT_EXTERNALLEADING);

          EndPaint(hwnd, &ps);

          return 0;

     case WM_DESTROY:

          FreeResource(hResource);

          PostQuitMessage(0);

          return 0;

     }

     return DefWindowProc(hwnd, message, wParam, lParam);

}

/******************************************************************************

LoadString 函数:加载字符串资源,然后将字符串复制到带有终止空字符的缓冲区中,

或者返回指向字符串资源本身的只读指针。

*******************************************************************************

LoadResource 函数:检索可用于获取指向内存中指定资源的第一个字节的指针的句柄

HGLOBAL LoadResource(

  HMODULE hModule,//其可执行文件包含资源的模块的句柄。如果hModule为NULL,则系统将从用于创建当前进程的模块中加载资源

  HRSRC   hResInfo//要加载的资源的句柄

);

*******************************************************************************

FindResource 函数:确定具有指定类型和名称的资源在指定模块中的位置

HRSRC FindResourceA(

  HMODULE hModule,//包含资源的模块的句柄

  LPCSTR  lpName,//资源的名称

  LPCSTR  lpType//资源的类型

);

*******************************************************************************

LockResource 函数:检索指向内存中指定资源的指针

LPVOID LockResource(

  HGLOBAL hResData//要访问的资源的句柄

);

*******************************************************************************

AnsiNext 宏定义:

16位Windows上的一个api函数(准确地说是一个宏定义),只能处理ansi字符串;

后来Win32出现的时候,微软为了兼容,封装就是通过CharNext来实现的。

CharNext可以ansi,也可以unicode字符串。

该函数的就是返回ansi字符串中的下一个位置(指针)。

*/

Resource.h头文件

//{{NO_DEPENDENCIES}}

// Microsoft Visual C++ 生成的包含文件。

// 供 057_POEPOEM.rc 使用

//

#define IDS_APPNAME                     1

#define IDS_Caption                     2

#define IDS_CAPTION                     3

#define IDS_ERRMSG                      4

#define IDI_ICON1                       1

#define IDC_CURSOR1                     2

#define IDR_TEXT1                       107

#define IDR_TEXT2                       108

// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        126

#define _APS_NEXT_COMMAND_VALUE         40002

#define _APS_NEXT_CONTROL_VALUE         1001

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif

057_POEPOEM.rc资源脚本文件包含4种类型资源:

1.图标资源:

// Icon

//

IDI_ICON1 ICON     "D:\\code\\windows5.0\\A daily

practice\\057_POEPOEM\\057_POEPOEM\\icon1.ico"

2.鼠标指针位图资源:

// Cursor

//

IDC_CURSOR1             CURSOR                  "cursor1.cur"

3.字符串资源表:

// String Table

//

STRINGTABLE

BEGIN

    IDS_APPNAME             "PoePoem"

    IDS_CAPTION             """Annabel Lee"" by Edgar Allan Poe"

    IDS_ERRMSG              "This program requires Windows NT!"

END

4.自定义资源:

// TEXT

//

ANNABELLEE              TEXT                    "POEPOEM.TXT"

运行结果:

图9-9 字符串资源表和自定义资源

 

总结

在POEPOEM.RC资源脚本中,用户定义资源被指定为TEXT类型,文本名字为 "ANNABELLEE" :ANNABELLEE TEXT POEPOEM.TXT

在WndProc中处理WM_CREATE消息时,该资源的句柄通过FindResource和LoadResource 来获得。LockResource将该资源锁定,一个小的例程将文件尾部的反斜杠(\)替换为0。这是为了方便在后面的WM_PAINT消息中使用DrawText函数。

【注意】我们使用了子窗口滚动条控件而不是窗口滚动条。该子窗口滚动条控件有一个自动键盘接口,所以在POEPOEM中不需要处理WM_KEYDOWN消息。

POEPOEM还使用了三个字符串,它们的ID在RESOURCE.H头文件中定义。在程序的开始,IDS_APPNAME和IDS_CAPTION字符串被LoadString加载到内存:

LoadString (hlnstance, IDS_APPNAME, szAppName,

sizeof (szAppName) /sizeof (TCHAR));

LoadString (hlnstance, IDS_CAPTION, szCaption,

sizeof (szCaption) /sizeof (TCHAR));

【注意】这两个调用在RegisterClass之前。程序用LoadStringA加载IDS_APPNAME和 IDS_ERRMSG字符串,并用MessageBoxA来显示自定义消息框:

if (!RegisterClass (&wndclass))

{

LoadStringA (hInstance, IDS_APPNAME, (char *) szAppName,

sizeof (szAppName)) ;

LoadStringA (hInstance, IDS_ERRMSG, (char *) szErrMsg,

sizeof (szErrMsg)) ;

MessageBoxA (NULL, (char *) szErrMsg,

(char *) szAppName, MB_ICONERROR) ;

return 0 ;

}

【注意】从TCHAR字符串变量到char指针的强制转换。

AnsiNext为16位Windows上的一个宏定义,Win32使用CharNext代替(AnsiNext只能处理ansi字符串;而CharNext可以ansi字符串,也可以unicode字符串)。

pText = AnsiNext(pText);

替换为:

pText = (LPCSTR)CharNext((LPCWSTR)pText);

由POEPOEM使用的所有字符串都被定义为资源,所以程序很容易就能够被翻译人员转换为非英语版本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值