【问题标题】:Noticed Something In winuser.h [duplicate]在winuser.h中注意到了一些东西[重复]
【发布时间】:2020-11-10 16:04:27
【问题描述】:

最近我开始从 Microsoft 文档中学习 WIN API,并决定使用我的 IDE 功能查看每个细节。 LoadIconA 是一个以 HINSTANCE 和 LPCSTR 作为参数的函数。我们将 IDI_APPLICATION 作为第二个参数传递。这是一个扩展为的宏

#define IDI_APPLICATION MAKEINTRESOURCE(32512) // winuser.h

此外,MAKEINTRESOURCE 扩展为 ANSI 或 UNICODE 等效项。我正在查看 ANSI 等效项。

#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) // winuser.h

在这里,我注意到整数 I(此处为 32512)最终被类型转换为 LPSTR,该 LPSTR 被传递给 LoadIconA 函数。但是当我做同样的事情时

#include <windows.h>
#include <iostream>
int main(){
     LPCSTR hello = MAKEINTRESOURCEA(32512);
     std::cout << hello << std::endl;
}

我的程序崩溃了。 有人知道这里发生了什么吗?

另外,我没有注意到任何库依赖项。抱歉,问题标题,我没有找到任何合适的标题。

【问题讨论】:

  • "...将整数值转换为与资源管理功能兼容的资源类型。..." docs.microsoft.com/en-us/windows/win32/api/winuser/… "...返回值应仅传递给明确表明它们接受 MAKEINTRESOURCE 作为参数的函数。.."
  • 我并没有声称当你做同样的事情时它会起作用,但我不明白为什么你期望在你做不同的事情时得到相同的结果
  • @vectorX LoadIconA "...要加载的图标资源的名称。或者,此参数可以在低位包含资源标识符,在高位包含零-order word。使用 MAKEINTRESOURCE 宏来创建这个值...." docs.microsoft.com/en-us/windows/win32/api/winuser/…
  • 听起来像在LoadIconA 内部,它确定 LPCSTR 参数是否在 MAKEINTRESOURCE 创建的范围内,如果是,它从不尝试直接将值用作字符串,而是将其用作其他字符串容器的索引。但是,当您 cout &lt;&lt; hello 时,您并没有这样做-您假设它是指向文本的指针,并且遵循无效的指针。因此,崩溃。
  • 非常非常非常古老的 Windows“技巧”。它是要么资源ID指向字符串的指针。在 Windows 中,地址空间的前 64K 总是无效的。因此,如果指针值 devblogs.microsoft.com/oldnewthing/20110217-00/?p=11463

标签: c++ winapi


【解决方案1】:

此宏将整数转换为指针。显然(除非你碰巧猜到一个表示有效指针的整数)结果是一个无效指针,因为取消引用它会导致未定义的行为(通常是崩溃)。

&lt;&lt; 尝试取消引用这个无效指针(将其打印为字符数组)并崩溃。

可以与MAKEINTRESOURCE 一起使用的 WinAPI 函数必须检查它们接收到的指针是否具有这些特殊值之一,并且只有在不是这种情况时才取消引用它们。

【讨论】:

  • 其实这样连续转换的有几千个。所以,这不可能是特别的。
  • @vectorX 然后 WinAPI 函数可能会检查一系列值。
  • 所有这些“特殊”值都小于 65536 (2^16),因此很容易判断是执行额外查找还是尝试将值用作指针。
  • @vectorX:所有这些功能都不是特别的;他们只是转发到FindResourceA/W,这特别的。
猜你喜欢
  • 2023-03-24
  • 1970-01-01
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 2013-03-10
  • 1970-01-01
  • 2023-03-08
相关资源
最近更新 更多