I narrowed down a problem in my GUI code to SetWindowTextW(HWND, wchar_t *)
silently failing if the new window title is not aligned to two bytes. In this case, SetWindowText()
returns 1
(success) but does not set the new text.
The natural alignment of wchar_t
on MSVC is 2 bytes, so this was definitely my error. But just to be sure I tried to find the alignment rules for Win32 strings.
I found no official documentation, just an old newsgroup thread mentioning a bug report for the Open Watcom compiler – which claims that Win32 and COM on Windows NT actually require 4-byte alignment! While this seemed outlandish to me, I noticed that MSVC does indeed align every wchar_t
literal to four bytes, not two. You can actually make MSVC pack wchar_t
constant strings more densely via alignas(2)
. Heap granularity in Win32 is also >=8 bytes.
If Win32 required four-byte alignment for wide-character strings (like the source claims) and API calls silently fail on wrong data alignment (like SetWindowText()
does with 1-byte alignment), I feel like being in deep trouble.
Is there any official documentation stating the definitive alignment requirements for wide-character strings in Win32/COM? Is it two or four bytes?
Code that reproduces the problem:
#include <Windows.h>
#include <CommCtrl.h>
#include <cassert>
int main() {
auto hWnd = CreateWindowW(WC_BUTTONW, L"original title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, nullptr, nullptr);
assert(hWnd);
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
// Set title (aligned string):
auto alignedResult = SetWindowTextW(hWnd, L"aligned title");
assert(alignedResult != 0);
// Set title (unaligned string):
char buffer[50];
memcpy(&buffer[1], L"unaligned title", sizeof L"unaligned title");
auto unalignedResult = SetWindowTextW(hWnd, reinterpret_cast<wchar_t*>(&buffer[1])); // undefined behavior but for simplicity
assert(unalignedResult != 0); // success is reported but title didn’t change
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BSTR
s which are slightly different: They still encode strings usingwchar_t
characters but have a 32-bit length prefix, meaning that the character string gets 4-byte aligned by coincidence. – TearfulSetWindowText()
still returns success, though. Tested on fully updated Windows Server 2019 – SauryWC_BUTTONW
instead ofWC_BUTTON
– Entwistlereinterpret_cast<wchar_t*>(&buffer[1])
aligned as 2? Why it works on x86 but x64. – DavisonSetWindowText()
I was asking if the alignment was officially documented somewhere. Someone mentioned "Using the Windows Headers" in a deleted answer, but there was surprisingly large confusion over the alignment of characters in structures vs. the alignment of strings on the stack. Hence I only answered after finding theCHARFORMATW
precedent – SauryUNALIGNED
macro implies that alignment is assumed by default. It is so obvious that nobody thought to write it down. Like "where did it say that when I pass a pointer, it has to be a valid pointer?" – HaarUNALIGNED
macro yet, so feel free to further edit my answer. – Saury