[PATCH] kernel32: Implement FormatMessage variable prefixes I, I32, and I64

Alex Henrie alexhenrie24 at gmail.com
Tue Nov 20 00:58:10 CST 2018


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=33392
Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 dlls/kernel32/format_msg.c       | 26 +++++++++++++++-
 dlls/kernel32/tests/format_msg.c | 51 +++++++++++++++++++++++++-------
 2 files changed, 66 insertions(+), 11 deletions(-)

diff --git a/dlls/kernel32/format_msg.c b/dlls/kernel32/format_msg.c
index 5741713d81..bd4b2df110 100644
--- a/dlls/kernel32/format_msg.c
+++ b/dlls/kernel32/format_msg.c
@@ -249,7 +249,31 @@ static LPCWSTR format_insert( BOOL unicode_caller, int insert, LPCWSTR format,
     {
         *p++ = 'c';
     }
-    /* FIXME: handle I64 etc. */
+    /* check for 32-bit integer format */
+    else if (format[0] == 'I' && format[1] == '3' && format[2] == '2' &&
+             (format[3] == 'd' || format[3] == 'i' || format[3] == 'u' ||
+              format[3] == 'o' || format[3] == 'x' || format[3] == 'X'))
+    {
+        *p++ = format[3];
+    }
+    /* check for 64-bit integer format */
+    else if (format[0] == 'I' && format[1] == '6' && format[2] == '4' &&
+             (format[3] == 'd' || format[3] == 'i' || format[3] == 'u' ||
+              format[3] == 'o' || format[3] == 'x' || format[3] == 'X'))
+    {
+        *p++ = 'l';
+        *p++ = format[3];
+    }
+    /* check for pointer-size integer format */
+    else if (format[0] == 'I' &&
+             (format[1] == 'd' || format[1] == 'i' || format[1] == 'u' ||
+              format[1] == 'o' || format[1] == 'x' || format[1] == 'x'))
+    {
+#ifdef _WIN64
+        *p++ = 'l';
+#endif
+        *p++ = format[1];
+    }
     else while (*format && *format != '!') *p++ = *format++;
 
     *p = 0;
diff --git a/dlls/kernel32/tests/format_msg.c b/dlls/kernel32/tests/format_msg.c
index 57ee78af9e..8aab9e7b43 100644
--- a/dlls/kernel32/tests/format_msg.c
+++ b/dlls/kernel32/tests/format_msg.c
@@ -26,6 +26,8 @@
 
 #define ULL(a,b)   (((ULONG64)(a) << 32) | (b))
 
+static const BOOL is_32bit = (sizeof(void *) == sizeof(int));
+
 static DWORD WINAPIV doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id,
                           LPSTR out, DWORD outsize, ... )
 {
@@ -98,6 +100,9 @@ static void test_message_from_string_wide(void)
     static const WCHAR fmt_1oou1oou[] = {'%','1','!','*','.','*','u','!',',','%','1','!','*','.','*','u','!',0};
     static const WCHAR fmt_1oou3oou[] = {'%','1','!','*','.','*','u','!',',','%','3','!','*','.','*','u','!',0};
     static const WCHAR fmt_1oou4oou[] = {'%','1','!','*','.','*','u','!',',','%','4','!','*','.','*','u','!',0};
+    static const WCHAR fmt_1I32d[]     = {'%','1','!','I','3','2','d','!',0};
+    static const WCHAR fmt_1I64d[]     = {'%','1','!','I','6','4','d','!',0};
+    static const WCHAR fmt_1Id[]       = {'%','1','!','I','d','!',0};
 
     static const WCHAR s_123d[]      = {'1','2','3',0};
     static const WCHAR s_14d[]       = {' ',' ',' ','1',0};
@@ -390,6 +395,20 @@ static void test_message_from_string_wide(void)
         ok(r==12,"failed: r=%d\n",r);
     }
 
+    /* prefixes not shared with standard printf */
+
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1I32d, 0, 0, out, ARRAY_SIZE(out), 123);
+    ok(!lstrcmpW(s_123d, out), "failed out=%s\n", wine_dbgstr_w(out));
+    ok(r==3,"failed: r=%d\n", r);
+
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1I64d, 0, 0, out, ARRAY_SIZE(out), 123);
+    ok(!lstrcmpW(s_123d, out), "failed out=%s\n", wine_dbgstr_w(out));
+    ok(r==3,"failed: r=%d\n", r);
+
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1Id, 0, 0, out, ARRAY_SIZE(out), 123);
+    ok(!lstrcmpW(s_123d, out), "failed out=%s\n", wine_dbgstr_w(out));
+    ok(r==3,"failed: r=%d\n", r);
+
     /* change of pace... test the low byte of dwflags */
 
     /* line feed */
@@ -688,6 +707,20 @@ static void test_message_from_string(void)
         }
     }
 
+    /* prefixes not shared with standard printf */
+
+    r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I32d!", 0, 0, out, ARRAY_SIZE(out), 123);
+    ok(!strcmp("123", out),"failed out=[%s]\n",out);
+    ok(r==3,"failed: r=%d\n",r);
+
+    r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64d!", 0, 0, out, ARRAY_SIZE(out), 123);
+    ok(!strcmp("123", out),"failed out=[%s]\n",out);
+    ok(r==3,"failed: r=%d\n",r);
+
+    r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!Id!", 0, 0, out, ARRAY_SIZE(out), 123);
+    ok(!strcmp("123", out),"failed out=[%s]\n",out);
+    ok(r==3,"failed: r=%d\n",r);
+
     /* change of pace... test the low byte of dwflags */
 
     /* line feed */
@@ -1718,26 +1751,28 @@ static void test_message_from_64bit_number(void)
         UINT64 number;
         const char expected[32];
         int len;
+        BOOL todo32;
     } unsigned_tests[] =
     {
         { 0, "0", 1 },
         { 1234567890, "1234567890", 10},
-        { ULL(0xFFFFFFFF,0xFFFFFFFF), "18446744073709551615", 20 },
-        { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19 },
+        { ULL(0xFFFFFFFF,0xFFFFFFFF), "18446744073709551615", 20, TRUE },
+        { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19, TRUE },
     };
     static const struct
     {
         INT64 number;
         const char expected[32];
         int len;
+        BOOL todo32;
     } signed_tests[] =
     {
         { 0, "0" , 1},
         { 1234567890, "1234567890", 10 },
         { -1, "-1", 2},
         { ULL(0xFFFFFFFF,0xFFFFFFFF), "-1", 2},
-        { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19 },
-        { -ULL(0x7FFFFFFF,0xFFFFFFFF), "-9223372036854775807", 20},
+        { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19, TRUE },
+        { -ULL(0x7FFFFFFF,0xFFFFFFFF), "-9223372036854775807", 20, TRUE },
     };
     int i;
 
@@ -1746,14 +1781,12 @@ static void test_message_from_64bit_number(void)
         r = doitW(FORMAT_MESSAGE_FROM_STRING, I64u, 0, 0, outW, ARRAY_SIZE(outW),
                   unsigned_tests[i].number);
         MultiByteToWideChar(CP_ACP, 0, unsigned_tests[i].expected, -1, expW, ARRAY_SIZE(expW));
-todo_wine {
+todo_wine_if(is_32bit && unsigned_tests[i].todo32) {
         ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i,
                      unsigned_tests[i].expected, wine_dbgstr_w(outW));
         ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r);
-}
         r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64u!",
                   0, 0, outA, sizeof(outA), unsigned_tests[i].number);
-todo_wine {
         ok(!strcmp(outA, unsigned_tests[i].expected),"[%d] failed, expected %s, got %s\n", i,
                    unsigned_tests[i].expected, outA);
         ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r);
@@ -1765,14 +1798,12 @@ todo_wine {
         r = doitW(FORMAT_MESSAGE_FROM_STRING, I64d, 0, 0, outW, ARRAY_SIZE(outW),
                   signed_tests[i].number);
         MultiByteToWideChar(CP_ACP, 0, signed_tests[i].expected, -1, expW, ARRAY_SIZE(expW));
-todo_wine {
+todo_wine_if(is_32bit && signed_tests[i].todo32) {
         ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i,
                      signed_tests[i].expected, wine_dbgstr_w(outW));
         ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r);
-}
         r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64d!",
                   0, 0, outA, sizeof(outA), signed_tests[i].number);
-todo_wine {
         ok(!strcmp(outA, signed_tests[i].expected),"[%d] failed, expected %s, got %s\n", i,
                    signed_tests[i].expected, outA);
         ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r);
-- 
2.19.1




More information about the wine-devel mailing list