Win32 Wide-Character String Alignment Requirements

322 views Asked by At

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;
}
1

There are 1 answers

0
Krishty On

Win32 Wide Character string alignment is two bytes.

The article Using the Windows Headers contains a section Controlling Structure Packing that interlocks Win32 type alignment with that of a C compiler. This boils down to two-byte alignment for wide-character strings.

The discussion linked in the question does not apply because it is about BSTRs. These have a different memory layout from wide-character strings.

The SetWindowTextW() problem is me hitting unspecified behavior because I violated a fundamental API rule by passing unaligned data.

Aside from documentation, you can find places in the Windows headers that set the precedent. The CHARFORMATW structure, for example, is four-byte aligned but contains a two-byte aligned wide-character string.