Fix ERROR_HWNDS_HAVE_DIFF_PARENT 0x000005A1
All window handles passed to a multiple-window position function must share the same parent window. This error fires when they don't. Here's why it happens and how to fix it.
When this error hits
You're calling DeferWindowPos or EndDeferWindowPos, and you've passed a set of HWNDs (window handles) that were created by different parent windows. The system expects all child windows in a single HDWP (handle to a deferred window position structure) to belong to the exact same parent. If you mix children from two different parent windows, you get ERROR_HWNDS_HAVE_DIFF_PARENT (0x000005A1).
This typically happens in custom dialog managers, multi-tabbed interfaces, or any code that repositions multiple child windows at once — but not all of them share a parent. I've seen it most often when someone builds a list of controls to reposition, and accidentally includes a child from a nested panel alongside one from the main dialog.
Why it happens
The BeginDeferWindowPos / DeferWindowPos / EndDeferWindowPos trio is an optimization. You batch up resize/move operations for multiple windows, then apply them all at once to reduce flicker. The API requires that every window you pass into the same batch shares one parent. That's a design constraint — the system sorts and applies the changes based on Z-order within a single parent. If you try to mix parents, it can't sort them correctly, so it bails out with this error.
It's not a corrupt handle or a permissions issue. It's purely a programmer mistake: you're passing a window that belongs to parent A and another that belongs to parent B into the same HDWP.
How to fix it
- Identify the mixed parents. Log the parent HWND of every window you're adding. Use
GetParent(hWnd)for each one. If you get two different parent handles, that's the culprit. - Separate into separate batches. Call
BeginDeferWindowPosonce for each unique parent. Add only that parent's children to its own batch. Then callEndDeferWindowPosper batch. - Refactor your code. If you're iterating a flat list of windows, group them by parent first. Something like:
// Pseudo-code — group by parent before batching
std::map<HWND, std::vector<HWND>> groups;
for (HWND hwnd : allWindows) {
HWND parent = GetParent(hwnd);
groups[parent].push_back(hwnd);
}
for (auto& [parent, children] : groups) {
HDWP hdwp = BeginDeferWindowPos((int)children.size());
for (HWND child : children) {
DeferWindowPos(hdwp, child, ...);
}
EndDeferWindowPos(hdwp);
}
- Check for NULL parents. If a window has no parent (it's a top-level window),
GetParentreturns NULL. NULL counts as a valid "parent" for the purpose of batching. So mixing a top-level window with a child window will also trigger this error. Keep top-level windows in their own batch. - Verify after the fix. Run your code in a debug build with assertions. Add
assert(GetParent(hwnd1) == GetParent(hwnd2))before passing them to the same batch.
If it still fails
Check these three things:
- Are you using the same
HDWPacross threads? The handle is not thread-safe. Each thread needs its own batch. - Did a window get re-parented mid-batch? If you call
SetParentbetweenBeginDeferWindowPosandEndDeferWindowPos, the parent changes, and the batch becomes inconsistent. Don't reparent windows during a deferred operation. - Are you passing the window handle to the wrong function? Make sure you're not accidentally passing the parent itself as one of the children. The system expects only siblings, not the parent, in the list.
The fix is usually a one-line change: split your windows into two batches. But if you're still hitting it after that, run SPY++ (comes with Visual Studio) and inspect the parent chain of every window in your list. That'll show you exactly where the mismatch is.
Was this solution helpful?