《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使用的所有字符串都被定义为资源,所以程序很容易就能够被翻译人员转换为非英语版本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/375084.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从人工巡检到智能预警:视频AI智能监控技术在水库/河湖/水利防汛抗洪中的应用

一、背景需求分析 近日&#xff0c;我国多省市遭遇连日暴雨&#xff0c;导致水库、湖泊、河道等水域水位暴涨&#xff0c;城市内涝频发。随着夏季汛期的到来&#xff0c;降雨天气频繁&#xff0c;水利安全管理面临严峻挑战。为保障水库安全、预防和减少洪涝灾害&#xff0c;采…

文档去重(TF-IDF,MinHash, SimHash)

2个doc有些相似有些不相似&#xff0c;如何衡量这个相似度&#xff1b; 直接用Jaccard距离&#xff0c;计算量太大 TF-IDF: TF*IDF TF&#xff1a;该词在该文档中的出现次数&#xff0c; IDF&#xff1a;该词在所有文档中的多少个文档出现是DF&#xff0c;lg(N/(1DF)) MinHash …

windows上修改redis端口号

概况 redis是一个开源的内存数据结构存储系统&#xff0c;常用做数据库、缓存和消息代理。默认的端口号为6379 更改redis端口号步骤如下 先停止redis服务 redis-cli shutdowm 打开redis配置文件 在redis安装目录下&#xff0c;即redis.windows.conf文件。 port 6396 然后…

i18n、L10n、G11N 和 T9N 的含义

注&#xff1a;机翻&#xff0c;未校对。 Looking into localization for the first time can be terrifying, if only due to all of the abbreviations. But the meaning of i18n, L10n, G11N, and T9N, are all very easy to understand. 第一次研究本地化可能会很可怕&…

NI VST 毫米波测试仪器创新

目录 概览​从UHF至V频段的频率覆盖范围&#xff1a;54 GHz远程测量模块​PXIe-5842&#xff1a;VST架构的扩展54 GHz扩频PXIe-5842功能​​宽频覆盖范围​IF和毫米波测试端口可满足多频带需求​高达2 GHz瞬时带宽误差矢量幅度测量性能相位相干同步基于PXI平台集成多种仪器 互补…

Jmeter多用户登录操作实战

在使用Jmeter性能测试时,首先要解决的问题恐怕就会并发压测和多用登录的问题.今天就一篇文章讲清楚这两个问题的解决方案: 一.多并发压测如何配置线程? &#xff08;1&#xff09;同时并发&#xff1a;设置线程组、执行时间、循环次数&#xff0c;这种方式可以控制接口请求的…

01表操作/数类型定义

文章目录 表操作表的创建列的类型定义整数类型浮点类型和定点数类型日期和时间类型 表操作 表的创建 列的类型定义 整数类型 浮点类型和定点数类型 日期和时间类型

探索【Python面向对象】编程:新时代的高级编程范式详解

目录 1. 面向对象编程概念&#xff08;OOP&#xff09; 1.1 什么是类和对象&#xff1f; 1.2 类的定义 1.3 类和对象的关系 1.4 小李的理解 2. 抽象 2.1 抽象的概念 2.2 抽象类和方法 2.3 小李的理解 3. 类和实例 3.1 类的定义和实例化 3.2 类的属性和方法 3.3 小…

【Android】基于 LocationManager 原生实现定位打卡

目录 前言一、实现效果二、定位原理三、具体实现1. 获取权限2. 页面绘制3. 获取经纬度4. 方法调用5. 坐标转换6. 距离计算7. 完整代码 前言 最近公司有个新需求&#xff0c;想要用定位进行考勤打卡&#xff0c;在距离打卡地一定范围内才可以进行打卡。本文将借鉴 RxTool 的 Rx…

【安全设备】入侵检测

一、什么是入侵检测 入侵检测是一种网络安全技术&#xff0c;用于监测和识别对计算机系统或网络的恶意使用行为或未经授权的访问。入侵检测系统&#xff08;IDS&#xff09;是实现这一目标的技术手段&#xff0c;其主要目的是确保计算机系统的安全&#xff0c;通过及时发现并报…

蜂窝互联网接入:连接世界的无缝体验

通过Wi—Fi&#xff0c;人们可以方便地接入互联网&#xff0c;但无线局域网的覆盖范围通常只有10&#xff5e;100m。当我们携带笔记本电脑在外面四处移动时&#xff0c;并不是在所有地方都能找到可接入互联网的Wi—Fi热点&#xff0c;这时候蜂窝移动通信系统可以为我们提供广域…

Lingo学习(三)——工厂合并、运算符、内置函数

一、工厂合并 &#xff08;一&#xff09; 工厂合并——生产二维矩阵 【引入】 sets: factory /1..6/ : a; plant /1..8/ : d; Cooperation(factory,p lant) : c, x; endsets 以上程序可…

Ubuntu编译PX4固件

目录 前言 准备编译参考 前言 要想自己编译PX4固件需要交叉编译器&#xff0c;交叉编译器可以将 x86架构 平台上写好程序编译出来&#xff0c;而编译出来的可执行文件是能用到 arm架构 的平台上。 本次编译是以 px4 v1.13.2 为例。 我的配置如下&#xff1a; 虚拟机 Ubuntu 18…

按下快门前的算法——对焦

对焦算法可以分为测距式&#xff0c;相位式&#xff0c;反差式。 其中测距式是通过激光&#xff0c;&#xff08;TOF&#xff0c;Time of Flight&#xff09;等主动式地得知物距&#xff0c;然后对焦。更常用的是后两者。 反差式CDAF&#xff08;Contrast Detection Auto Foc…

设计模式7-装饰模式

设计模式7-装饰模式 写在前面动机模式定义结构代码推导原始代码解决问题分析 选择装饰模式的理由1. 职责分离&#xff08;Single Responsibility Principle&#xff09;2. 动态扩展功能3. 避免类爆炸4. 开闭原则&#xff08;Open/Closed Principle&#xff09;5. 更好的组合复用…

Vulkan入门系列0- Vulkan与OpenGL的区别

一:概述 Vulkan 是新一代图形和计算API,是由科纳斯组织(Khronos Group)维护的一套跨平台的、开放标准的、现代GPU 的编程接口,它仅仅是规定了一套编程接口,并没有接口的具体实现,实现是由硬件厂商适配实现的,市面上像NVIDIA、AMD和Intel等国际大厂基本提供了完整的…

一天20MW!天途推出无人机全自主光伏巡检平台

01 光伏电站的运维挑战 光伏发电为人类提供了可持续的清洁能源供给。一般集中式电站建设在空旷的地区&#xff0c;如荒地、沙漠等地区&#xff1b;分布式电站建设在用户的屋顶和建筑物表面&#xff0c;如住宅、商业建筑、工业厂房等地区。 随着光伏电站的大规模的使用&#x…

流程图编辑框架LogicFlow-vue-ts和js

LogicFlow官网https://site.logic-flow.cn/LogicFlow 是一款流程图编辑框架&#xff0c;提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow支持前端研发自定义开发各种逻辑编排场景&#xff0c;如流程图、ER图、BPMN流程等。在工作审批配…

WebDriver与浏览器通信的深度剖析与探索

在自动化测试的世界里&#xff0c;WebDriver无疑是连接测试脚本与浏览器之间的桥梁&#xff0c;它让复杂的自动化测试成为可能。本文将深入探讨WebDriver与浏览器之间的通信机制&#xff0c;揭示它们之间如何协同工作&#xff0c;以及这一过程中涉及的关键技术和挑战。 一、We…

Lingo学习(二)——线性规划基础、矩阵工厂

一、线性规划基础 &#xff08;一&#xff09;方法 ① 一个线性规划中只含一个目标函数。(两个以上是多目标线性规划,Lingo无法直接解) ② 求目标函数的最大值或最小值分别用max …或min …来表示。 ③ 以!开头,以;结束的语句是注释语句; ④ 线性规划和非线性规划的本质…