[APPHELP][APPHELP_APITEST] Add SdbGetFileAttributes + tests, based on the work of...
[reactos.git] / rostests / apitests / apphelp / apphelp.c
index 8900c7a..f065ba8 100644 (file)
 
 #include "wine/test.h"
 
+/* data.c */
+void test_create_exe_imp(const char* name, int skip_rsrc_exports);
+void test_create_file_imp(const char* name, const char* contents, size_t len);
+void test_create_ne_imp(const char* name, int skip_names);
+
+#define test_create_exe     (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_create_exe_imp
+#define test_create_file    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_create_file_imp
+#define test_create_ne      (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_create_ne_imp
+
 
 static DWORD g_Version;
 
@@ -48,6 +57,9 @@ static DWORD g_Version;
 
 
 typedef WORD TAG;
+typedef DWORD TAGID;
+typedef DWORD TAGREF;
+typedef UINT64 QWORD;
 
 #define TAG_TYPE_MASK 0xF000
 
@@ -60,10 +72,55 @@ typedef WORD TAG;
 #define TAG_TYPE_LIST 0x7000
 #define TAG_TYPE_STRING 0x8000
 #define TAG_TYPE_BINARY 0x9000
+#define TAG_NULL 0x0
+#define TAG_SIZE (0x1 | TAG_TYPE_DWORD)
+#define TAG_CHECKSUM (0x3 | TAG_TYPE_DWORD)
+#define TAG_MODULE_TYPE (0x6 | TAG_TYPE_DWORD)
+#define TAG_VERDATEHI (0x7 | TAG_TYPE_DWORD)
+#define TAG_VERDATELO (0x8 | TAG_TYPE_DWORD)
+#define TAG_VERFILEOS (0x9 | TAG_TYPE_DWORD)
+#define TAG_VERFILETYPE (0xA | TAG_TYPE_DWORD)
+#define TAG_PE_CHECKSUM (0xB | TAG_TYPE_DWORD)
+#define TAG_VER_LANGUAGE (0x12 | TAG_TYPE_DWORD)
+#define TAG_LINKER_VERSION (0x1C | TAG_TYPE_DWORD)
+#define TAG_LINK_DATE (0x1D | TAG_TYPE_DWORD)
+#define TAG_UPTO_LINK_DATE (0x1E | TAG_TYPE_DWORD)
+#define TAG_EXE_WRAPPER (0x31 | TAG_TYPE_DWORD)
+#define TAG_BIN_FILE_VERSION (0x2 | TAG_TYPE_QWORD)
+#define TAG_BIN_PRODUCT_VERSION (0x3 | TAG_TYPE_QWORD)
+#define TAG_UPTO_BIN_PRODUCT_VERSION (0x6 | TAG_TYPE_QWORD)
+#define TAG_UPTO_BIN_FILE_VERSION (0xD | TAG_TYPE_QWORD)
+#define TAG_NAME (0x1 | TAG_TYPE_STRINGREF)
+#define TAG_COMPANY_NAME (0x9 | TAG_TYPE_STRINGREF)
+#define TAG_PRODUCT_NAME (0x10 | TAG_TYPE_STRINGREF)
+#define TAG_PRODUCT_VERSION (0x11 | TAG_TYPE_STRINGREF)
+#define TAG_FILE_DESCRIPTION (0x12 | TAG_TYPE_STRINGREF)
+#define TAG_FILE_VERSION (0x13 | TAG_TYPE_STRINGREF)
+#define TAG_ORIGINAL_FILENAME (0x14 | TAG_TYPE_STRINGREF)
+#define TAG_INTERNAL_NAME (0x15 | TAG_TYPE_STRINGREF)
+#define TAG_LEGAL_COPYRIGHT (0x16 | TAG_TYPE_STRINGREF)
+#define TAG_16BIT_DESCRIPTION (0x17 | TAG_TYPE_STRINGREF)
+#define TAG_16BIT_MODULE_NAME (0x20 | TAG_TYPE_STRINGREF)
+#define TAG_EXPORT_NAME (0x24 | TAG_TYPE_STRINGREF)
+
 
+#define ATTRIBUTE_AVAILABLE 0x1
+#define ATTRIBUTE_FAILED 0x2
+
+typedef struct tagATTRINFO {
+  TAG   type;
+  DWORD flags;  /* ATTRIBUTE_AVAILABLE, ATTRIBUTE_FAILED */
+  union {
+    QWORD qwattr;
+    DWORD dwattr;
+    WCHAR *lpattr;
+  };
+} ATTRINFO, *PATTRINFO;
 
 static HMODULE hdll;
 static LPCWSTR (WINAPI *pSdbTagToString)(TAG);
+static BOOL (WINAPI *pSdbGetFileAttributes)(LPCWSTR, PATTRINFO *, LPDWORD);
+static BOOL (WINAPI *pSdbFreeFileAttributes)(PATTRINFO);
 
 static void test_SdbTagToString(void)
 {
@@ -368,6 +425,386 @@ static void test_SdbTagToStringAllTags(void)
     }
 }
 
+static void expect_tag_skip_imp(PATTRINFO pattr, DWORD num)
+{
+    PATTRINFO p = &pattr[num];
+    winetest_ok(p->type == TAG_NULL, "expected entry #%d to be TAG_NULL, was %x\n", num, p->type);
+    winetest_ok(p->flags == ATTRIBUTE_FAILED, "expected entry #%d to be failed, was %d\n", num, p->flags);
+    winetest_ok(p->qwattr == 0, "expected entry #%d to be 0, was 0x%I64x\n", num, p->qwattr);
+}
+static void expect_tag_empty_imp(PATTRINFO pattr, DWORD num)
+{
+    PATTRINFO p = &pattr[num];
+    winetest_ok(p->type == TAG_NULL, "expected entry #%d to be TAG_NULL, was %x\n", num, p->type);
+    winetest_ok(p->flags == 0, "expected entry #%d to be 0, was %d\n", num, p->flags);
+    winetest_ok(p->qwattr == 0, "expected entry #%d to be 0, was 0x%I64x\n", num, p->qwattr);
+}
+
+static void expect_tag_dword_imp(PATTRINFO pattr, DWORD num, TAG tag, DWORD value)
+{
+    PATTRINFO p = &pattr[num];
+    winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
+    winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
+    winetest_ok(p->dwattr == value, "expected entry #%d to be 0x%x, was 0x%x\n", num, value, p->dwattr);
+}
+
+static void expect_tag_qword_imp(PATTRINFO pattr, DWORD num, TAG tag, QWORD value)
+{
+    PATTRINFO p = &pattr[num];
+    winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
+    winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
+    winetest_ok(p->qwattr == value, "expected entry #%d to be 0x%I64x, was 0x%I64x\n", num, value, p->qwattr);
+}
+
+static void expect_tag_str_imp(PATTRINFO pattr, DWORD num, TAG tag, const WCHAR* value)
+{
+    PATTRINFO p = &pattr[num];
+    winetest_ok(p->type == tag, "expected entry #%d to be %x, was %x\n", num, tag, p->type);
+    winetest_ok(p->flags == ATTRIBUTE_AVAILABLE, "expected entry #%d to be available, was %d\n", num, p->flags);
+    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));
+}
+
+#define expect_tag_skip     (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_skip_imp
+#define expect_tag_empty    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_empty_imp
+#define expect_tag_dword    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_dword_imp
+#define expect_tag_qword    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_qword_imp
+#define expect_tag_str      (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_tag_str_imp
+#define expect_tag_skip_range(ptr, from, to) \
+    do { \
+        int n = (from), n_end = (to); \
+        winetest_set_location(__FILE__, __LINE__); \
+        for ( ; n < n_end; ++n) \
+            expect_tag_skip_imp((ptr), n); \
+    } while (0)
+#define test_crc            (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_crc_imp
+#define test_crc2           (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_crc2_imp
+
+void test_onefile(WCHAR* filename)
+{
+    PATTRINFO pattrinfo;
+    DWORD num;
+
+    if (!pSdbFreeFileAttributes)
+    {
+        hdll = LoadLibraryA("apphelp.dll");
+        pSdbTagToString = (void *)GetProcAddress(hdll, "SdbTagToString");
+        pSdbGetFileAttributes = (void *)GetProcAddress(hdll, "SdbGetFileAttributes");
+        pSdbFreeFileAttributes = (void *)GetProcAddress(hdll, "SdbFreeFileAttributes");
+    }
+
+    if (pSdbGetFileAttributes(filename, &pattrinfo, &num))
+    {
+        if (pattrinfo[16].flags == ATTRIBUTE_AVAILABLE)
+        {
+            if (pattrinfo[16].type != TAG_MODULE_TYPE)//SdbpSetAttrFail(&attr_info[16]); /* TAG_MODULE_TYPE (1: WIN16?) (3: WIN32?) (WIN64?), Win32VersionValue? */)
+                printf("FAIL TAG_MODULE_TYPE (%S)\n", filename);
+            if (pattrinfo[16].dwattr != 3 && pattrinfo[16].dwattr != 2)
+                printf("TAG_MODULE_TYPE(%S): %d\n", filename, pattrinfo[16].dwattr);    // C:\Program Files (x86)\Windows Kits\8.1\Lib\win7\stub512.com
+            if (pattrinfo[16].dwattr == 2)
+            {
+                printf("TAG_MODULE_TYPE(%S): %d, %d\n", filename, pattrinfo[16].dwattr, pattrinfo[0].dwattr);
+            }
+        }
+
+        if (pattrinfo[27].flags == ATTRIBUTE_AVAILABLE)
+        {
+            if (pattrinfo[27].type != TAG_EXE_WRAPPER)
+                printf("FAIL TAG_EXE_WRAPPER (%S)\n", filename);
+            if (pattrinfo[27].dwattr != 0)
+                printf("TAG_EXE_WRAPPER(%S): %d\n", filename, pattrinfo[27].dwattr);
+        }
+
+        pSdbFreeFileAttributes(pattrinfo);
+    }
+}
+
+static void test_crc_imp(size_t len, DWORD expected)
+{
+    static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
+    static char crc_test[] = {4, 4, 4, 4, 1, 1, 1, 1, 4, 4, 4, 4, 2, 2, 2, 2};
+
+    PATTRINFO pattrinfo = (PATTRINFO)0xdead;
+    DWORD num = 333;
+    BOOL ret;
+
+    test_create_file_imp("testxx.exe", crc_test, len);
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    winetest_ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
+    winetest_ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
+    winetest_ok(num == 28, "expected 28 items, got %d.\n", num);
+
+    if (num == 28 && ret)
+    {
+        expect_tag_dword_imp(pattrinfo, 1, TAG_CHECKSUM, expected);
+    }
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+}
+
+static void test_crc2_imp(size_t len, int fill, DWORD expected)
+{
+    static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
+
+    PATTRINFO pattrinfo = (PATTRINFO)0xdead;
+    DWORD num = 333;
+    BOOL ret;
+    size_t n;
+    char* crc_test = malloc(len);
+    for (n = 0; n < len; ++n)
+        crc_test[n] = (char)(fill ? fill : n);
+
+    test_create_file_imp("testxx.exe", crc_test, len);
+    free(crc_test);
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    winetest_ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
+    winetest_ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
+    winetest_ok(num == 28, "expected 28 items, got %d.\n", num);
+
+    if (num == 28 && ret)
+    {
+        expect_tag_dword_imp(pattrinfo, 0, TAG_SIZE, len);
+        expect_tag_dword_imp(pattrinfo, 1, TAG_CHECKSUM, expected);
+    }
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+}
+
+
+
+static void test_ApplicationAttributes(void)
+{
+    static const WCHAR path[] = {'t','e','s','t','x','x','.','e','x','e',0};
+    static const WCHAR PRODUCT_VERSION[] = {'1','.','0','.','0','.','1',0};
+    static const WCHAR FILE_DESCRIPTION[] = {'F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0};
+    static const WCHAR COMPANY_NAME[] = {'C','o','m','p','a','n','y','N','a','m','e',0};
+    static const WCHAR PRODUCT_NAME[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
+    static const WCHAR FILE_VERSION[] = {'1','.','0','.','0','.','0',0};
+    static const WCHAR ORIGINAL_FILENAME[] = {'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0};
+    static const WCHAR INTERNAL_NAME[] = {'I','n','t','e','r','n','a','l','N','a','m','e',0};
+    static const WCHAR LEGAL_COPYRIGHT[] = {'L','e','g','a','l','C','o','p','y','r','i','g','h','t',0};
+    static const WCHAR EXPORT_NAME[] = {'T','e','S','t','2','.','e','x','e',0};
+    static const WCHAR OS2_DESCRIPTION[] = {'M','O','D',' ','D','E','S','C','R','I','P','T','I','O','N',' ','H','E','R','E',0};
+    static const WCHAR OS2_EXPORT_NAME[] = {'T','E','S','T','M','O','D','.','h','X','x',0};
+    static const WCHAR OS2_DESCRIPTION_broken[] = {'Z',0};
+    static const WCHAR OS2_EXPORT_NAME_broken[] = {'E',0};
+
+    PATTRINFO pattrinfo = (PATTRINFO)0xdead;
+    DWORD num = 333;
+    BOOL ret;
+
+    /* ensure the file is not there. */
+    DeleteFileA("testxx.exe");
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    ok(ret == FALSE, "expected SdbGetFileAttributes to fail.\n");
+    ok(pattrinfo == (PATTRINFO)0xdead, "expected the pointer not to change.\n");
+    ok(num == 333, "expected the number of items not to change.\n");
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+
+    /* Test a file with as much features as possible */
+    test_create_exe("testxx.exe", 0);
+
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
+    ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
+    ok(num == 28, "expected 28 items, got %d.\n", num);
+
+    if (num == 28 && ret)
+    {
+        expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0x800);
+        expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0x178bd629);
+        expect_tag_qword(pattrinfo, 2, TAG_BIN_FILE_VERSION, 0x1000000000000ull);
+        expect_tag_qword(pattrinfo, 3, TAG_BIN_PRODUCT_VERSION, 0x1000000000001ull);
+        expect_tag_str(pattrinfo, 4, TAG_PRODUCT_VERSION, PRODUCT_VERSION);
+        expect_tag_str(pattrinfo, 5, TAG_FILE_DESCRIPTION, FILE_DESCRIPTION);
+        expect_tag_str(pattrinfo, 6, TAG_COMPANY_NAME, COMPANY_NAME);
+        expect_tag_str(pattrinfo, 7, TAG_PRODUCT_NAME, PRODUCT_NAME);
+        expect_tag_str(pattrinfo, 8, TAG_FILE_VERSION, FILE_VERSION);
+        expect_tag_str(pattrinfo, 9, TAG_ORIGINAL_FILENAME, ORIGINAL_FILENAME);
+        expect_tag_str(pattrinfo, 10, TAG_INTERNAL_NAME, INTERNAL_NAME);
+        expect_tag_str(pattrinfo, 11, TAG_LEGAL_COPYRIGHT, LEGAL_COPYRIGHT);
+        expect_tag_dword(pattrinfo, 12, TAG_VERDATEHI, 0x1d1a019);
+        expect_tag_dword(pattrinfo, 13, TAG_VERDATELO, 0xac754c50);
+        expect_tag_dword(pattrinfo, 14, TAG_VERFILEOS, VOS__WINDOWS32);
+        expect_tag_dword(pattrinfo, 15, TAG_VERFILETYPE, VFT_APP);
+        expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x3); /* Win32 */
+        expect_tag_dword(pattrinfo, 17, TAG_PE_CHECKSUM, 0xBAAD);
+        expect_tag_dword(pattrinfo, 18, TAG_LINKER_VERSION, 0x40002);
+        expect_tag_skip(pattrinfo, 19); /* TAG_16BIT_DESCRIPTION */
+        expect_tag_skip(pattrinfo, 20); /* TAG_16BIT_MODULE_NAME */
+        expect_tag_qword(pattrinfo, 21, TAG_UPTO_BIN_FILE_VERSION, 0x1000000000000ull);
+        expect_tag_qword(pattrinfo, 22, TAG_UPTO_BIN_PRODUCT_VERSION, 0x1000000000001ull);
+        expect_tag_dword(pattrinfo, 23, TAG_LINK_DATE, 0x12345);
+        expect_tag_dword(pattrinfo, 24, TAG_UPTO_LINK_DATE, 0x12345);
+        expect_tag_str(pattrinfo, 25, TAG_EXPORT_NAME, EXPORT_NAME);
+        expect_tag_dword(pattrinfo, 26, TAG_VER_LANGUAGE, 0xffff);
+        expect_tag_dword(pattrinfo, 27, TAG_EXE_WRAPPER, 0x0);
+    }
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+
+
+    /* Disable resource and exports */
+    test_create_exe("testxx.exe", 1);
+
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
+    ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
+    ok(num == 28, "expected 28 items, got %d.\n", num);
+
+    if (num == 28 && ret)
+    {
+        expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0x800);
+        expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0xea7caffd);
+        expect_tag_skip_range(pattrinfo, 2, 16);
+        expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x3); /* Win32 */
+        expect_tag_dword(pattrinfo, 17, TAG_PE_CHECKSUM, 0xBAAD);
+        expect_tag_dword(pattrinfo, 18, TAG_LINKER_VERSION, 0x40002);
+        expect_tag_skip_range(pattrinfo, 19, 23);
+        expect_tag_dword(pattrinfo, 23, TAG_LINK_DATE, 0x12345);
+        expect_tag_dword(pattrinfo, 24, TAG_UPTO_LINK_DATE, 0x12345);
+        expect_tag_skip(pattrinfo, 25); /* TAG_EXPORT_NAME */
+        expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
+        expect_tag_dword(pattrinfo, 27, TAG_EXE_WRAPPER, 0x0);
+    }
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+
+    /* A file with just 'MZ' */
+    test_create_file("testxx.exe", "MZ", 2);
+
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
+    ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
+    ok(num == 28, "expected 28 items, got %d.\n", num);
+
+    if (num == 28 && ret)
+    {
+        expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0x2);
+        expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0);
+        expect_tag_skip_range(pattrinfo, 2, 16);
+        expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x1);
+        expect_tag_skip_range(pattrinfo, 17, 26);
+        expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
+        expect_tag_skip(pattrinfo, 27); /* TAG_EXE_WRAPPER */
+    }
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+
+    /* Empty file */
+    test_create_file("testxx.exe", NULL, 0);
+
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
+    ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
+    ok(num == 28, "expected 28 items, got %d.\n", num);
+
+    if (num == 28 && ret)
+    {
+        expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0);
+        expect_tag_skip_range(pattrinfo, 1, 26);
+        expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
+        expect_tag_skip(pattrinfo, 27); /* TAG_EXE_WRAPPER */
+    }
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+
+    /* minimal NE executable */
+    test_create_ne("testxx.exe", 0);
+
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
+    ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
+    ok(num == 28, "expected 28 items, got %d.\n", num);
+
+    if (num == 28 && ret)
+    {
+        expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0xa8);
+        expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0xf2abe4e9);
+        expect_tag_skip_range(pattrinfo, 2, 16);
+        expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x2);
+        expect_tag_skip(pattrinfo, 17); /* TAG_PE_CHECKSUM */
+        expect_tag_skip(pattrinfo, 18); /* TAG_LINKER_VERSION */
+        expect_tag_str(pattrinfo, 19, TAG_16BIT_DESCRIPTION, OS2_DESCRIPTION);
+        expect_tag_str(pattrinfo, 20, TAG_16BIT_MODULE_NAME, OS2_EXPORT_NAME);
+        expect_tag_skip_range(pattrinfo, 21, 26);
+        expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
+        expect_tag_skip(pattrinfo, 27); /* TAG_EXE_WRAPPER */
+    }
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+
+    /* NE executable with description / module name pointers zero, to show they are always used */
+    test_create_ne("testxx.exe", 1);
+
+    ret = pSdbGetFileAttributes(path, &pattrinfo, &num);
+    ok(ret != FALSE, "expected SdbGetFileAttributes to succeed.\n");
+    ok(pattrinfo != (PATTRINFO)0xdead, "expected a valid pointer.\n");
+    ok(num == 28, "expected 28 items, got %d.\n", num);
+
+    if (num == 28 && ret)
+    {
+        expect_tag_dword(pattrinfo, 0, TAG_SIZE, 0xa8);
+        expect_tag_dword(pattrinfo, 1, TAG_CHECKSUM, 0xddcbe4c9);
+        expect_tag_skip_range(pattrinfo, 2, 16);
+        expect_tag_dword(pattrinfo, 16, TAG_MODULE_TYPE, 0x2);
+        expect_tag_skip(pattrinfo, 17); /* TAG_PE_CHECKSUM */
+        expect_tag_skip(pattrinfo, 18); /* TAG_LINKER_VERSION */
+        expect_tag_str(pattrinfo, 19, TAG_16BIT_DESCRIPTION, OS2_DESCRIPTION_broken);   /* the 'Z' from 'MZ' */
+        expect_tag_str(pattrinfo, 20, TAG_16BIT_MODULE_NAME, OS2_EXPORT_NAME_broken);   /* the 'E' from 'NE' */
+        expect_tag_skip_range(pattrinfo, 21, 26);
+        expect_tag_empty(pattrinfo, 26); /* TAG_VER_LANGUAGE */
+        expect_tag_skip(pattrinfo, 27); /* TAG_EXE_WRAPPER */
+    }
+    if (ret)
+        pSdbFreeFileAttributes(pattrinfo);
+
+    test_crc(1, 0);
+    test_crc(2, 0);
+    test_crc(3, 0);
+    test_crc(4, 0x2020202);
+    test_crc(5, 0x2020202);
+    test_crc(6, 0x2020202);
+    test_crc(7, 0x2020202);
+    test_crc(8, 0x81818181);
+    test_crc(9, 0x81818181);
+    test_crc(10, 0x81818181);
+    test_crc(11, 0x81818181);
+    test_crc(12, 0xc2c2c2c2);
+    test_crc(16, 0x62626262);
+
+    /* This seems to be the cutoff point */
+    test_crc2(0xffc, 4, 0xfbfbfcfc);
+    test_crc2(0xffc, 8, 0x7070717);
+    test_crc2(0xffc, 0xcc, 0xc8eba002);
+    test_crc2(0xffc, 0, 0x4622028d);
+
+    test_crc2(0x1000, 4, 0x80);
+    test_crc2(0x1000, 8, 0x8787878f);
+    test_crc2(0x1000, 0xcc, 0x4adc3667);
+    test_crc2(0x1000, 0, 0xa3108044);
+
+    /* Here is another cutoff point */
+    test_crc2(0x11fc, 4, 0x80);
+    test_crc2(0x11fc, 8, 0x8787878f);
+    test_crc2(0x11fc, 0xcc, 0x4adc3667);
+    test_crc2(0x11fc, 0, 0xf03e0800);
+
+    test_crc2(0x1200, 4, 0x80);
+    test_crc2(0x1200, 8, 0x8787878f);
+    test_crc2(0x1200, 0xcc, 0x4adc3667);
+    test_crc2(0x1200, 0, 0xa3108044);
+
+    /* After that, it stays the same for all sizes */
+    test_crc2(0xf000, 4, 0x80);
+    test_crc2(0xf000, 8, 0x8787878f);
+    test_crc2(0xf000, 0xcc, 0x4adc3667);
+    test_crc2(0xf000, 0, 0xa3108044);
+
+
+    DeleteFileA("testxx.exe");
+}
+
 START_TEST(apphelp)
 {
     RTL_OSVERSIONINFOEXW rtlinfo;
@@ -383,6 +820,10 @@ START_TEST(apphelp)
     //SetEnvironmentVariable("DEBUGCHANNEL", "+apphelp");
     hdll = LoadLibraryA("apphelp.dll");
     pSdbTagToString = (void *) GetProcAddress(hdll, "SdbTagToString");
+    pSdbGetFileAttributes = (void *) GetProcAddress(hdll, "SdbGetFileAttributes");
+    pSdbFreeFileAttributes = (void *) GetProcAddress(hdll, "SdbFreeFileAttributes");
+
+    test_ApplicationAttributes();
     test_SdbTagToString();
 #ifdef __REACTOS__
     if (g_Version < VERSION_WIN7)