Code:
auto pMenuEdit = GetCongregationSubMenu(1);
if (pMenuEdit != nullptr)
{
const int iSize = pMenuEdit->GetMenuItemCount();
for (int i = 0; i < iSize; i++)
{
CString strMenuText;
MENUITEMINFO sInfo{};
sInfo.cbSize = sizeof(MENUITEMINFO);
sInfo.fMask = MIIM_STRING | MIIM_ID;
sInfo.dwTypeData = strMenuText.GetBuffer();
GetMenuItemInfo(pMenuEdit->GetSafeHmenu(), i, TRUE, &sInfo);
strMenuText.ReleaseBuffer();
if (strMenuText == strCongregation)
{
// Simulate pressing the Edit Congregation menu item
PostMessage(WM_COMMAND, sInfo.wID);
break;
}
pMenuEdit->GetMenuString(i, strMenuText, MF_BYPOSITION);
if (strMenuText == strCongregation)
{
// Simulate pressing the Edit Congregation menu item
PostMessage(WM_COMMAND, sInfo.wID);
break;
}
}
}
Why is it that the pMenuEdit->GetMenuString(i, strMenuText, MF_BYPOSITION);
approach works correctly but the GetMenuItemInfo(pMenuEdit->GetSafeHmenu(), i, TRUE, &sInfo);
approach does not? According to the debugger the text is empty.
The Microsoft documentation encourage using GetMenuItemInfo
instead of GetMenuString
.
My mistake?
Text buffers in C always consist of two parts: A pointer to the beginning of the buffer and a count (in elements or bytes). The code in question never supplies a value for the cch
field of the MENUITEMINFO
structure.
Solving this will still cause the code to fail to retrieve the menu item text because the strMenuText
buffer is empty. You also must allocate sufficient space (e.g., by supplying a buffer size in the call to CString::GetBuffer()
).
The standard pattern is to discover the required length first:
MENUITEMINFO sInfo{};
sInfo.cbSize = sizeof(MENUITEMINFO);
sInfo.fMask = MIIM_STRING | MIIM_ID;
if (!GetMenuItemInfo(pMenuEdit->GetSafeHmenu(), i, TRUE, &sInfo)) {
// Handle error
}
UINT const required_length = sInfo.cch;
and use that information to allocate a sufficiently sized buffer:
CString strMenuText;
sInfo.dwTypeData = strMenuText.GetBuffer(required_length);
sInfo.cch = required_length + 1;
if (!GetMenuItemInfo(pMenuEdit->GetSafeHmenu(), i, TRUE, &sInfo)) {
// Handle error
}
strMenuText.ReleaseBufferSetLength(sInfo.cch);