Menüs ohne Resource Compiler
Verfasst: 24.05.2013, 20:58
Wer nicht Microsofts Resource Compiler benutzen möchte, um vordefinierte Menüs zu erzeugen, kann das durch LoadMenuIndirect() machen. Leider scheint die Funktion so gut wie garnicht dokumentiert zu sein, darum habe ich mir die nötigen Details aus diesem OldNewThing-Artikel zusammengekratzt und schreibe meine Ergebnisse hier:
static auto const menu =
EMPTY_MENUITEMTEMPLATEHEADER
NEXT_POPUP(L"first")
NEXT_STRING(0123, L"1st sub 0")
NEXT_STRING(0124, L"1st sub 1")
NEXT_SEPERATOR
LAST_POPUP(L"1st sub 2")
LAST_STRING(0125, L"sub sub 1")
NEXT_POPUP(L"second")
NEXT_STRING(0126, L"2nd sub 0")
LAST_STRING(0127, L"2nd sub 1")
LAST_STRING(0128, L"last")
;
SetMenu(hwnd, LoadMenuIndirectW((MENUTEMPLATEW*)menu));
erzeugt dieses Menü: Die dazu nötigen Präprozessordefinitionen:
Ich habe checked/unchecked (Häkchen vor Einträgen) der Einfachheit wegen weggelassen. Weil die Daten als String vorliegen, werden sie möglicherweise durch String Pooling gefaltet (was gut ist).
Nur mit Visual C++ 2012 getestet. Auf einigen Compilern wollt ihr vielleicht C++11s u""-Präfix statt L"" benutzen.
Viel Spaß!
static auto const menu =
EMPTY_MENUITEMTEMPLATEHEADER
NEXT_POPUP(L"first")
NEXT_STRING(0123, L"1st sub 0")
NEXT_STRING(0124, L"1st sub 1")
NEXT_SEPERATOR
LAST_POPUP(L"1st sub 2")
LAST_STRING(0125, L"sub sub 1")
NEXT_POPUP(L"second")
NEXT_STRING(0126, L"2nd sub 0")
LAST_STRING(0127, L"2nd sub 1")
LAST_STRING(0128, L"last")
;
SetMenu(hwnd, LoadMenuIndirectW((MENUTEMPLATEW*)menu));
erzeugt dieses Menü: Die dazu nötigen Präprozessordefinitionen:
Code: Alles auswählen
#define MAKE_UTF16_LITERAL(x) L###x
// Expresses an empty 'MENUITEMTEMPLATEHEADER' instance as a UTF-16 literal.
#define EMPTY_MENUITEMTEMPLATEHEADER L"\x0000\x0000"
// Expresses a string entry of the given hexadecimal ID (without the '0x' prefix) and the given name (with the 'L' prefix) as a
// UTF-16 literal.
#define NEXT_STRING(hexID_noPefix, title_UTF16Prefixd) L"\x0000" MAKE_UTF16_LITERAL(\x##hexID_noPefix) title_UTF16Prefixd L"\0"
#define LAST_STRING(hexID_noPefix, title_UTF16Prefixd) L"\x0080" MAKE_UTF16_LITERAL(\x##hexID_noPefix) title_UTF16Prefixd L"\0"
// Expresses a popup entry of the given name (with the 'L' prefix!) as a UTF-16 literal.
//
// "The other type of menu item template is the pop-up submenu.
//
// struct POPUPMENUITEM16 {
// WORD wFlags; // menu item flags (MFT_*, MFS_*)
// CHAR szText[]; // null terminated ANSI string
// };
//
// The pop-up item template doesn't have an ID, the MF_POPUP flag must be set in the flags (naturally), the MFS_HILITE
// flag must not be set, and it is immediately followed by... another menu resource, minus the resource header, which
// describes the pop-up submenu itself. (This is the recursive part.)"
// (http://blogs.msdn.com/b/oldnewthing/archive/2008/07/09/8711897.aspx)
#define NEXT_POPUP(title_UTF16Prefixd) L"\x0010" title_UTF16Prefixd L"\0"
#define LAST_POPUP(title_UTF16Prefixd) L"\x0090" title_UTF16Prefixd L"\0"
// Expresses a seperator as a UTF-16 literal.
//
// "The next item of the pop-up menu is a separator. If you have been following the rules strictly, you would generate the
// separator like this:
//
// 001D 00 08 // wFlags = MFT_SEPARATOR
// 001F 00 00 // wID = 0
// 0021 00 // ""
//
// However, it turns out that there is an alternate form for separators, namely to pass all zeroes:
//
// 001D 00 00 // wFlags = 0
// 001F 00 00 // wID = 0
// 0021 00 // ""
//
// The existence of this alternate form is actually an artifact of history, which we'll look at next time. But for now,
// just realize that you can express a separator in two different ways, either the official way with MFT_SEPARATOR or the
// alternate way with wFlags = 0. Either works just fine."
// (http://blogs.msdn.com/b/oldnewthing/archive/2008/07/09/8711897.aspx)
#define NEXT_SEPERATOR L"\x0000\x0000\x0000"
#define LAST_SEPERATOR L"\x0080\x0000\x0000"
Nur mit Visual C++ 2012 getestet. Auf einigen Compilern wollt ihr vielleicht C++11s u""-Präfix statt L"" benutzen.
Viel Spaß!