1 /*
2  * PROJECT:     apphelp_apitest
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Misc apphelp tests
5  * COPYRIGHT:   Copyright 2012 Detlef Riekenberg
6  *              Copyright 2013 Mislav Blažević
7  *              Copyright 2015-2019 Mark Jansen (mark.jansen@reactos.org)
8  */
9 
10 #include <ntstatus.h>
11 #define WIN32_NO_STATUS
12 #include <windows.h>
13 #include <shlwapi.h>
14 #include <winnt.h>
15 #ifdef __REACTOS__
16 #include <ntndk.h>
17 #else
18 #include <winternl.h>
19 #endif
20 
21 #include <winerror.h>
22 #include <stdio.h>
23 #include <initguid.h>
24 #include <shlguid.h>
25 #include <shobjidl.h>
26 
27 #include <pseh/pseh2.h>
28 
29 #include "wine/test.h"
30 
31 #include "apphelp_apitest.h"
32 
33 
34 #define TAG_TYPE_MASK 0xF000
35 
36 #define TAG_TYPE_NULL 0x1000
37 #define TAG_TYPE_BYTE 0x2000
38 #define TAG_TYPE_WORD 0x3000
39 #define TAG_TYPE_DWORD 0x4000
40 #define TAG_TYPE_QWORD 0x5000
41 #define TAG_TYPE_STRINGREF 0x6000
42 #define TAG_TYPE_LIST 0x7000
43 #define TAG_TYPE_STRING 0x8000
44 #define TAG_TYPE_BINARY 0x9000
45 #define TAG_NULL 0x0
46 #define TAG_SIZE (0x1 | TAG_TYPE_DWORD)
47 #define TAG_CHECKSUM (0x3 | TAG_TYPE_DWORD)
48 #define TAG_MODULE_TYPE (0x6 | TAG_TYPE_DWORD)
49 #define TAG_VERDATEHI (0x7 | TAG_TYPE_DWORD)
50 #define TAG_VERDATELO (0x8 | TAG_TYPE_DWORD)
51 #define TAG_VERFILEOS (0x9 | TAG_TYPE_DWORD)
52 #define TAG_VERFILETYPE (0xA | TAG_TYPE_DWORD)
53 #define TAG_PE_CHECKSUM (0xB | TAG_TYPE_DWORD)
54 #define TAG_VER_LANGUAGE (0x12 | TAG_TYPE_DWORD)
55 #define TAG_LINKER_VERSION (0x1C | TAG_TYPE_DWORD)
56 #define TAG_LINK_DATE (0x1D | TAG_TYPE_DWORD)
57 #define TAG_UPTO_LINK_DATE (0x1E | TAG_TYPE_DWORD)
58 #define TAG_EXE_WRAPPER (0x31 | TAG_TYPE_DWORD)
59 #define TAG_BIN_FILE_VERSION (0x2 | TAG_TYPE_QWORD)
60 #define TAG_BIN_PRODUCT_VERSION (0x3 | TAG_TYPE_QWORD)
61 #define TAG_UPTO_BIN_PRODUCT_VERSION (0x6 | TAG_TYPE_QWORD)
62 #define TAG_UPTO_BIN_FILE_VERSION (0xD | TAG_TYPE_QWORD)
63 #define TAG_NAME (0x1 | TAG_TYPE_STRINGREF)
64 #define TAG_COMPANY_NAME (0x9 | TAG_TYPE_STRINGREF)
65 #define TAG_PRODUCT_NAME (0x10 | TAG_TYPE_STRINGREF)
66 #define TAG_PRODUCT_VERSION (0x11 | TAG_TYPE_STRINGREF)
67 #define TAG_FILE_DESCRIPTION (0x12 | TAG_TYPE_STRINGREF)
68 #define TAG_FILE_VERSION (0x13 | TAG_TYPE_STRINGREF)
69 #define TAG_ORIGINAL_FILENAME (0x14 | TAG_TYPE_STRINGREF)
70 #define TAG_INTERNAL_NAME (0x15 | TAG_TYPE_STRINGREF)
71 #define TAG_LEGAL_COPYRIGHT (0x16 | TAG_TYPE_STRINGREF)
72 #define TAG_16BIT_DESCRIPTION (0x17 | TAG_TYPE_STRINGREF)
73 #define TAG_16BIT_MODULE_NAME (0x20 | TAG_TYPE_STRINGREF)
74 #define TAG_EXPORT_NAME (0x24 | TAG_TYPE_STRINGREF)
75 
76 
77 #define ATTRIBUTE_AVAILABLE 0x1
78 #define ATTRIBUTE_FAILED 0x2
79 
80 typedef struct tagATTRINFO {
81   TAG   type;
82   DWORD flags;  /* ATTRIBUTE_AVAILABLE, ATTRIBUTE_FAILED */
83   union {
84     QWORD qwattr;
85     DWORD dwattr;
86     WCHAR *lpattr;
87   };
88 } ATTRINFO, *PATTRINFO;
89 
90 static HMODULE hdll;
91 static BOOL (WINAPI *pApphelpCheckShellObject)(REFCLSID, BOOL, ULONGLONG *);
92 static LPCWSTR (WINAPI *pSdbTagToString)(TAG tag);
93 static BOOL (WINAPI *pSdbGUIDToString)(REFGUID Guid, PWSTR GuidString, SIZE_T Length);
94 static BOOL (WINAPI *pSdbIsNullGUID)(REFGUID Guid);
95 static BOOL (WINAPI *pSdbGetStandardDatabaseGUID)(DWORD Flags, GUID* Guid);
96 static BOOL (WINAPI *pSdbGetFileAttributes)(LPCWSTR wszPath, PATTRINFO *ppAttrInfo, LPDWORD pdwAttrCount);
97 static BOOL (WINAPI *pSdbFreeFileAttributes)(PATTRINFO AttrInfo);
98 static HRESULT (WINAPI* pSdbGetAppPatchDir)(PVOID hsdb, LPWSTR path, DWORD size);
99 static DWORD g_AttrInfoSize;
100 
101 /* 'Known' database guids */
102 DEFINE_GUID(GUID_DATABASE_MSI,0xd8ff6d16,0x6a3a,0x468a,0x8b,0x44,0x01,0x71,0x4d,0xdc,0x49,0xea);
103 DEFINE_GUID(GUID_DATABASE_SHIM,0x11111111,0x1111,0x1111,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11);
104 DEFINE_GUID(GUID_DATABASE_DRIVERS,0xf9ab2228,0x3312,0x4a73,0xb6,0xf9,0x93,0x6d,0x70,0xe1,0x12,0xef);
105 
106 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
107 
108 DEFINE_GUID(test_Microsoft_Browser_Architecture, 0xa5e46e3a, 0x8849, 0x11d1, 0x9d, 0x8c, 0x00, 0xc0, 0x4f, 0xc9, 0x9d, 0x61);
109 DEFINE_GUID(test_UserAssist, 0xdd313e04, 0xfeff, 0x11d1, 0x8e, 0xcd, 0x00, 0x00, 0xf8, 0x7a, 0x47, 0x0c);
110 DEFINE_GUID(CLSID_InternetSecurityManager, 0x7b8a2d94, 0x0ac9, 0x11d1, 0x89, 0x6c, 0x00, 0xc0, 0x4f, 0xB6, 0xbf, 0xc4);
111 
112 static const CLSID * objects[] = {
113     &GUID_NULL,
114     /* used by IE */
115     &test_Microsoft_Browser_Architecture,
116     &CLSID_MenuBand,
117     &CLSID_ShellLink,
118     &CLSID_ShellWindows,
119     &CLSID_InternetSecurityManager,
120     &test_UserAssist,
121     (const CLSID *)NULL
122 };
123 
124 static void test_ApphelpCheckShellObject(void)
125 {
126     ULONGLONG flags;
127     BOOL res;
128     int i;
129 
130     if (!pApphelpCheckShellObject)
131     {
132         win_skip("ApphelpCheckShellObject not available\n");
133         return;
134     }
135 
136     for (i = 0; objects[i]; i++)
137     {
138         flags = 0xdeadbeef;
139         SetLastError(0xdeadbeef);
140         res = pApphelpCheckShellObject(objects[i], FALSE, &flags);
141         ok(res && (flags == 0), "%s 0: got %d and 0x%x%08x with 0x%x (expected TRUE and 0)\n",
142             wine_dbgstr_guid(objects[i]), res, (ULONG)(flags >> 32), (ULONG)flags, GetLastError());
143 
144         flags = 0xdeadbeef;
145         SetLastError(0xdeadbeef);
146         res = pApphelpCheckShellObject(objects[i], TRUE, &flags);
147         ok(res && (flags == 0), "%s 1: got %d and 0x%x%08x with 0x%x (expected TRUE and 0)\n",
148             wine_dbgstr_guid(objects[i]), res, (ULONG)(flags >> 32), (ULONG)flags, GetLastError());
149 
150     }
151 
152     /* NULL as pointer to flags is checked */
153     SetLastError(0xdeadbeef);
154     res = pApphelpCheckShellObject(&GUID_NULL, FALSE, NULL);
155     ok(res, "%s 0: got %d with 0x%x (expected != FALSE)\n", wine_dbgstr_guid(&GUID_NULL), res, GetLastError());
156 
157     /* NULL as CLSID* crash on Windows */
158     if (0)
159     {
160         flags = 0xdeadbeef;
161         SetLastError(0xdeadbeef);
162         res = pApphelpCheckShellObject(NULL, FALSE, &flags);
163         trace("NULL as CLSID*: got %d and 0x%x%08x with 0x%x\n", res, (ULONG)(flags >> 32), (ULONG)flags, GetLastError());
164     }
165 }
166 
167 static void test_SdbTagToString(void)
168 {
169     static const TAG invalid_values[] = {
170         1, TAG_TYPE_WORD, TAG_TYPE_MASK,
171         TAG_TYPE_DWORD | 0xFF,
172         TAG_TYPE_DWORD | (0x800 + 0xEE),
173         0x900, 0xFFFF, 0xDEAD, 0xBEEF
174     };
175     static const WCHAR invalid[] = {'I','n','v','a','l','i','d','T','a','g',0};
176     LPCWSTR ret;
177     WORD i;
178 
179     for (i = 0; i < 9; ++i)
180     {
181         ret = pSdbTagToString(invalid_values[i]);
182         ok(lstrcmpW(ret, invalid) == 0, "unexpected string %s, should be %s\n",
183            wine_dbgstr_w(ret), wine_dbgstr_w(invalid));
184     }
185 }
186 
187 static int strcmp_wa(LPCWSTR strw, const char *stra)
188 {
189     CHAR buf[512];
190     WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), 0, 0);
191     return lstrcmpA(buf, stra);
192 }
193 
194 void test_tag(TAG base, const char* names[], size_t upperlimit, int line)
195 {
196     TAG n;
197     for (n = 0; names[n]; ++n)
198     {
199         LPCWSTR tagstr = pSdbTagToString(base | n);
200         ok_(__FILE__, line + 2)(!strcmp_wa(tagstr, names[n]), "Got %s instead of '%s' for %x\n", wine_dbgstr_w(tagstr), names[n], base | n);
201     }
202     for (; n < upperlimit; ++n)
203     {
204         LPCWSTR tagstr = pSdbTagToString(base | n);
205         ok_(__FILE__, line + 2)(!strcmp_wa(tagstr, "InvalidTag"), "Got %s instead of 'InvalidTag' for %x\n", wine_dbgstr_w(tagstr), base | n);
206     }
207 }
208 
209 static struct
210 {
211     TAG base;
212     DWORD upper_limit;
213     DWORD line;
214     DWORD min_ver;
215     DWORD max_ver;
216     const char* tags[7*8];
217 } data[] = {
218     {
219         TAG_TYPE_NULL, 0x1000, __LINE__, WINVER_ANY, WINVER_2003,
220         {
221             "InvalidTag", "INCLUDE", "GENERAL", "MATCH_LOGIC_NOT", "APPLY_ALL_SHIMS", "USE_SERVICE_PACK_FILES", NULL
222         }
223     },
224     {
225         TAG_TYPE_NULL, 0x1000, __LINE__, WINVER_VISTA, WINVER_VISTA,
226         {
227             "InvalidTag", "INCLUDE", "GENERAL", "MATCH_LOGIC_NOT", "APPLY_ALL_SHIMS", "USE_SERVICE_PACK_FILES", "MITIGATION_OS", "BLOCK_UPGRADE",
228             "INCLUDEEXCLUDEDLL", NULL
229         }
230     },
231     {
232         TAG_TYPE_NULL, 0x1000, __LINE__, WINVER_WIN7, WINVER_ANY,
233         {
234             "InvalidTag", "INCLUDE", "GENERAL", "MATCH_LOGIC_NOT", "APPLY_ALL_SHIMS", "USE_SERVICE_PACK_FILES", "MITIGATION_OS", "BLOCK_UPGRADE",
235             "INCLUDEEXCLUDEDLL", "RAC_EVENT_OFF", "TELEMETRY_OFF", "SHIM_ENGINE_OFF", "LAYER_PROPAGATION_OFF", "REINSTALL_UPGRADE", NULL
236         }
237     },
238 
239     {
240         TAG_TYPE_BYTE, 0x1000, __LINE__, WINVER_ANY, WINVER_ANY,
241         {
242             "InvalidTag", NULL
243         }
244     },
245 
246     {
247         TAG_TYPE_WORD, 0x800, __LINE__, WINVER_ANY, WINVER_WIN7,
248         {
249             "InvalidTag", "MATCH_MODE", NULL
250         }
251     },
252     {
253         TAG_TYPE_WORD, 0x800, __LINE__, WINVER_WIN8, WINVER_ANY,
254         {
255             "InvalidTag", "MATCH_MODE", "QUIRK_COMPONENT_CODE_ID", "QUIRK_CODE_ID", NULL
256         }
257     },
258     {
259         TAG_TYPE_WORD | 0x800, 0x800, __LINE__, WINVER_ANY, WINVER_ANY,
260         {
261             "InvalidTag", "TAG", "INDEX_TAG", "INDEX_KEY", NULL
262         }
263     },
264 
265     {
266         TAG_TYPE_DWORD, 0x800, __LINE__, WINVER_ANY, WINVER_WINXP,
267         {
268             "InvalidTag", "SIZE", "OFFSET", "CHECKSUM", "SHIM_TAGID", "PATCH_TAGID", "MODULE_TYPE", "VERFILEDATEHI",
269             "VERFILEDATELO", "VERFILEOS", "VERFILETYPE", "PE_CHECKSUM", "PREVOSMAJORVERSION", "PREVOSMINORVERSION", "PREVOSPLATFORMID", "PREVOSBUILDNO",
270             "PROBLEM_SEVERITY", "APPHELP_LANGID", "VER_LANGUAGE", "InvalidTag", "ENGINE", "HTMLHELPID", "INDEXFLAGS", "FLAGS",
271             "VALUETYPE", "DATA_DWORD", "LAYER_TAGID", "MSI_TRANSFORM_TAGID", "LINKER_VERSION", "LINK_DATE", "UPTO_LINK_DATE", "OS_SERVICE_PACK",
272             "FLAG_TAGID", "RUNTIME_PLATFORM", "OS_SKU", NULL
273         }
274     },
275     {
276         TAG_TYPE_DWORD, 0x800, __LINE__, WINVER_2003, WINVER_2003,
277         {
278             "InvalidTag", "SIZE", "OFFSET", "CHECKSUM", "SHIM_TAGID", "PATCH_TAGID", "MODULE_TYPE", "VERFILEDATEHI",
279             "VERFILEDATELO", "VERFILEOS", "VERFILETYPE", "PE_CHECKSUM", "PREVOSMAJORVERSION", "PREVOSMINORVERSION", "PREVOSPLATFORMID", "PREVOSBUILDNO",
280             "PROBLEM_SEVERITY", "APPHELP_LANGID", "VER_LANGUAGE", "InvalidTag", "ENGINE", "HTMLHELPID", "INDEXFLAGS", "FLAGS",
281             "VALUETYPE", "DATA_DWORD", "LAYER_TAGID", "MSI_TRANSFORM_TAGID", "LINKER_VERSION", "LINK_DATE", "UPTO_LINK_DATE", "OS_SERVICE_PACK",
282             "FLAG_TAGID", "RUNTIME_PLATFORM", "OS_SKU", "OS_PLATFORM", NULL
283         }
284     },
285     {
286         TAG_TYPE_DWORD, 0x800, __LINE__, WINVER_VISTA, WINVER_VISTA,
287         {
288             "InvalidTag", "SIZE", "OFFSET", "CHECKSUM", "SHIM_TAGID", "PATCH_TAGID", "MODULE_TYPE", "VERDATEHI",
289             "VERDATELO", "VERFILEOS", "VERFILETYPE", "PE_CHECKSUM", "PREVOSMAJORVER", "PREVOSMINORVER", "PREVOSPLATFORMID", "PREVOSBUILDNO",
290             "PROBLEMSEVERITY", "LANGID", "VER_LANGUAGE", "InvalidTag", "ENGINE", "HTMLHELPID", "INDEX_FLAGS", "FLAGS",
291             "DATA_VALUETYPE", "DATA_DWORD", "LAYER_TAGID", "MSI_TRANSFORM_TAGID", "LINKER_VERSION", "LINK_DATE", "UPTO_LINK_DATE", "OS_SERVICE_PACK",
292             "FLAG_TAGID", "RUNTIME_PLATFORM", "OS_SKU", "OS_PLATFORM", "APP_NAME_RC_ID", "VENDOR_NAME_RC_ID", "SUMMARY_MSG_RC_ID", "VISTA_SKU",
293             NULL
294         }
295     },
296     {
297         TAG_TYPE_DWORD, 0x800, __LINE__, WINVER_WIN7, WINVER_ANY,
298         {
299             "InvalidTag", "SIZE", "OFFSET", "CHECKSUM", "SHIM_TAGID", "PATCH_TAGID", "MODULE_TYPE", "VERDATEHI",
300             "VERDATELO", "VERFILEOS", "VERFILETYPE", "PE_CHECKSUM", "PREVOSMAJORVER", "PREVOSMINORVER", "PREVOSPLATFORMID", "PREVOSBUILDNO",
301             "PROBLEMSEVERITY", "LANGID", "VER_LANGUAGE", "InvalidTag", "ENGINE", "HTMLHELPID", "INDEX_FLAGS", "FLAGS",
302             "DATA_VALUETYPE", "DATA_DWORD", "LAYER_TAGID", "MSI_TRANSFORM_TAGID", "LINKER_VERSION", "LINK_DATE", "UPTO_LINK_DATE", "OS_SERVICE_PACK",
303             "FLAG_TAGID", "RUNTIME_PLATFORM", "OS_SKU", "OS_PLATFORM", "APP_NAME_RC_ID", "VENDOR_NAME_RC_ID", "SUMMARY_MSG_RC_ID", "VISTA_SKU",
304             "DESCRIPTION_RC_ID", "PARAMETER1_RC_ID", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag",
305             "CONTEXT_TAGID", "EXE_WRAPPER", "URL_ID", NULL
306         }
307     },
308     {
309         TAG_TYPE_DWORD | 0x800, 0x800, __LINE__, WINVER_ANY, WINVER_ANY,
310         {
311             "InvalidTag", "TAGID", NULL
312         }
313     },
314 
315     {
316         TAG_TYPE_QWORD, 0x1000, __LINE__, WINVER_ANY, WINVER_WINXP,
317         {
318             "InvalidTag", "TIME", "BIN_FILE_VERSION", "BIN_PRODUCT_VERSION", "MODTIME", "FLAG_MASK_KERNEL", "UPTO_BIN_PRODUCT_VERSION", "DATA_QWORD",
319             "FLAG_MASK_USER", "FLAGS_NTVDM1", "FLAGS_NTVDM2", "FLAGS_NTVDM3", "FLAG_MASK_SHELL", "UPTO_BIN_FILE_VERSION", NULL
320         }
321     },
322     {
323         TAG_TYPE_QWORD, 0x1000, __LINE__, WINVER_2003, WINVER_2003,
324         {
325             "InvalidTag", "TIME", "BIN_FILE_VERSION", "BIN_PRODUCT_VERSION", "MODTIME", "FLAG_MASK_KERNEL", "UPTO_BIN_PRODUCT_VERSION", "DATA_QWORD",
326             "FLAG_MASK_USER", "FLAGS_NTVDM1", "FLAGS_NTVDM2", "FLAGS_NTVDM3", "FLAG_MASK_SHELL", "UPTO_BIN_FILE_VERSION", "FLAG_MASK_FUSION", "FLAGS_PROCESSPARAM",
327             NULL
328         }
329     },
330     {
331         TAG_TYPE_QWORD, 0x1000, __LINE__, WINVER_VISTA, WINVER_ANY,
332         {
333             "InvalidTag", "TIME", "BIN_FILE_VERSION", "BIN_PRODUCT_VERSION", "MODTIME", "FLAG_MASK_KERNEL", "UPTO_BIN_PRODUCT_VERSION", "DATA_QWORD",
334             "FLAG_MASK_USER", "FLAGS_NTVDM1", "FLAGS_NTVDM2", "FLAGS_NTVDM3", "FLAG_MASK_SHELL", "UPTO_BIN_FILE_VERSION", "FLAG_MASK_FUSION", "FLAG_PROCESSPARAM",
335             "FLAG_LUA", "FLAG_INSTALL", NULL
336         }
337     },
338 
339     {
340         TAG_TYPE_STRINGREF, 0x1000, __LINE__, WINVER_ANY, WINVER_2003,
341         {
342             "InvalidTag", "NAME", "DESCRIPTION", "MODULE", "API", "VENDOR", "APP_NAME", "InvalidTag",
343             "COMMAND_LINE", "COMPANY_NAME", "DLLFILE", "WILDCARD_NAME", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag",
344             "PRODUCT_NAME", "PRODUCT_VERSION", "FILE_DESCRIPTION", "FILE_VERSION", "ORIGINAL_FILENAME", "INTERNAL_NAME", "LEGAL_COPYRIGHT", "S16BIT_DESCRIPTION",
345             "PROBLEM_DETAILS", "LINK_URL", "LINK_TEXT", "APPHELP_TITLE", "APPHELP_CONTACT", "SXS_MANIFEST", "DATA_STRING", "MSI_TRANSFORM_FILE",
346             "S16BIT_MODULE_NAME", "LAYER_DISPLAYNAME", "COMPILER_VERSION", "ACTION_TYPE", NULL
347         }
348     },
349     {
350         TAG_TYPE_STRINGREF, 0x1000, __LINE__, WINVER_VISTA, WINVER_VISTA,
351         {
352             "InvalidTag", "NAME", "DESCRIPTION", "MODULE", "API", "VENDOR", "APP_NAME", "InvalidTag",
353             "COMMAND_LINE", "COMPANY_NAME", "DLLFILE", "WILDCARD_NAME", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag",
354             "PRODUCT_NAME", "PRODUCT_VERSION", "FILE_DESCRIPTION", "FILE_VERSION", "ORIGINAL_FILENAME", "INTERNAL_NAME", "LEGAL_COPYRIGHT", "16BIT_DESCRIPTION",
355             "APPHELP_DETAILS", "LINK_URL", "LINK_TEXT", "APPHELP_TITLE", "APPHELP_CONTACT", "SXS_MANIFEST", "DATA_STRING", "MSI_TRANSFORM_FILE",
356             "16BIT_MODULE_NAME", "LAYER_DISPLAYNAME", "COMPILER_VERSION", "ACTION_TYPE", "EXPORT_NAME", NULL
357         }
358     },
359     {
360         TAG_TYPE_STRINGREF, 0x1000, __LINE__, WINVER_WIN7, WINVER_ANY,
361         {
362             "InvalidTag", "NAME", "DESCRIPTION", "MODULE", "API", "VENDOR", "APP_NAME", "InvalidTag",
363             "COMMAND_LINE", "COMPANY_NAME", "DLLFILE", "WILDCARD_NAME", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag",
364             "PRODUCT_NAME", "PRODUCT_VERSION", "FILE_DESCRIPTION", "FILE_VERSION", "ORIGINAL_FILENAME", "INTERNAL_NAME", "LEGAL_COPYRIGHT", "16BIT_DESCRIPTION",
365             "APPHELP_DETAILS", "LINK_URL", "LINK_TEXT", "APPHELP_TITLE", "APPHELP_CONTACT", "SXS_MANIFEST", "DATA_STRING", "MSI_TRANSFORM_FILE",
366             "16BIT_MODULE_NAME", "LAYER_DISPLAYNAME", "COMPILER_VERSION", "ACTION_TYPE", "EXPORT_NAME", "URL", NULL
367         }
368     },
369 
370     {
371         TAG_TYPE_LIST, 0x800, __LINE__, WINVER_ANY, WINVER_2003,
372         {
373             "InvalidTag", "DATABASE", "LIBRARY", "INEXCLUDE", "SHIM", "PATCH", "APP", "EXE",
374             "MATCHING_FILE", "SHIM_REF", "PATCH_REF", "LAYER", "FILE", "APPHELP", "LINK", "DATA",
375             "MSI TRANSFORM", "MSI TRANSFORM REF", "MSI PACKAGE", "FLAG", "MSI CUSTOM ACTION", "FLAG_REF", "ACTION", NULL
376         }
377     },
378     {
379         TAG_TYPE_LIST, 0x800, __LINE__, WINVER_VISTA, WINVER_VISTA,
380         {
381             "InvalidTag", "DATABASE", "LIBRARY", "INEXCLUDE", "SHIM", "PATCH", "APP", "EXE",
382             "MATCHING_FILE", "SHIM_REF", "PATCH_REF", "LAYER", "FILE", "APPHELP", "LINK", "DATA",
383             "MSI_TRANSFORM", "MSI_TRANSFORM_REF", "MSI_PACKAGE", "FLAG", "MSI_CUSTOM_ACTION", "FLAG_REF", "ACTION", "LOOKUP",
384             NULL
385         }
386     },
387     {
388         TAG_TYPE_LIST, 0x800, __LINE__, WINVER_WIN7, WINVER_ANY,
389         {
390             "InvalidTag", "DATABASE", "LIBRARY", "INEXCLUDE", "SHIM", "PATCH", "APP", "EXE",
391             "MATCHING_FILE", "SHIM_REF", "PATCH_REF", "LAYER", "FILE", "APPHELP", "LINK", "DATA",
392             "MSI_TRANSFORM", "MSI_TRANSFORM_REF", "MSI_PACKAGE", "FLAG", "MSI_CUSTOM_ACTION", "FLAG_REF", "ACTION", "LOOKUP",
393             "CONTEXT", "CONTEXT_REF", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag",
394             "SPC", NULL
395         }
396     },
397     {
398         TAG_TYPE_LIST | 0x800, 0x800, __LINE__, WINVER_ANY, WINVER_ANY,
399         {
400             "InvalidTag", "STRINGTABLE", "INDEXES", "INDEX", NULL
401         }
402     },
403 
404     {
405         TAG_TYPE_STRING, 0x800, __LINE__, WINVER_ANY, WINVER_ANY,
406         {
407             "InvalidTag", NULL
408         }
409     },
410     {
411         TAG_TYPE_STRING | 0x800, 0x800, __LINE__, WINVER_ANY, WINVER_2003,
412         {
413             "InvalidTag", "STRTAB_ITEM", NULL
414         }
415     },
416     {
417         TAG_TYPE_STRING | 0x800, 0x800, __LINE__, WINVER_VISTA, WINVER_ANY,
418         {
419             "InvalidTag", "STRINGTABLE_ITEM", NULL
420         }
421     },
422 
423 
424     {
425         TAG_TYPE_BINARY, 0x800, __LINE__, WINVER_ANY, WINVER_2003,
426         {
427             "InvalidTag", "InvalidTag", "PATCH_BITS", "FILE_BITS", "EXE_ID(GUID)", "DATA_BITS", "MSI_PACKAGE_ID(GUID)", "DATABASE_ID(GUID)",
428             NULL
429         }
430     },
431     {
432         TAG_TYPE_BINARY, 0x800, __LINE__, WINVER_VISTA, WINVER_VISTA,
433         {
434             "InvalidTag", "InvalidTag", "PATCH_BITS", "FILE_BITS", "EXE_ID", "DATA_BITS", "MSI_PACKAGE_ID", "DATABASE_ID",
435             NULL
436         }
437     },
438     {
439         TAG_TYPE_BINARY, 0x800, __LINE__, WINVER_WIN7, WINVER_ANY,
440         {
441             "InvalidTag", "InvalidTag", "PATCH_BITS", "FILE_BITS", "EXE_ID", "DATA_BITS", "MSI_PACKAGE_ID", "DATABASE_ID",
442             "CONTEXT_PLATFORM_ID", "CONTEXT_BRANCH_ID", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag", "InvalidTag",
443             "FIX_ID", "APP_ID", NULL
444         }
445     },
446     {
447         TAG_TYPE_BINARY | 0x800, 0x800, __LINE__, WINVER_ANY, WINVER_ANY,
448         {
449             "InvalidTag", "INDEX_BITS", NULL
450         }
451     },
452 
453     { 0, 0, 0, 0, 0, { NULL } }
454 };
455 
456 
457 static void test_SdbTagToStringAllTags(void)
458 {
459     int n;
460     for (n = 0; data[n].base; ++n)
461     {
462         if ((data[n].min_ver == WINVER_ANY || g_WinVersion >= data[n].min_ver) &&
463             (data[n].max_ver == WINVER_ANY || g_WinVersion <= data[n].max_ver))
464         {
465             test_tag(data[n].base, data[n].tags, data[n].upper_limit, data[n].line);
466         }
467     }
468 }
469 
470 static void test_GuidFunctions(void)
471 {
472     GUID guid;
473     ok(pSdbIsNullGUID(&GUID_NULL), "expected GUID_NULL to be recognized as NULL GUID\n");
474     ok(pSdbIsNullGUID(NULL), "expected NULL to be recognized as NULL GUID\n");
475     ok(pSdbIsNullGUID(&test_UserAssist) == 0, "expected a set GUID not to be recognized as NULL GUID\n");
476 
477     memset(&guid, 0, sizeof(guid));
478     ok(pSdbGetStandardDatabaseGUID(0, &guid) == 0,"Expected SdbGetStandardDatabaseGUID to fail\n");
479     ok(IsEqualGUID(&GUID_NULL, &guid), "Expected guid not to be changed\n");
480 
481     ok(pSdbGetStandardDatabaseGUID(0x80020000, NULL),"Expected SdbGetStandardDatabaseGUID to succeed\n");
482 
483     memset(&guid, 0, sizeof(guid));
484     ok(pSdbGetStandardDatabaseGUID(0x80020000, &guid),"Expected SdbGetStandardDatabaseGUID to succeed\n");
485     ok(IsEqualGUID(&GUID_DATABASE_MSI, &guid), "Expected guid to equal GUID_DATABASE_MSI, was: %s\n", wine_dbgstr_guid(&guid));
486 
487     memset(&guid, 0, sizeof(guid));
488     ok(pSdbGetStandardDatabaseGUID(0x80030000, &guid),"Expected SdbGetStandardDatabaseGUID to succeed\n");
489     ok(IsEqualGUID(&GUID_DATABASE_SHIM, &guid), "Expected guid to equal GUID_DATABASE_SHIM, was: %s\n", wine_dbgstr_guid(&guid));
490 
491     memset(&guid, 0, sizeof(guid));
492     ok(pSdbGetStandardDatabaseGUID(0x80040000, &guid),"Expected SdbGetStandardDatabaseGUID to succeed\n");
493     ok(IsEqualGUID(&GUID_DATABASE_DRIVERS, &guid), "Expected guid to equal GUID_DATABASE_DRIVERS, was: %s\n", wine_dbgstr_guid(&guid));
494 }
495 
496 static TAG g_Tags_26[] = {
497     TAG_SIZE,
498     TAG_CHECKSUM,
499     TAG_BIN_FILE_VERSION,
500     TAG_BIN_PRODUCT_VERSION,
501     TAG_PRODUCT_VERSION,
502     TAG_FILE_DESCRIPTION,
503     TAG_COMPANY_NAME,
504     TAG_PRODUCT_NAME,
505     TAG_FILE_VERSION,
506     TAG_ORIGINAL_FILENAME,
507     TAG_INTERNAL_NAME,
508     TAG_LEGAL_COPYRIGHT,
509     TAG_VERDATEHI,  /* TAG_VERFILEDATEHI */
510     TAG_VERDATELO,  /* TAG_VERFILEDATELO */
511     TAG_VERFILEOS,
512     TAG_VERFILETYPE,
513     TAG_MODULE_TYPE,
514     TAG_PE_CHECKSUM,
515     TAG_LINKER_VERSION,
516     TAG_16BIT_DESCRIPTION,  /* CHECKME! */
517     TAG_16BIT_MODULE_NAME,  /* CHECKME! */
518     TAG_UPTO_BIN_FILE_VERSION,
519     TAG_UPTO_BIN_PRODUCT_VERSION,
520     TAG_LINK_DATE,
521     TAG_UPTO_LINK_DATE,
522     TAG_VER_LANGUAGE,
523     0
524 };
525 
526 static TAG g_Tags_28[] = {
527     TAG_SIZE,
528     TAG_CHECKSUM,
529     TAG_BIN_FILE_VERSION,
530     TAG_BIN_PRODUCT_VERSION,
531     TAG_PRODUCT_VERSION,
532     TAG_FILE_DESCRIPTION,
533     TAG_COMPANY_NAME,
534     TAG_PRODUCT_NAME,
535     TAG_FILE_VERSION,
536     TAG_ORIGINAL_FILENAME,
537     TAG_INTERNAL_NAME,
538     TAG_LEGAL_COPYRIGHT,
539     TAG_VERDATEHI,
540     TAG_VERDATELO,
541     TAG_VERFILEOS,
542     TAG_VERFILETYPE,
543     TAG_MODULE_TYPE,
544     TAG_PE_CHECKSUM,
545     TAG_LINKER_VERSION,
546     TAG_16BIT_DESCRIPTION,
547     TAG_16BIT_MODULE_NAME,
548     TAG_UPTO_BIN_FILE_VERSION,
549     TAG_UPTO_BIN_PRODUCT_VERSION,
550     TAG_LINK_DATE,
551     TAG_UPTO_LINK_DATE,
552     TAG_EXPORT_NAME,
553     TAG_VER_LANGUAGE,
554     TAG_EXE_WRAPPER,
555     0
556 };
557 
558 static DWORD find_tag(TAG tag)
559 {
560     DWORD n;
561     TAG* allTags;
562     switch (g_AttrInfoSize)
563     {
564     case 26:
565         allTags = g_Tags_26;
566         break;
567     case 28:
568         allTags = g_Tags_28;
569         break;
570     default:
571         return ~0;
572     }
573 
574     for (n = 0; n < allTags[n]; ++n)
575     {
576         if (allTags[n] == tag)
577             return n;
578     }
579     return ~0;
580 }
581 
582 static void expect_tag_skip_imp(PATTRINFO pattr, TAG tag)
583 {
584     DWORD num = find_tag(tag);
585     PATTRINFO p;
586 
587     if (num == ~0)
588         return;
589 
590     p = &pattr[num];
591     winetest_ok(p->type == TAG_NULL, "expected entry #%d to be TAG_NULL, was %x\n", num, p->type);
592     winetest_ok(p->flags == ATTRIBUTE_FAILED, "expected entry #%d to be failed, was %d\n", num, p->flags);
593     winetest_ok(p->qwattr == 0, "expected entry #%d to be 0, was 0x%I64x\n", num, p->qwattr);
594 }
595 static void expect_tag_empty_imp(PATTRINFO pattr, TAG tag)
596 {
597     DWORD num = find_tag(tag);
598     PATTRINFO p;
599 
600     if (num == ~0)
601         return;
602 
603     p = &pattr[num];
604     winetest_ok(p->type == TAG_NULL, "expected entry #%d to be TAG_NULL, was %x\n", num, p->type);
605     winetest_ok(p->flags == 0, "expected entry #%d to be 0, was %d\n", num, p->flags);
606     winetest_ok(p->qwattr == 0, "expected entry #%d to be 0, was 0x%I64x\n", num, p->qwattr);
607 }
608 
609 static void expect_tag_dword_imp(PATTRINFO pattr, TAG tag, DWORD value)
610 {
611     DWORD num = find_tag(tag);
612     PATTRINFO p;
613 
614     if (num == ~0)
615         return;
616 
617     p = &pattr[num];
618     winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
619     winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
620     winetest_ok(p->dwattr == value, "expected entry #%d to be 0x%x, was 0x%x\n", num, value, p->dwattr);
621 }
622 
623 static void expect_tag_qword_imp(PATTRINFO pattr, TAG tag, QWORD value)
624 {
625     DWORD num = find_tag(tag);
626     PATTRINFO p;
627 
628     if (num == ~0)
629         return;
630 
631     p = &pattr[num];
632     winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
633     winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
634     winetest_ok(p->qwattr == value, "expected entry #%d to be 0x%I64x, was 0x%I64x\n", num, value, p->qwattr);
635 }
636 
637 static void expect_tag_str_imp(PATTRINFO pattr, TAG tag, const WCHAR* value)
638 {
639     DWORD num = find_tag(tag);
640     PATTRINFO p;
641 
642     if (num == ~0)
643         return;
644 
645     p = &pattr[num];
646     winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
647     winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
648     winetest_ok(p->lpattr && wcscmp(p->lpattr, value) == 0, "expected entry #%d to be %s, was %s\n", num, wine_dbgstr_w(value), wine_dbgstr_w(p->lpattr));
649 }
650 
651 #define expect_tag_skip     (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_skip_imp
652 #define expect_tag_empty    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_empty_imp
653 #define expect_tag_dword    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_dword_imp
654 #define expect_tag_qword    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_qword_imp
655 #define expect_tag_str      (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_str_imp
656 #define expect_tag_skip_range(ptr, from, to) \
657     do { \
658         int n = (from), n_end = (to); \
659         winetest_set_location(__FILE__, __LINE__); \
660         for ( ; n < n_end; ++n) \
661             expect_tag_skip_imp((ptr), n); \
662     } while (0)
663 #define test_crc            (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_crc_imp
664 #define test_crc2           (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_crc2_imp
665 
666 void test_onefile(WCHAR* filename)
667 {
668     PATTRINFO pattrinfo;
669     DWORD num;
670 
671     if (!pSdbFreeFileAttributes)
672     {
673         hdll = LoadLibraryA("apphelp.dll");
674         pSdbTagToString = (void *)GetProcAddress(hdll, "SdbTagToString");
675         pSdbGetFileAttributes = (void *)GetProcAddress(hdll, "SdbGetFileAttributes");
676         pSdbFreeFileAttributes = (void *)GetProcAddress(hdll, "SdbFreeFileAttributes");
677     }
678 
679     if (pSdbGetFileAttributes(filename, &pattrinfo, &num))
680     {
681         if (pattrinfo[16].flags == ATTRIBUTE_AVAILABLE)
682         {
683             if (pattrinfo[16].type != TAG_MODULE_TYPE)//SdbpSetAttrFail(&attr_info[16]); /* TAG_MODULE_TYPE (1: WIN16?) (3: WIN32?) (WIN64?), Win32VersionValue? */)
684                 printf("FAIL TAG_MODULE_TYPE (%S)\n", filename);
685             if (pattrinfo[16].dwattr != 3 && pattrinfo[16].dwattr != 2)
686                 printf("TAG_MODULE_TYPE(%S): %d\n", filename, pattrinfo[16].dwattr);    // C:\Program Files (x86)\Windows Kits\8.1\Lib\win7\stub512.com
687             if (pattrinfo[16].dwattr == 2)
688             {
689                 printf("TAG_MODULE_TYPE(%S): %d, %d\n", filename, pattrinfo[16].dwattr, pattrinfo[0].dwattr);
690             }
691         }
692 
693         if (pattrinfo[27].flags == ATTRIBUTE_AVAILABLE)
694         {
695             if (pattrinfo[27].type != TAG_EXE_WRAPPER)
696                 printf("FAIL TAG_EXE_WRAPPER (%S)\n", filename);
697             if (pattrinfo[27].dwattr != 0)
698                 printf("TAG_EXE_WRAPPER(%S): %d\n", filename, pattrinfo[27].dwattr);
699         }
700 
701         pSdbFreeFileAttributes(pattrinfo);
702     }
703 }
704 
705 static void test_crc_imp(size_t len, DWORD expected)
706 {
707     static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
708     static char crc_test[] = {4, 4, 4, 4, 1, 1, 1, 1, 4, 4, 4, 4, 2, 2, 2, 2};
709 
710     PATTRINFO pattrinfo = (PATTRINFO)0xdead;
711     DWORD num = 333;
712     BOOL ret;
713 
714     test_create_file_imp(L"testxx.exe", crc_test, len);
715     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
716     winetest_ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
717     winetest_ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
718     winetest_ok(num == g_AttrInfoSize, "expected %u items, got %d.\n", g_AttrInfoSize, num);
719 
720     if (num == g_AttrInfoSize && ret)
721     {
722         expect_tag_dword_imp(pattrinfo, TAG_CHECKSUM, expected);
723     }
724     if (ret)
725         pSdbFreeFileAttributes(pattrinfo);
726 }
727 
728 static void test_crc2_imp(DWORD len, int fill, DWORD expected)
729 {
730     static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
731 
732     PATTRINFO pattrinfo = (PATTRINFO)0xdead;
733     DWORD num = 333;
734     BOOL ret;
735     size_t n;
736     char* crc_test = malloc(len);
737     for (n = 0; n < len; ++n)
738         crc_test[n] = (char)(fill ? fill : n);
739 
740     test_create_file_imp(L"testxx.exe", crc_test, len);
741     free(crc_test);
742     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
743     winetest_ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
744     winetest_ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
745     winetest_ok(num == g_AttrInfoSize, "expected %u items, got %d.\n", g_AttrInfoSize, num);
746 
747     if (num == g_AttrInfoSize && ret)
748     {
749         expect_tag_dword_imp(pattrinfo, TAG_SIZE, len);
750         expect_tag_dword_imp(pattrinfo, TAG_CHECKSUM, expected);
751     }
752     if (ret)
753         pSdbFreeFileAttributes(pattrinfo);
754 }
755 
756 
757 
758 static void test_ApplicationAttributes(void)
759 {
760     static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
761     static const WCHAR PRODUCT_VERSION[] = {'1','.','0','.','0','.','1',0};
762     static const WCHAR FILE_DESCRIPTION[] = {'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0};
763     static const WCHAR COMPANY_NAME[] = {'C','o','m','p','a','n','y','N','a','m','e',0};
764     static const WCHAR PRODUCT_NAME[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
765     static const WCHAR FILE_VERSION[] = {'1','.','0','.','0','.','0',0};
766     static const WCHAR ORIGINAL_FILENAME[] = {'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0};
767     static const WCHAR INTERNAL_NAME[] = {'I','n','t','e','r','n','a','l','N','a','m','e',0};
768     static const WCHAR LEGAL_COPYRIGHT[] = {'L','e','g','a','l','C','o','p','y','r','i','g','h','t',0};
769     static const WCHAR EXPORT_NAME[] = {'T','e','S','t','2','.','e','x','e',0};
770     static const WCHAR OS2_DESCRIPTION[] = {'M','O','D',' ','D','E','S','C','R','I','P','T','I','O','N',' ','H','E','R','E',0};
771     static const WCHAR OS2_EXPORT_NAME[] = {'T','E','S','T','M','O','D','.','h','X','x',0};
772     static const WCHAR OS2_DESCRIPTION_broken[] = {'Z',0};
773     static const WCHAR OS2_EXPORT_NAME_broken[] = {'E',0};
774 
775     PATTRINFO pattrinfo = (PATTRINFO)0xdead;
776     DWORD num = 333;
777     BOOL ret;
778 
779     /* ensure the file is not there. */
780     DeleteFileA("testxx.exe");
781     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
782     ok(ret == FALSE, "expected SdbGetFileAttributes to fail.\n");
783     ok(pattrinfo == (PATTRINFO)0xdead, "expected the pointer not to change.\n");
784     ok(num == 333, "expected the number of items not to change.\n");
785     if (ret)
786         pSdbFreeFileAttributes(pattrinfo);
787 
788     /* Test a file with as much features as possible */
789     test_create_exe(L"testxx.exe", 0);
790 
791     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
792     ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
793     ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
794 
795     //for (UINT n = 0; n < num; ++n)
796     //{
797     //    trace("%S\n", pSdbTagToString(pattrinfo[n].type));
798     //}
799 
800     switch (num)
801     {
802     case 26:
803         // 2k3
804         g_AttrInfoSize = 26;
805         break;
806     case 28:
807         // Win7+ (and maybe vista, but who cares about that?)
808         g_AttrInfoSize = 28;
809         break;
810     default:
811         ok(0, "Unknown attrinfo size: %u\n", num);
812         break;
813     }
814 
815     ok(num == g_AttrInfoSize, "expected %u items, got %d.\n", g_AttrInfoSize, num);
816 
817     if (num == g_AttrInfoSize && ret)
818     {
819         expect_tag_dword(pattrinfo, TAG_SIZE, 0x800);
820         expect_tag_dword(pattrinfo, TAG_CHECKSUM, 0x178bd629);
821         expect_tag_qword(pattrinfo, TAG_BIN_FILE_VERSION, 0x1000000000000ull);
822         expect_tag_qword(pattrinfo, TAG_BIN_PRODUCT_VERSION, 0x1000000000001ull);
823         expect_tag_str(pattrinfo, TAG_PRODUCT_VERSION, PRODUCT_VERSION);
824         expect_tag_str(pattrinfo, TAG_FILE_DESCRIPTION, FILE_DESCRIPTION);
825         expect_tag_str(pattrinfo, TAG_COMPANY_NAME, COMPANY_NAME);
826         expect_tag_str(pattrinfo, TAG_PRODUCT_NAME, PRODUCT_NAME);
827         expect_tag_str(pattrinfo, TAG_FILE_VERSION, FILE_VERSION);
828         expect_tag_str(pattrinfo, TAG_ORIGINAL_FILENAME, ORIGINAL_FILENAME);
829         expect_tag_str(pattrinfo, TAG_INTERNAL_NAME, INTERNAL_NAME);
830         expect_tag_str(pattrinfo, TAG_LEGAL_COPYRIGHT, LEGAL_COPYRIGHT);
831         expect_tag_dword(pattrinfo, TAG_VERDATEHI, 0x1d1a019);
832         expect_tag_dword(pattrinfo, TAG_VERDATELO, 0xac754c50);
833         expect_tag_dword(pattrinfo, TAG_VERFILEOS, VOS__WINDOWS32);
834         expect_tag_dword(pattrinfo, TAG_VERFILETYPE, VFT_APP);
835         expect_tag_dword(pattrinfo, TAG_MODULE_TYPE, 0x3); /* Win32 */
836         expect_tag_dword(pattrinfo, TAG_PE_CHECKSUM, 0xBAAD);
837         expect_tag_dword(pattrinfo, TAG_LINKER_VERSION, 0x40002);
838         expect_tag_skip(pattrinfo, TAG_16BIT_DESCRIPTION);
839         expect_tag_skip(pattrinfo, TAG_16BIT_MODULE_NAME);
840         expect_tag_qword(pattrinfo, TAG_UPTO_BIN_FILE_VERSION, 0x1000000000000ull);
841         expect_tag_qword(pattrinfo, TAG_UPTO_BIN_PRODUCT_VERSION, 0x1000000000001ull);
842         expect_tag_dword(pattrinfo, TAG_LINK_DATE, 0x12345);
843         expect_tag_dword(pattrinfo, TAG_UPTO_LINK_DATE, 0x12345);
844         expect_tag_str(pattrinfo, TAG_EXPORT_NAME, EXPORT_NAME);
845         expect_tag_dword(pattrinfo, TAG_VER_LANGUAGE, 0xffff);
846         expect_tag_dword(pattrinfo, TAG_EXE_WRAPPER, 0x0);
847     }
848     if (ret)
849         pSdbFreeFileAttributes(pattrinfo);
850 
851 
852     /* Disable resource and exports */
853     test_create_exe(L"testxx.exe", 1);
854 
855     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
856     ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
857     ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
858     ok(num == g_AttrInfoSize, "expected %u items, got %d.\n", g_AttrInfoSize, num);
859 
860     if (num == g_AttrInfoSize && ret)
861     {
862         expect_tag_dword(pattrinfo, TAG_SIZE, 0x800);
863         expect_tag_dword(pattrinfo, TAG_CHECKSUM, 0xea7caffd);
864         //expect_tag_skip_range(pattrinfo, 2, 16);
865         expect_tag_dword(pattrinfo, TAG_MODULE_TYPE, 0x3); /* Win32 */
866         expect_tag_dword(pattrinfo, TAG_PE_CHECKSUM, 0xBAAD);
867         expect_tag_dword(pattrinfo, TAG_LINKER_VERSION, 0x40002);
868         //expect_tag_skip_range(pattrinfo, 19, 23);
869         expect_tag_dword(pattrinfo, TAG_LINK_DATE, 0x12345);
870         expect_tag_dword(pattrinfo, TAG_UPTO_LINK_DATE, 0x12345);
871         expect_tag_skip(pattrinfo, TAG_EXPORT_NAME);
872         expect_tag_empty(pattrinfo, TAG_VER_LANGUAGE);
873         expect_tag_dword(pattrinfo, TAG_EXE_WRAPPER, 0x0);
874     }
875     if (ret)
876         pSdbFreeFileAttributes(pattrinfo);
877 
878     /* A file with just 'MZ' */
879     test_create_file(L"testxx.exe", "MZ", 2);
880 
881     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
882     ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
883     ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
884     ok(num == g_AttrInfoSize, "expected %u items, got %d.\n", g_AttrInfoSize, num);
885 
886     if (num == g_AttrInfoSize && ret)
887     {
888         expect_tag_dword(pattrinfo, TAG_SIZE, 0x2);
889         expect_tag_dword(pattrinfo, TAG_CHECKSUM, 0);
890         //expect_tag_skip_range(pattrinfo, 2, 16);
891         expect_tag_dword(pattrinfo, TAG_MODULE_TYPE, 0x1);
892         //expect_tag_skip_range(pattrinfo, 17, 26);
893         expect_tag_empty(pattrinfo, TAG_VER_LANGUAGE);
894         expect_tag_skip(pattrinfo, TAG_EXE_WRAPPER);
895     }
896     if (ret)
897         pSdbFreeFileAttributes(pattrinfo);
898 
899     /* Empty file */
900     test_create_file(L"testxx.exe", NULL, 0);
901 
902     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
903     ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
904     ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
905     ok(num == g_AttrInfoSize, "expected %u items, got %d.\n", g_AttrInfoSize, num);
906 
907     if (num == g_AttrInfoSize && ret)
908     {
909         expect_tag_dword(pattrinfo, TAG_SIZE, 0);
910         //expect_tag_skip_range(pattrinfo, 1, 26);
911         expect_tag_empty(pattrinfo, TAG_VER_LANGUAGE);
912         expect_tag_skip(pattrinfo, TAG_EXE_WRAPPER);
913     }
914     if (ret)
915         pSdbFreeFileAttributes(pattrinfo);
916 
917     /* minimal NE executable */
918     test_create_ne(L"testxx.exe", 0);
919 
920     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
921     ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
922     ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
923     ok(num == g_AttrInfoSize, "expected %u items, got %d.\n", g_AttrInfoSize, num);
924 
925     if (num == g_AttrInfoSize && ret)
926     {
927         expect_tag_dword(pattrinfo, TAG_SIZE, 0xa8);
928         expect_tag_dword(pattrinfo, TAG_CHECKSUM, 0xf2abe4e9);
929         //expect_tag_skip_range(pattrinfo, 2, 16);
930         expect_tag_dword(pattrinfo, TAG_MODULE_TYPE, 0x2);
931         expect_tag_skip(pattrinfo, TAG_PE_CHECKSUM);
932         expect_tag_skip(pattrinfo, TAG_LINKER_VERSION);
933         expect_tag_str(pattrinfo, TAG_16BIT_DESCRIPTION, OS2_DESCRIPTION);
934         expect_tag_str(pattrinfo, TAG_16BIT_MODULE_NAME, OS2_EXPORT_NAME);
935         //expect_tag_skip_range(pattrinfo, 21, 26);
936         expect_tag_empty(pattrinfo, TAG_VER_LANGUAGE);
937         expect_tag_skip(pattrinfo, TAG_EXE_WRAPPER);
938     }
939     if (ret)
940         pSdbFreeFileAttributes(pattrinfo);
941 
942     /* NE executable with description / module name pointers zero, to show they are always used */
943     test_create_ne(L"testxx.exe", 1);
944 
945     ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
946     ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
947     ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
948     ok(num == g_AttrInfoSize, "expected %u items, got %d.\n", g_AttrInfoSize, num);
949 
950     if (num == g_AttrInfoSize && ret)
951     {
952         expect_tag_dword(pattrinfo, TAG_SIZE, 0xa8);
953         expect_tag_dword(pattrinfo, TAG_CHECKSUM, 0xddcbe4c9);
954         //expect_tag_skip_range(pattrinfo, 2, 16);
955         expect_tag_dword(pattrinfo, TAG_MODULE_TYPE, 0x2);
956         expect_tag_skip(pattrinfo, TAG_PE_CHECKSUM);
957         expect_tag_skip(pattrinfo, TAG_LINKER_VERSION);
958         expect_tag_str(pattrinfo, TAG_16BIT_DESCRIPTION, OS2_DESCRIPTION_broken);   /* the 'Z' from 'MZ' */
959         expect_tag_str(pattrinfo, TAG_16BIT_MODULE_NAME, OS2_EXPORT_NAME_broken);   /* the 'E' from 'NE' */
960         //expect_tag_skip_range(pattrinfo, 21, 26);
961         expect_tag_empty(pattrinfo, TAG_VER_LANGUAGE);
962         expect_tag_skip(pattrinfo, TAG_EXE_WRAPPER);
963     }
964     if (ret)
965         pSdbFreeFileAttributes(pattrinfo);
966 
967     test_crc(1, 0);
968     test_crc(2, 0);
969     test_crc(3, 0);
970     test_crc(4, 0x2020202);
971     test_crc(5, 0x2020202);
972     test_crc(6, 0x2020202);
973     test_crc(7, 0x2020202);
974     test_crc(8, 0x81818181);
975     test_crc(9, 0x81818181);
976     test_crc(10, 0x81818181);
977     test_crc(11, 0x81818181);
978     test_crc(12, 0xc2c2c2c2);
979     test_crc(16, 0x62626262);
980 
981     /* This seems to be the cutoff point */
982     test_crc2(0xffc, 4, 0xfbfbfcfc);
983     test_crc2(0xffc, 8, 0x7070717);
984     test_crc2(0xffc, 0xcc, 0xc8eba002);
985     test_crc2(0xffc, 0, 0x4622028d);
986 
987     test_crc2(0x1000, 4, 0x80);
988     test_crc2(0x1000, 8, 0x8787878f);
989     test_crc2(0x1000, 0xcc, 0x4adc3667);
990     test_crc2(0x1000, 0, 0xa3108044);
991 
992     /* Here is another cutoff point */
993     test_crc2(0x11fc, 4, 0x80);
994     test_crc2(0x11fc, 8, 0x8787878f);
995     test_crc2(0x11fc, 0xcc, 0x4adc3667);
996     test_crc2(0x11fc, 0, 0xf03e0800);
997 
998     test_crc2(0x1200, 4, 0x80);
999     test_crc2(0x1200, 8, 0x8787878f);
1000     test_crc2(0x1200, 0xcc, 0x4adc3667);
1001     test_crc2(0x1200, 0, 0xa3108044);
1002 
1003     /* After that, it stays the same for all sizes */
1004     test_crc2(0xf000, 4, 0x80);
1005     test_crc2(0xf000, 8, 0x8787878f);
1006     test_crc2(0xf000, 0xcc, 0x4adc3667);
1007     test_crc2(0xf000, 0, 0xa3108044);
1008 
1009 
1010     DeleteFileA("testxx.exe");
1011 }
1012 
1013 /* Showing that SdbGetAppPatchDir returns HRESULT */
1014 static void test_SdbGetAppPatchDir(void)
1015 {
1016     WCHAR Buffer[MAX_PATH];
1017     HRESULT hr, expect_hr;
1018     int n;
1019 
1020 
1021     _SEH2_TRY
1022     {
1023         hr = pSdbGetAppPatchDir(NULL, NULL, 0);
1024         ok_hex(hr, S_FALSE);
1025     }
1026     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1027     {
1028         /* Some versions accept it, some don't */
1029         trace("SdbGetAppPatchDir did not handle a NULL pointer very gracefully.\n");
1030     }
1031     _SEH2_END;
1032 
1033 
1034 
1035     memset(Buffer, 0xbb, sizeof(Buffer));
1036     hr = pSdbGetAppPatchDir(NULL, Buffer, 0);
1037     if (g_WinVersion < WINVER_WIN7)
1038         expect_hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
1039     else if (g_WinVersion < WINVER_WIN10)
1040         expect_hr = S_OK;
1041     else
1042         expect_hr = S_FALSE;
1043     ok_hex(hr, expect_hr);
1044 
1045     if (g_WinVersion < WINVER_WIN7)
1046         expect_hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1047     else if (g_WinVersion < WINVER_WIN10)
1048         expect_hr = S_OK;
1049     else
1050         expect_hr = TRUE;
1051 
1052     memset(Buffer, 0xbb, sizeof(Buffer));
1053     hr = pSdbGetAppPatchDir(NULL, Buffer, 1);
1054     ok_hex(hr, expect_hr);
1055 
1056 
1057     for (n = 2; n < _countof(Buffer) - 1; ++n)
1058     {
1059         memset(Buffer, 0xbb, sizeof(Buffer));
1060         hr = pSdbGetAppPatchDir(NULL, Buffer, n);
1061         ok(Buffer[n] == 0xbbbb, "Expected SdbGetAppPatchDir to leave WCHAR at %d untouched, was: %d\n",
1062            n, Buffer[n]);
1063         ok(hr == S_OK || hr == expect_hr, "Expected S_OK or 0x%x, was: 0x%x (at %d)\n", expect_hr, hr, n);
1064     }
1065 }
1066 START_TEST(apphelp)
1067 {
1068     //SetEnvironmentVariable("SHIM_DEBUG_LEVEL", "4");
1069     //SetEnvironmentVariable("DEBUGCHANNEL", "+apphelp");
1070     silence_debug_output();
1071 
1072     hdll = LoadLibraryA("apphelp.dll");
1073     g_WinVersion = get_module_version(hdll);
1074     trace("Detected apphelp.dll version: 0x%x\n", g_WinVersion);
1075 
1076 #define RESOLVE(fnc)    do { p##fnc = (void *) GetProcAddress(hdll, #fnc); ok(!!p##fnc, #fnc " not found.\n"); } while (0)
1077     RESOLVE(ApphelpCheckShellObject);
1078     RESOLVE(SdbTagToString);
1079     RESOLVE(SdbGUIDToString);
1080     RESOLVE(SdbIsNullGUID);
1081     RESOLVE(SdbGetStandardDatabaseGUID);
1082     RESOLVE(SdbGetFileAttributes);
1083     RESOLVE(SdbFreeFileAttributes);
1084     RESOLVE(SdbGetAppPatchDir);
1085 #undef RESOLVE
1086 
1087     test_ApphelpCheckShellObject();
1088     test_GuidFunctions();
1089     test_ApplicationAttributes();
1090     test_SdbTagToString();
1091     test_SdbTagToStringAllTags();
1092     if (pSdbGetAppPatchDir)
1093         test_SdbGetAppPatchDir();
1094 }
1095