xref: /aosp_15_r20/external/lzma/CPP/Windows/Menu.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Windows/Menu.cpp
2 
3 #include "StdAfx.h"
4 
5 #ifndef _UNICODE
6 #include "../Common/StringConvert.h"
7 #endif
8 #include "Menu.h"
9 
10 #ifndef _UNICODE
11 extern bool g_IsNT;
12 #endif
13 
14 namespace NWindows {
15 
16 /*
17 structures
18   MENUITEMINFOA
19   MENUITEMINFOW
20 contain additional member:
21   #if (WINVER >= 0x0500)
22     HBITMAP hbmpItem;
23   #endif
24 If we compile the source code with (WINVER >= 0x0500), some functions
25 will not work at NT4, if cbSize is set as sizeof(MENUITEMINFO).
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 */
42 
43 #if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500)
44   #ifndef _UNICODE
45   #define my_compatib_MENUITEMINFOA_size  sizeof(MENUITEMINFOA)
46   #endif
47   #define my_compatib_MENUITEMINFOW_size  sizeof(MENUITEMINFOW)
48 #else
49   #define MY_STRUCT_SIZE_BEFORE(structname, member) ((UINT)(UINT_PTR)((LPBYTE)(&((structname*)0)->member) - (LPBYTE)(structname*)0))
50   #ifndef _UNICODE
51   #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem)
52   #endif
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"
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)  \
73 
ConvertItemToSysForm(const CMenuItem & item,MENUITEMINFOW & si)74 static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si)
75 {
76   ZeroMemory(&si, sizeof(si));
77   si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si);
78   COPY_MENUITEM_fields(si, item)
79 }
80 
81 #ifndef _UNICODE
ConvertItemToSysForm(const CMenuItem & item,MENUITEMINFOA & si)82 static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si)
83 {
84   ZeroMemory(&si, sizeof(si));
85   si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si);
86   COPY_MENUITEM_fields(si, item)
87 }
88 #endif
89 
ConvertItemToMyForm(const MENUITEMINFOW & si,CMenuItem & item)90 static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item)
91 {
92   COPY_MENUITEM_fields(item, si)
93 }
94 
95 #ifndef _UNICODE
ConvertItemToMyForm(const MENUITEMINFOA & si,CMenuItem & item)96 static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item)
97 {
98   COPY_MENUITEM_fields(item, si)
99 }
100 #endif
101 
102 
GetItem(UINT itemIndex,bool byPosition,CMenuItem & item) const103 bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const
104 {
105   item.StringValue.Empty();
106   const unsigned kMaxSize = 512;
107   #ifndef _UNICODE
108   if (!g_IsNT)
109   {
110     MENUITEMINFOA si;
111     ConvertItemToSysForm(item, si);
112     const bool isString = item.IsString();
113     unsigned bufSize = kMaxSize;
114     AString a;
115     if (isString)
116     {
117       si.cch = bufSize;
118       si.dwTypeData = a.GetBuf(bufSize);
119     }
120     bool res = GetItemInfo(itemIndex, byPosition, &si);
121     if (isString)
122       a.ReleaseBuf_CalcLen(bufSize);
123     if (!res)
124       return false;
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       }
140       ConvertItemToMyForm(si, item);
141       if (isString)
142         item.StringValue = GetUnicodeString(a);
143       return true;
144     }
145   }
146   else
147   #endif
148   {
149     wchar_t s[kMaxSize + 1];
150     s[0] = 0;
151     MENUITEMINFOW si;
152     ConvertItemToSysForm(item, si);
153     const bool isString = item.IsString();
154     unsigned bufSize = kMaxSize;
155     if (isString)
156     {
157       si.cch = bufSize;
158       si.dwTypeData = s;
159     }
160     bool res = GetItemInfo(itemIndex, byPosition, &si);
161     if (!res)
162       return false;
163     if (isString)
164     {
165       s[Z7_ARRAY_SIZE(s) - 1] = 0;
166       item.StringValue = s;
167       if (si.cch >= bufSize - 1)
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
182     }
183     ConvertItemToMyForm(si, item);
184     return true;
185   }
186 }
187 
188 
SetItem(UINT itemIndex,bool byPosition,const CMenuItem & item)189 bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item)
190 {
191   #ifndef _UNICODE
192   if (!g_IsNT)
193   {
194     MENUITEMINFOA si;
195     ConvertItemToSysForm(item, si);
196     AString s;
197     if (item.IsString())
198     {
199       s = GetSystemString(item.StringValue);
200       si.dwTypeData = s.Ptr_non_const();
201     }
202     return SetItemInfo(itemIndex, byPosition, &si);
203   }
204   else
205   #endif
206   {
207     MENUITEMINFOW si;
208     ConvertItemToSysForm(item, si);
209     if (item.IsString())
210       si.dwTypeData = item.StringValue.Ptr_non_const();
211     return SetItemInfo(itemIndex, byPosition, &si);
212   }
213 }
214 
215 
InsertItem(UINT itemIndex,bool byPosition,const CMenuItem & item)216 bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item)
217 {
218   #ifndef _UNICODE
219   if (!g_IsNT)
220   {
221     MENUITEMINFOA si;
222     ConvertItemToSysForm(item, si);
223     AString s;
224     if (item.IsString())
225     {
226       s = GetSystemString(item.StringValue);
227       si.dwTypeData = s.Ptr_non_const();
228     }
229     return InsertItem(itemIndex, byPosition, &si);
230   }
231   else
232   #endif
233   {
234     MENUITEMINFOW si;
235     ConvertItemToSysForm(item, si);
236     if (item.IsString())
237       si.dwTypeData = item.StringValue.Ptr_non_const();
238     #ifdef UNDER_CE
239     UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING;
240     UINT_PTR id = item.wID;
241     if ((item.fMask & MIIM_SUBMENU) != 0)
242     {
243       flags |= MF_POPUP;
244       id = (UINT_PTR)item.hSubMenu;
245     }
246     if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue))
247       return false;
248     return SetItemInfo(itemIndex, byPosition, &si);
249     #else
250     return InsertItem(itemIndex, byPosition, &si);
251     #endif
252   }
253 }
254 
255 #ifndef _UNICODE
AppendItem(UINT flags,UINT_PTR newItemID,LPCWSTR newItem)256 bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem)
257 {
258   if (g_IsNT)
259     return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem));
260   else
261     return AppendItem(flags, newItemID, GetSystemString(newItem));
262 }
263 #endif
264 
265 }
266