Win32 宽字符串对齐要求

Kri*_*hty 6 c++ winapi abi memory-alignment

我将 GUI 代码中的问题缩小到SetWindowTextW(HWND, wchar_t *)如果新窗口标题未与两个字节对齐则默默失败。在本例中,SetWindowText()返回1( success ) 但不设置新文本。

\n

MSVC 上的自然对齐wchar_t是 2 个字节,所以这绝对是我的错误。但为了确保我尝试找到 Win32 字符串的对齐规则。

\n

我没有找到官方文档,只是一个旧的新闻组帖子提到了 Open Watcom 编译器\xc2\xa0\xe2\x80\x93的错误报告,该报告声称Windows NT 上的 Win32 和 COM 实际上需要4 字节对齐!虽然这对我来说似乎很奇怪,但我注意到 MSVC 确实将每个wchar_t文字对齐到四个字节,而不是两个。实际上,您可以wchar_t通过 使 MSVC 更密集地打包常量字符串alignas(2)。Win32 中的堆粒度也 >=8 字节。

\n

如果 Win32 需要对宽字符字符串进行四字节对齐(如源声明),并且 API 调用在错误的数据对齐上默默失败(如SetWindowText()1 字节对齐),我感觉遇到了很大的麻烦。

\n

有没有官方文档说明 Win32/COM 中宽字符串的明确对齐要求?是两个字节还是四个字节?

\n
\n

重现问题的代码:

\n
#include <Windows.h>\n#include <CommCtrl.h>\n#include <cassert>\n\nint main() {\n\n  auto hWnd = CreateWindowW(WC_BUTTONW, L"original title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, nullptr, nullptr);\n  assert(hWnd);\n  ShowWindow(hWnd, SW_SHOWDEFAULT);\n  UpdateWindow(hWnd);\n\n  // Set title (aligned string):\n  auto alignedResult = SetWindowTextW(hWnd, L"aligned title");\n  assert(alignedResult != 0);\n\n  // Set title (unaligned string):\n  char buffer[50];\n  memcpy(&buffer[1], L"unaligned title", sizeof L"unaligned title");\n  auto unalignedResult = SetWindowTextW(hWnd, reinterpret_cast<wchar_t*>(&buffer[1])); // undefined behavior but for simplicity\n  assert(unalignedResult != 0); // success is reported but title didn\xe2\x80\x99t change\n\n  MSG msg;\n  while (GetMessage(&msg, nullptr, 0, 0)) {\n    TranslateMessage(&msg);\n    DispatchMessage(&msg);\n  }\n\n  return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Kri*_*hty 2

Win32 宽字符串对齐为两个字节

使用 Windows 标头一文包含控制结构打包一节,该节将 Win32 类型对齐与 C 编译器的类型对齐联锁。这归结为宽字符字符串的两字节对齐。

问题中链接的讨论不适用,因为它是关于BSTRs 的。它们具有与宽字符串不同的内存布局。

问题SetWindowTextW()是我遇到了未指定的行为,因为我通过传递未对齐的数据违反了基本的 API 规则。

除了文档之外,您还可以在 Windows 标头中找到开创先例的位置。CHARFORMATW例如,该结构是四字节对齐的,但包含两字节对齐的宽字符字符串。