1 /*
2  * PROJECT:     ReactOS API Tests
3  * LICENSE:     MIT (https://spdx.org/licenses/MIT)
4  * PURPOSE:     Tests for VerQueryValue[A/W]
5  * COPYRIGHT:   Copyright 2024 Timo Kreuzer <timo.kreuzer@reactos.org>
6  */
7 
8 #include "precomp.h"
9 
10 typedef struct
11 {
12     WORD wLength;
13     WORD wValueLength;
14     WORD wType;
15     WCHAR szKey[16]; // L"VS_VERSION_INFO"
16     WORD Padding1;
17     VS_FIXEDFILEINFO Value;
18 
19     struct _StringFileInfo
20     {
21         WORD wLength;
22         WORD wValueLength;
23         WORD wType;
24         WCHAR szKey[15]; // L"StringFileInfo"
25 
26         struct _StringTable
27         {
28             WORD wLength;
29             WORD wValueLength;
30             WORD wType;
31             WCHAR szKey[9]; // L"000004B"
32 
33             struct _String_CompanyName
34             {
35                 WORD wLength;
36                 WORD wValueLength;
37                 WORD wType;
38                 WCHAR szKey[12]; // L"CompanyName"
39                 WORD Padding1;
40                 WCHAR Value[16]; // L"ReactOS Project"
41             } CompanyName;
42 
43             struct _String_Comments
44             {
45                 WORD wLength;
46                 WORD wValueLength; // 0
47                 WORD wType;
48                 WCHAR szKey[9]; // L"Comments"
49             } Comments;
50 
51             struct _String_Comments2
52             {
53                 WORD wLength;
54                 WORD wValueLength; // 0
55                 WORD wType;
56                 WCHAR szKey[10]; // L"Comments2"
57                 WORD Padding;
58             } Comments2;
59 
60             struct _String_FooBar
61             {
62                 WORD wLength;
63                 WORD wValueLength;
64                 WORD wType;
65                 WCHAR szKey[7]; // L"FooBar"
66                 WCHAR Value[4]; // L"Bar"
67             } FooBar;
68 
69         } StringTable;
70     } StringFileInfo;
71 } TEST_VERSIONINFO;
72 
73 static const TEST_VERSIONINFO g_VersionInfo =
74 {
75     .wLength = 298, // Header: 40, Value: 54, StringFileInfo: 204
76     .wValueLength = sizeof(VS_FIXEDFILEINFO),
77     .wType = 0,
78     .szKey = L"VS_VERSION_INFO",
79     .Padding1 = 0,
80     .Value =
81     {
82         .dwSignature = VS_FFI_SIGNATURE,
83         .dwStrucVersion = VS_FFI_STRUCVERSION,
84         .dwFileVersionMS = 0x00050002,
85         .dwFileVersionLS = 0x0ECE0000,
86         .dwProductVersionMS = 0x00050002,
87         .dwProductVersionLS = 0x0ECE0000,
88         .dwFileFlagsMask = 0x00000002,
89         .dwFileFlags = 0x00000000,
90         .dwFileOS = VOS__WINDOWS32,
91         .dwFileType = VFT_APP,
92         .dwFileSubtype = VFT2_UNKNOWN,
93         .dwFileDateMS = 0x00020074,
94         .dwFileDateLS = 0x00000000,
95     },
96     .StringFileInfo =
97     {
98         .wLength = 204, // Header: 36, StringTable: 168
99         .wValueLength = 0,
100         .wType = 1,
101         .szKey = L"StringFileInfo",
102         .StringTable =
103         {
104             .wLength = 168, //Header: 24, Children: 144
105             .wValueLength = 0,
106             .wType = 1,
107             .szKey = L"000004B0",
108 
109             .CompanyName =
110             {
111                 .wLength = 64,
112                 .wValueLength = 16,
113                 .wType = 1,
114                 .szKey = L"CompanyName",
115                 .Padding1 = 0,
116                 .Value = L"ReactOS Project",
117             },
118             .Comments =
119             {
120                 .wLength = 24,
121                 .wValueLength = 0,
122                 .wType = 1,
123                 .szKey = L"Comments",
124             },
125             .Comments2 =
126             {
127                 .wLength = 28,
128                 .wValueLength = 0,
129                 .wType = 1,
130                 .szKey = L"Comments2",
131                 .Padding = 0xCC,
132             },
133             .FooBar =
134             {
135                 .wLength = 28,
136                 .wValueLength = 4,
137                 .wType = 1,
138                 .szKey = L"FooBar",
139                 .Value = L"Bar",
140             },
141         },
142     },
143 };
144 
145 void
146 Test_VerQueryValueA(void)
147 {
148     DWORD dwVersionInfoSizeW, dwVersionInfoSizeA;
149     PVOID pvVersionInfoA, pvData = NULL;
150     CHAR szSubBlock[256];
151     USHORT uLanguage, uCodePage;
152     UINT cbLen;
153     BOOL result;
154 
155     /* Get the size for the unicode version info */
156     dwVersionInfoSizeW = GetFileVersionInfoSizeW(L"kernel32.dll", NULL);
157     ok(dwVersionInfoSizeW > 0, "GetFileVersionInfoSizeW failed\n");
158 
159     /* Get the size for the ANSI version info */
160     dwVersionInfoSizeA = GetFileVersionInfoSizeA("kernel32.dll", NULL);
161     ok(dwVersionInfoSizeA > 0, "GetFileVersionInfoSizeA failed\n");
162     ok(dwVersionInfoSizeA == dwVersionInfoSizeW, "Unexpected size\n");
163 
164     /* Get the ANSI version info from kernel32 */
165     pvVersionInfoA = malloc(dwVersionInfoSizeA);
166     memset(pvVersionInfoA, 0xCC, dwVersionInfoSizeA);
167     result = GetFileVersionInfoA("kernel32.dll", 0, dwVersionInfoSizeA, pvVersionInfoA);
168     ok(result, "GetFileVersionInfoA failed\n");
169 
170     /* Query available translations */
171     result = VerQueryValueA(pvVersionInfoA,
172                             "\\VarFileInfo\\Translation",
173                             &pvData,
174                             &cbLen);
175     ok(result, "VerQueryValueA failed\n");
176     ok(cbLen >= 4, "Unexpected value\n");
177     ok((cbLen & 0x3) == 0, "Unexpected value\n");
178     uLanguage = ((USHORT*)pvData)[0];
179     uCodePage = ((USHORT*)pvData)[1];
180 
181     /* Query sublock */
182     sprintf(szSubBlock, "\\StringFileInfo\\%04X%04X\\CompanyName", uLanguage, uCodePage);
183     result = VerQueryValueA(pvVersionInfoA,
184                             szSubBlock,
185                             &pvData,
186                             &cbLen);
187     ok(result, "VerQueryValueA failed\n");
188     ok(cbLen >= 2, "Unexpected value\n");
189     ok((cbLen & 0x1) == 0, "Unexpected value\n");
190 
191     free(pvVersionInfoA);
192 }
193 
194 void
195 Test_VerQueryValueW(void)
196 {
197     DWORD dwVersionInfoSizeW;
198     PVOID pvVersionInfoW, pvData = NULL;
199     WCHAR szSubBlock[256];
200     USHORT uLanguage, uCodePage;
201     UINT cbLen;
202     BOOL result;
203 
204     /* Get the size for the unicode version info */
205     dwVersionInfoSizeW = GetFileVersionInfoSizeW(L"kernel32.dll", NULL);
206     ok(dwVersionInfoSizeW > 0, "GetFileVersionInfoSizeW failed\n");
207 
208     /* Get the unicode version info from kernel32 */
209     pvVersionInfoW = malloc(dwVersionInfoSizeW);
210     result = GetFileVersionInfoW(L"kernel32.dll", 0, dwVersionInfoSizeW, pvVersionInfoW);
211     ok(result, "GetFileVersionInfoW failed\n");
212 
213     /* Query available translations */
214     result = VerQueryValueW(pvVersionInfoW,
215                             L"\\VarFileInfo\\Translation",
216                             &pvData,
217                             &cbLen);
218     ok(result, "VerQueryValueA failed\n");
219     ok(cbLen >= 4, "Unexpected value\n");
220     ok((cbLen & 0x3) == 0, "Unexpected value\n");
221     uLanguage = ((USHORT*)pvData)[0];
222     uCodePage = ((USHORT*)pvData)[1];
223 
224     /* Query sublock */
225     _swprintf(szSubBlock, L"\\StringFileInfo\\%04X%04X\\CompanyName", uLanguage, uCodePage);
226     result = VerQueryValueW(pvVersionInfoW,
227                             szSubBlock,
228                             &pvData,
229                             &cbLen);
230     ok(result, "VerQueryValueA failed\n");
231     ok(cbLen >= 2, "Unexpected value\n");
232     ok((cbLen & 0x1) == 0, "Unexpected value\n");
233 
234     free(pvVersionInfoW);
235 }
236 
237 void
238 Test_StaticVersionInfo(void)
239 {
240     PVOID pVersionInfo;
241     PVOID pvData = NULL;
242     SIZE_T ExpectedOffset;
243     UINT cbLen;
244     BOOL result;
245 
246     /* Make a copy of the version info. Windows actually writes to it!
247        We make the buffer twice as big to account for the ANSI copy,
248        even if we don't use it. */
249     pVersionInfo = malloc(2 * sizeof(g_VersionInfo));
250     memset(pVersionInfo, 0, 2 * sizeof(g_VersionInfo));
251     memcpy(pVersionInfo, &g_VersionInfo, sizeof(g_VersionInfo));
252 
253     /* Test a special static version */
254     result = VerQueryValueW(pVersionInfo,
255                             L"\\StringFileInfo\\000004B0\\CompanyName",
256                             &pvData,
257                             &cbLen);
258     ok(result, "VerQueryValueW failed\n");
259     ok_eq_int(cbLen, 16);
260     ok_eq_wstr((WCHAR*)pvData, L"ReactOS Project");
261     ExpectedOffset = FIELD_OFFSET(TEST_VERSIONINFO, StringFileInfo.StringTable.CompanyName.Value);
262     ok(pvData == (PVOID)((ULONG_PTR)pVersionInfo + ExpectedOffset), "Unexpected offset\n");
263 
264     result = VerQueryValueW(pVersionInfo,
265                             L"\\StringFileInfo\\000004B0\\Comments",
266                             &pvData,
267                             &cbLen);
268     ok(result, "VerQueryValueW failed\n");
269     ok_eq_int(cbLen, 0);
270     ok_eq_wstr((WCHAR*)pvData, L"");
271     ExpectedOffset = FIELD_OFFSET(TEST_VERSIONINFO, StringFileInfo.StringTable.Comments.szKey[8]);
272     ok(pvData == (PVOID)((ULONG_PTR)pVersionInfo + ExpectedOffset), "Unexpected offset\n");
273 
274     result = VerQueryValueW(pVersionInfo,
275                             L"\\StringFileInfo\\000004B0\\Comments2",
276                             &pvData,
277                             &cbLen);
278     ok(result, "VerQueryValueW failed\n");
279     ok_eq_int(cbLen, 0);
280     ok_eq_wstr((WCHAR*)pvData, L"");
281     ExpectedOffset = FIELD_OFFSET(TEST_VERSIONINFO, StringFileInfo.StringTable.Comments2.szKey[9]);
282     ok(pvData == (PVOID)((ULONG_PTR)pVersionInfo + ExpectedOffset), "Unexpected offset\n");
283 
284     result = VerQueryValueW(pVersionInfo,
285                             L"\\StringFileInfo\\000004B0\\FooBar",
286                             &pvData,
287                             &cbLen);
288     ok(result, "VerQueryValueW failed\n");
289     ok_eq_int(cbLen, 4);
290     ok(wcscmp((WCHAR*)pvData, L"Bar") == 0, "Bar\n");
291     ExpectedOffset = FIELD_OFFSET(TEST_VERSIONINFO, StringFileInfo.StringTable.FooBar.Value);
292     ok(pvData == (PVOID)((ULONG_PTR)pVersionInfo + ExpectedOffset), "Unexpected offset\n");
293 
294     free(pVersionInfo);
295 }
296 
297 START_TEST(VerQueryValue)
298 {
299     Test_VerQueryValueA();
300     Test_VerQueryValueW();
301     Test_StaticVersionInfo();
302 }
303