diff options
Diffstat (limited to '')
-rw-r--r-- | CPP/Windows/Menu.cpp | 155 |
1 files changed, 102 insertions, 53 deletions
diff --git a/CPP/Windows/Menu.cpp b/CPP/Windows/Menu.cpp index 3ad6953..af54c66 100644 --- a/CPP/Windows/Menu.cpp +++ b/CPP/Windows/Menu.cpp | |||
@@ -22,8 +22,23 @@ contain additional member: | |||
22 | HBITMAP hbmpItem; | 22 | HBITMAP hbmpItem; |
23 | #endif | 23 | #endif |
24 | If we compile the source code with (WINVER >= 0x0500), some functions | 24 | If we compile the source code with (WINVER >= 0x0500), some functions |
25 | will not work at NT 4.0, if cbSize is set as sizeof(MENUITEMINFO*). | 25 | will not work at NT4, if cbSize is set as sizeof(MENUITEMINFO). |
26 | So we use size of old version of structure. */ | 26 | So we use size of old version of structure in some conditions. |
27 | Win98 probably supports full structure including hbmpItem. | ||
28 | |||
29 | We have 2 ways to get/set string in menu item: | ||
30 | win95/NT4: we must use MIIM_TYPE only. | ||
31 | MIIM_TYPE : Retrieves or sets the fType and dwTypeData members. | ||
32 | win98/win2000: there are new flags that can be used instead of MIIM_TYPE: | ||
33 | MIIM_FTYPE : Retrieves or sets the fType member. | ||
34 | MIIM_STRING : Retrieves or sets the dwTypeData member. | ||
35 | |||
36 | Windows versions probably support MIIM_TYPE flag, if we set MENUITEMINFO::cbSize | ||
37 | as sizeof of old (small) MENUITEMINFO that doesn't include (hbmpItem) field. | ||
38 | But do all Windows versions support old MIIM_TYPE flag, if we use | ||
39 | MENUITEMINFO::cbSize as sizeof of new (big) MENUITEMINFO including (hbmpItem) field ? | ||
40 | win10 probably supports any combination of small/big (cbSize) and old/new MIIM_TYPE/MIIM_STRING. | ||
41 | */ | ||
27 | 42 | ||
28 | #if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500) | 43 | #if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500) |
29 | #ifndef _UNICODE | 44 | #ifndef _UNICODE |
@@ -36,20 +51,31 @@ So we use size of old version of structure. */ | |||
36 | #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem) | 51 | #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem) |
37 | #endif | 52 | #endif |
38 | #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem) | 53 | #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem) |
54 | #if defined(__clang__) && __clang_major__ >= 13 | ||
55 | // error : performing pointer subtraction with a null pointer may have undefined behavior | ||
56 | #pragma GCC diagnostic ignored "-Wnull-pointer-subtraction" | ||
39 | #endif | 57 | #endif |
58 | #endif | ||
59 | |||
60 | |||
61 | #define COPY_MENUITEM_field(d, s, name) \ | ||
62 | d.name = s.name; | ||
63 | |||
64 | #define COPY_MENUITEM_fields(d, s) \ | ||
65 | COPY_MENUITEM_field(d, s, fMask) \ | ||
66 | COPY_MENUITEM_field(d, s, fType) \ | ||
67 | COPY_MENUITEM_field(d, s, fState) \ | ||
68 | COPY_MENUITEM_field(d, s, wID) \ | ||
69 | COPY_MENUITEM_field(d, s, hSubMenu) \ | ||
70 | COPY_MENUITEM_field(d, s, hbmpChecked) \ | ||
71 | COPY_MENUITEM_field(d, s, hbmpUnchecked) \ | ||
72 | COPY_MENUITEM_field(d, s, dwItemData) \ | ||
40 | 73 | ||
41 | static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si) | 74 | static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si) |
42 | { | 75 | { |
43 | ZeroMemory(&si, sizeof(si)); | 76 | ZeroMemory(&si, sizeof(si)); |
44 | si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si); | 77 | si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si); |
45 | si.fMask = item.fMask; | 78 | COPY_MENUITEM_fields(si, item) |
46 | si.fType = item.fType; | ||
47 | si.fState = item.fState; | ||
48 | si.wID = item.wID; | ||
49 | si.hSubMenu = item.hSubMenu; | ||
50 | si.hbmpChecked = item.hbmpChecked; | ||
51 | si.hbmpUnchecked = item.hbmpUnchecked; | ||
52 | si.dwItemData = item.dwItemData; | ||
53 | } | 79 | } |
54 | 80 | ||
55 | #ifndef _UNICODE | 81 | #ifndef _UNICODE |
@@ -57,62 +83,63 @@ static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si) | |||
57 | { | 83 | { |
58 | ZeroMemory(&si, sizeof(si)); | 84 | ZeroMemory(&si, sizeof(si)); |
59 | si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si); | 85 | si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si); |
60 | si.fMask = item.fMask; | 86 | COPY_MENUITEM_fields(si, item) |
61 | si.fType = item.fType; | ||
62 | si.fState = item.fState; | ||
63 | si.wID = item.wID; | ||
64 | si.hSubMenu = item.hSubMenu; | ||
65 | si.hbmpChecked = item.hbmpChecked; | ||
66 | si.hbmpUnchecked = item.hbmpUnchecked; | ||
67 | si.dwItemData = item.dwItemData; | ||
68 | } | 87 | } |
69 | #endif | 88 | #endif |
70 | 89 | ||
71 | static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item) | 90 | static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item) |
72 | { | 91 | { |
73 | item.fMask = si.fMask; | 92 | COPY_MENUITEM_fields(item, si) |
74 | item.fType = si.fType; | ||
75 | item.fState = si.fState; | ||
76 | item.wID = si.wID; | ||
77 | item.hSubMenu = si.hSubMenu; | ||
78 | item.hbmpChecked = si.hbmpChecked; | ||
79 | item.hbmpUnchecked = si.hbmpUnchecked; | ||
80 | item.dwItemData = si.dwItemData; | ||
81 | } | 93 | } |
82 | 94 | ||
83 | #ifndef _UNICODE | 95 | #ifndef _UNICODE |
84 | static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item) | 96 | static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item) |
85 | { | 97 | { |
86 | item.fMask = si.fMask; | 98 | COPY_MENUITEM_fields(item, si) |
87 | item.fType = si.fType; | ||
88 | item.fState = si.fState; | ||
89 | item.wID = si.wID; | ||
90 | item.hSubMenu = si.hSubMenu; | ||
91 | item.hbmpChecked = si.hbmpChecked; | ||
92 | item.hbmpUnchecked = si.hbmpUnchecked; | ||
93 | item.dwItemData = si.dwItemData; | ||
94 | } | 99 | } |
95 | #endif | 100 | #endif |
96 | 101 | ||
97 | bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) | 102 | |
103 | bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const | ||
98 | { | 104 | { |
99 | const UINT kMaxSize = 512; | 105 | item.StringValue.Empty(); |
106 | const unsigned kMaxSize = 512; | ||
100 | #ifndef _UNICODE | 107 | #ifndef _UNICODE |
101 | if (!g_IsNT) | 108 | if (!g_IsNT) |
102 | { | 109 | { |
103 | CHAR s[kMaxSize + 1]; | ||
104 | MENUITEMINFOA si; | 110 | MENUITEMINFOA si; |
105 | ConvertItemToSysForm(item, si); | 111 | ConvertItemToSysForm(item, si); |
106 | if (item.IsString()) | 112 | const bool isString = item.IsString(); |
113 | unsigned bufSize = kMaxSize; | ||
114 | AString a; | ||
115 | if (isString) | ||
107 | { | 116 | { |
108 | si.cch = kMaxSize; | 117 | si.cch = bufSize; |
109 | si.dwTypeData = s; | 118 | si.dwTypeData = a.GetBuf(bufSize); |
110 | } | 119 | } |
111 | if (GetItemInfo(itemIndex, byPosition, &si)) | 120 | bool res = GetItemInfo(itemIndex, byPosition, &si); |
121 | if (isString) | ||
122 | a.ReleaseBuf_CalcLen(bufSize); | ||
123 | if (!res) | ||
124 | return false; | ||
112 | { | 125 | { |
126 | if (isString && si.cch >= bufSize - 1) | ||
127 | { | ||
128 | si.dwTypeData = NULL; | ||
129 | res = GetItemInfo(itemIndex, byPosition, &si); | ||
130 | if (!res) | ||
131 | return false; | ||
132 | si.cch++; | ||
133 | bufSize = si.cch; | ||
134 | si.dwTypeData = a.GetBuf(bufSize); | ||
135 | res = GetItemInfo(itemIndex, byPosition, &si); | ||
136 | a.ReleaseBuf_CalcLen(bufSize); | ||
137 | if (!res) | ||
138 | return false; | ||
139 | } | ||
113 | ConvertItemToMyForm(si, item); | 140 | ConvertItemToMyForm(si, item); |
114 | if (item.IsString()) | 141 | if (isString) |
115 | item.StringValue = GetUnicodeString(s); | 142 | item.StringValue = GetUnicodeString(a); |
116 | return true; | 143 | return true; |
117 | } | 144 | } |
118 | } | 145 | } |
@@ -120,24 +147,45 @@ bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) | |||
120 | #endif | 147 | #endif |
121 | { | 148 | { |
122 | wchar_t s[kMaxSize + 1]; | 149 | wchar_t s[kMaxSize + 1]; |
150 | s[0] = 0; | ||
123 | MENUITEMINFOW si; | 151 | MENUITEMINFOW si; |
124 | ConvertItemToSysForm(item, si); | 152 | ConvertItemToSysForm(item, si); |
125 | if (item.IsString()) | 153 | const bool isString = item.IsString(); |
154 | unsigned bufSize = kMaxSize; | ||
155 | if (isString) | ||
126 | { | 156 | { |
127 | si.cch = kMaxSize; | 157 | si.cch = bufSize; |
128 | si.dwTypeData = s; | 158 | si.dwTypeData = s; |
129 | } | 159 | } |
130 | if (GetItemInfo(itemIndex, byPosition, &si)) | 160 | bool res = GetItemInfo(itemIndex, byPosition, &si); |
161 | if (!res) | ||
162 | return false; | ||
163 | if (isString) | ||
131 | { | 164 | { |
132 | ConvertItemToMyForm(si, item); | 165 | s[Z7_ARRAY_SIZE(s) - 1] = 0; |
133 | if (item.IsString()) | 166 | item.StringValue = s; |
134 | item.StringValue = s; | 167 | if (si.cch >= bufSize - 1) |
135 | return true; | 168 | { |
169 | si.dwTypeData = NULL; | ||
170 | res = GetItemInfo(itemIndex, byPosition, &si); | ||
171 | if (!res) | ||
172 | return false; | ||
173 | si.cch++; | ||
174 | bufSize = si.cch; | ||
175 | si.dwTypeData = item.StringValue.GetBuf(bufSize); | ||
176 | res = GetItemInfo(itemIndex, byPosition, &si); | ||
177 | item.StringValue.ReleaseBuf_CalcLen(bufSize); | ||
178 | if (!res) | ||
179 | return false; | ||
180 | } | ||
181 | // if (item.StringValue.Len() != si.cch) throw 123; // for debug | ||
136 | } | 182 | } |
183 | ConvertItemToMyForm(si, item); | ||
184 | return true; | ||
137 | } | 185 | } |
138 | return false; | ||
139 | } | 186 | } |
140 | 187 | ||
188 | |||
141 | bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) | 189 | bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) |
142 | { | 190 | { |
143 | #ifndef _UNICODE | 191 | #ifndef _UNICODE |
@@ -164,6 +212,7 @@ bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) | |||
164 | } | 212 | } |
165 | } | 213 | } |
166 | 214 | ||
215 | |||
167 | bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) | 216 | bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) |
168 | { | 217 | { |
169 | #ifndef _UNICODE | 218 | #ifndef _UNICODE |
@@ -188,11 +237,11 @@ bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) | |||
188 | si.dwTypeData = item.StringValue.Ptr_non_const(); | 237 | si.dwTypeData = item.StringValue.Ptr_non_const(); |
189 | #ifdef UNDER_CE | 238 | #ifdef UNDER_CE |
190 | UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING; | 239 | UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING; |
191 | UINT id = item.wID; | 240 | UINT_PTR id = item.wID; |
192 | if ((item.fMask & MIIM_SUBMENU) != 0) | 241 | if ((item.fMask & MIIM_SUBMENU) != 0) |
193 | { | 242 | { |
194 | flags |= MF_POPUP; | 243 | flags |= MF_POPUP; |
195 | id = (UINT)item.hSubMenu; | 244 | id = (UINT_PTR)item.hSubMenu; |
196 | } | 245 | } |
197 | if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue)) | 246 | if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue)) |
198 | return false; | 247 | return false; |