[PATCH 8/8] comctl32/tests: Add tests for NM_CUSTOMDRAW buttons

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Mar 4 10:25:21 CST 2019


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/comctl32/tests/button.c | 240 ++++++++++++++++++++++++++++++++---
 1 file changed, 222 insertions(+), 18 deletions(-)

diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c
index 753aa24..25208b9 100644
--- a/dlls/comctl32/tests/button.c
+++ b/dlls/comctl32/tests/button.c
@@ -39,8 +39,9 @@ static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
 /****************** button message test *************************/
 #define ID_BUTTON 0x000e
 
-#define COMBINED_SEQ_INDEX 0
-#define NUM_MSG_SEQUENCES  1
+#define COMBINED_SEQ_INDEX  0
+#define PARENT_CD_SEQ_INDEX 1
+#define NUM_MSG_SEQUENCES   2
 
 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
 
@@ -152,11 +153,38 @@ static LRESULT CALLBACK button_subclass_proc(HWND hwnd, UINT message, WPARAM wPa
     return ret;
 }
 
+static struct
+{
+    DWORD button;
+    UINT line;
+    UINT state;
+    DWORD ret;
+    BOOL empty;
+} test_cd;
+
+#define set_test_cd_state(s) do { \
+    test_cd.state = (s); \
+    test_cd.empty = TRUE; \
+    test_cd.line = __LINE__; \
+} while (0)
+
+#define set_test_cd_ret(r) do { \
+    test_cd.ret = (r); \
+    test_cd.empty = TRUE; \
+    test_cd.line = __LINE__; \
+} while (0)
+
+static void disable_test_cd(void)
+{
+    test_cd.line = 0;
+}
+
 static LRESULT WINAPI test_parent_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static LONG defwndproc_counter = 0;
     static LONG beginpaint_counter = 0;
     struct message msg = { 0 };
+    NMCUSTOMDRAW *cd = (NMCUSTOMDRAW*)lParam;
     LRESULT ret;
 
     if (ignore_message( message )) return 0;
@@ -176,6 +204,46 @@ static LRESULT WINAPI test_parent_wndproc(HWND hwnd, UINT message, WPARAM wParam
         add_message(sequences, COMBINED_SEQ_INDEX, &msg);
     }
 
+    if (message == WM_NOTIFY && cd->hdr.code == NM_CUSTOMDRAW && test_cd.line)
+    {
+        /* Ignore an inconsistency across Windows versions */
+        UINT state = cd->uItemState & ~CDIS_SHOWKEYBOARDCUES;
+        test_cd.empty = FALSE;
+
+        ok_(__FILE__,test_cd.line)(!(cd->dwDrawStage & CDDS_ITEM),
+            "[%u] CDDS_ITEM is set\n", test_cd.button);
+
+        ok_(__FILE__,test_cd.line)(state == test_cd.state,
+            "[%u] expected uItemState %u, got %u\n", test_cd.button,
+            test_cd.state, state);
+
+        msg.message = message;
+        msg.flags = sent|parent|wparam|lparam|id|custdraw;
+        msg.wParam = wParam;
+        msg.lParam = lParam;
+        msg.id = NM_CUSTOMDRAW;
+        msg.stage = cd->dwDrawStage;
+        add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
+
+        ret = test_cd.ret;
+        switch (msg.stage)
+        {
+            case CDDS_PREERASE:
+                ret &= ~CDRF_NOTIFYPOSTPAINT;
+                cd->dwItemSpec = 0xdeadbeef;
+                break;
+            case CDDS_PREPAINT:
+                ret &= ~CDRF_NOTIFYPOSTERASE;
+                break;
+            case CDDS_POSTERASE:
+            case CDDS_POSTPAINT:
+                ok_(__FILE__,test_cd.line)(cd->dwItemSpec == 0xdeadbeef,
+                    "[%u] NMCUSTOMDRAW was not shared, stage %u\n", test_cd.button, msg.stage);
+                break;
+        }
+        return ret;
+    }
+
     if (message == WM_PAINT)
     {
         PAINTSTRUCT ps;
@@ -453,6 +521,50 @@ static const struct message setcheck_radio_redraw_seq[] =
     { 0 }
 };
 
+static const struct message empty_cd_seq[] = { { 0 } };
+
+static const struct message pre_cd_seq[] =
+{
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
+    { 0 }
+};
+
+static const struct message pre_pre_cd_seq[] =
+{
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
+
+    /* Some Windows configurations paint twice under certain conditions */
+    { WM_NOTIFY, sent|parent|id|custdraw|optional, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
+    { WM_NOTIFY, sent|parent|id|custdraw|optional, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
+    { 0 }
+};
+
+static const struct message pre_post_pre_cd_seq[] =
+{
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTERASE },
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
+    { 0 }
+};
+
+static const struct message pre_pre_post_cd_seq[] =
+{
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
+    { 0 }
+};
+
+static const struct message pre_post_pre_post_cd_seq[] =
+{
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREERASE },
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTERASE },
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
+    { WM_NOTIFY, sent|parent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
+    { 0 }
+};
+
 static HWND create_button(DWORD style, HWND parent)
 {
     HMENU menuid = 0;
@@ -471,6 +583,13 @@ static HWND create_button(DWORD style, HWND parent)
 
 static void test_button_messages(void)
 {
+    enum cd_seq_type
+    {
+        cd_seq_empty,
+        cd_seq_normal,
+        cd_seq_optional
+    };
+
     static const struct
     {
         DWORD style;
@@ -481,55 +600,74 @@ static void test_button_messages(void)
         const struct message *setstate;
         const struct message *clearstate;
         const struct message *setcheck;
+        enum cd_seq_type cd_setfocus_type;
+        enum cd_seq_type cd_setstyle_type;
+        enum cd_seq_type cd_setstate_type;
+        enum cd_seq_type cd_setcheck_type;
     } button[] = {
         { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
           setfocus_seq, killfocus_seq, setstyle_seq,
-          setstate_seq, setstate_seq, setcheck_ignored_seq },
+          setstate_seq, setstate_seq, setcheck_ignored_seq,
+          cd_seq_normal, cd_seq_normal, cd_seq_normal, cd_seq_optional },
         { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
           setfocus_seq, killfocus_seq, setstyle_seq,
-          setstate_seq, setstate_seq, setcheck_ignored_seq },
+          setstate_seq, setstate_seq, setcheck_ignored_seq,
+          cd_seq_normal, cd_seq_normal, cd_seq_normal, cd_seq_optional },
         { BS_CHECKBOX, DLGC_BUTTON,
           setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
-          setstate_static_seq, setstate_static_seq, setcheck_static_seq },
+          setstate_static_seq, setstate_static_seq, setcheck_static_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
         { BS_AUTOCHECKBOX, DLGC_BUTTON,
           setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
-          setstate_static_seq, setstate_static_seq, setcheck_static_seq },
+          setstate_static_seq, setstate_static_seq, setcheck_static_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
         { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
           setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
-          setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq },
+          setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
         { BS_3STATE, DLGC_BUTTON,
           setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
-          setstate_static_seq, setstate_static_seq, setcheck_static_seq },
+          setstate_static_seq, setstate_static_seq, setcheck_static_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
         { BS_AUTO3STATE, DLGC_BUTTON,
           setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
-          setstate_static_seq, setstate_static_seq, setcheck_static_seq },
+          setstate_static_seq, setstate_static_seq, setcheck_static_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
         { BS_GROUPBOX, DLGC_STATIC,
           setfocus_groupbox_seq, killfocus_static_seq, setstyle_static_seq,
-          setstate_static_seq, setstate_static_seq, setcheck_ignored_seq },
+          setstate_static_seq, setstate_static_seq, setcheck_ignored_seq,
+          cd_seq_empty, cd_seq_empty, cd_seq_empty, cd_seq_empty },
         { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
           setfocus_seq, killfocus_seq, setstyle_user_seq,
-          setstate_user_seq, clearstate_seq, setcheck_ignored_seq },
+          setstate_user_seq, clearstate_seq, setcheck_ignored_seq,
+          cd_seq_normal, cd_seq_empty, cd_seq_empty, cd_seq_empty },
         { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
           setfocus_static_seq, killfocus_static_seq, setstyle_static_seq,
-          setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq },
+          setstate_static_seq, setstate_static_seq, setcheck_radio_redraw_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_optional },
         { BS_OWNERDRAW, DLGC_BUTTON,
           setfocus_ownerdraw_seq, killfocus_ownerdraw_seq, setstyle_ownerdraw_seq,
-          setstate_ownerdraw_seq, clearstate_ownerdraw_seq, setcheck_ignored_seq },
+          setstate_ownerdraw_seq, clearstate_ownerdraw_seq, setcheck_ignored_seq,
+          cd_seq_empty, cd_seq_empty, cd_seq_empty, cd_seq_empty },
         { BS_SPLITBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON | DLGC_WANTARROWS,
           setfocus_seq, killfocus_seq, setstyle_seq,
-          setstate_seq, setstate_seq, setcheck_ignored_seq },
+          setstate_seq, setstate_seq, setcheck_ignored_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_empty },
         { BS_DEFSPLITBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON | DLGC_WANTARROWS,
           setfocus_seq, killfocus_seq, setstyle_seq,
-          setstate_seq, setstate_seq, setcheck_ignored_seq },
+          setstate_seq, setstate_seq, setcheck_ignored_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_empty },
         { BS_COMMANDLINK, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
           setfocus_seq, killfocus_seq, setstyle_seq,
-          setstate_seq, setstate_seq, setcheck_ignored_seq },
+          setstate_seq, setstate_seq, setcheck_ignored_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_empty },
         { BS_DEFCOMMANDLINK, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
           setfocus_seq, killfocus_seq, setstyle_seq,
-          setstate_seq, setstate_seq, setcheck_ignored_seq },
+          setstate_seq, setstate_seq, setcheck_ignored_seq,
+          cd_seq_optional, cd_seq_optional, cd_seq_optional, cd_seq_empty }
     };
     LOGFONTA logfont = { 0 };
-    const struct message *seq;
+    const struct message *seq, *cd_seq;
     HFONT zfont, hfont2;
     unsigned int i;
     HWND hwnd, parent;
@@ -557,6 +695,11 @@ static void test_button_messages(void)
     hfont2 = CreateFontIndirectA(&logfont);
     ok(hfont2 != NULL, "Failed to create Tahoma font\n");
 
+    #define check_cd_seq(type, context) do { \
+        if (button[i].type != cd_seq_optional || !test_cd.empty) \
+            ok_sequence(sequences, PARENT_CD_SEQ_INDEX, cd_seq, "[CustomDraw] " context, FALSE); \
+    } while(0)
+
     for (i = 0; i < ARRAY_SIZE(button); i++)
     {
         HFONT prevfont, hfont;
@@ -564,6 +707,7 @@ static void test_button_messages(void)
         DWORD style, state;
         HDC hdc;
 
+        test_cd.button = button[i].style;
         hwnd = create_button(button[i].style, parent);
         ok(hwnd != NULL, "Failed to create a button.\n");
 
@@ -591,7 +735,10 @@ static void test_button_messages(void)
         SetFocus(0);
         flush_events();
         SetFocus(0);
+        cd_seq = (button[i].cd_setfocus_type == cd_seq_empty) ? empty_cd_seq : pre_pre_cd_seq;
         flush_sequences(sequences, NUM_MSG_SEQUENCES);
+        set_test_cd_ret(CDRF_DODEFAULT);
+        set_test_cd_state(CDIS_FOCUS);
 
         todo = button[i].style != BS_OWNERDRAW;
         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
@@ -599,18 +746,25 @@ static void test_button_messages(void)
         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
         ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setfocus, "SetFocus(hwnd) on a button", todo);
+        check_cd_seq(cd_setfocus_type, "SetFocus(hwnd)");
 
+        set_test_cd_state(0);
         SetFocus(0);
         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
         ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].killfocus, "SetFocus(0) on a button", FALSE);
+        check_cd_seq(cd_setfocus_type, "SetFocus(0)");
         ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
 
+        cd_seq = (button[i].cd_setstyle_type == cd_seq_empty) ? empty_cd_seq : pre_pre_cd_seq;
+        set_test_cd_state(0);
+
         SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
         todo = button[i].style == BS_OWNERDRAW;
         ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setstyle, "BM_SETSTYLE on a button", todo);
+        check_cd_seq(cd_setstyle_type, "BM_SETSTYLE");
 
         style = GetWindowLongA(hwnd, GWL_STYLE);
         style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
@@ -620,12 +774,15 @@ static void test_button_messages(void)
         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
         ok(state == 0, "expected state 0, got %04x\n", state);
 
+        cd_seq = (button[i].cd_setstate_type == cd_seq_empty) ? empty_cd_seq : pre_pre_cd_seq;
         flush_sequences(sequences, NUM_MSG_SEQUENCES);
+        set_test_cd_state(CDIS_SELECTED);
 
         SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
         ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
+        check_cd_seq(cd_setstate_type, "BM_SETSTATE/TRUE");
 
         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
         ok(state == BST_PUSHED, "expected state 0x0004, got %04x\n", state);
@@ -635,11 +792,13 @@ static void test_button_messages(void)
         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
 
         flush_sequences(sequences, NUM_MSG_SEQUENCES);
+        set_test_cd_state(0);
 
         SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
         ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
+        check_cd_seq(cd_setstate_type, "BM_SETSTATE/FALSE");
 
         state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
         ok(state == 0, "expected state 0, got %04x\n", state);
@@ -651,7 +810,9 @@ static void test_button_messages(void)
         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
 
+        cd_seq = (button[i].cd_setcheck_type == cd_seq_empty) ? empty_cd_seq : pre_pre_cd_seq;
         flush_sequences(sequences, NUM_MSG_SEQUENCES);
+        set_test_cd_state(0);
 
         if (button[i].style == BS_RADIOBUTTON ||
             button[i].style == BS_AUTORADIOBUTTON)
@@ -665,6 +826,7 @@ static void test_button_messages(void)
         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
         ok_sequence(sequences, COMBINED_SEQ_INDEX, seq, "BM_SETCHECK on a button", FALSE);
+        check_cd_seq(cd_setcheck_type, "BM_SETCHECK");
 
         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
         ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
@@ -674,11 +836,13 @@ static void test_button_messages(void)
         ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
 
         flush_sequences(sequences, NUM_MSG_SEQUENCES);
+        set_test_cd_state(0);
 
         SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
         SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
         ok_sequence(sequences, COMBINED_SEQ_INDEX, button[i].setcheck, "BM_SETCHECK on a button", FALSE);
+        check_cd_seq(cd_setcheck_type, "BM_SETCHECK");
 
         state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
         if (button[i].style == BS_PUSHBUTTON ||
@@ -726,9 +890,49 @@ static void test_button_messages(void)
 
         DeleteDC(hdc);
 
+        /* Test Custom Draw return values */
+        if (button[i].cd_setfocus_type != cd_seq_empty &&
+            broken(button[i].style != BS_USERBUTTON) /* WinXP */)
+        {
+            static const struct
+            {
+                const char *context;
+                LRESULT val;
+                const struct message *seq;
+            } ret[] = {
+                { "CDRF_DODEFAULT", CDRF_DODEFAULT, pre_pre_cd_seq },
+                { "CDRF_DOERASE", CDRF_DOERASE, pre_pre_cd_seq },
+                { "CDRF_SKIPDEFAULT", CDRF_SKIPDEFAULT, pre_cd_seq },
+                { "CDRF_SKIPDEFAULT | CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT",
+                   CDRF_SKIPDEFAULT | CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT, pre_cd_seq },
+                { "CDRF_NOTIFYPOSTERASE", CDRF_NOTIFYPOSTERASE, pre_post_pre_cd_seq },
+                { "CDRF_NOTIFYPOSTPAINT", CDRF_NOTIFYPOSTPAINT, pre_pre_post_cd_seq },
+                { "CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT",
+                   CDRF_NOTIFYPOSTERASE | CDRF_NOTIFYPOSTPAINT, pre_post_pre_post_cd_seq },
+            };
+            UINT k = 0;
+
+            for (k = 0; k < ARRAY_SIZE(ret); k++)
+            {
+                disable_test_cd();
+                SetFocus(0);
+                set_test_cd_ret(ret[k].val);
+                set_test_cd_state(CDIS_FOCUS);
+                SetFocus(hwnd);
+                flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+                while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+                if (button[i].cd_setfocus_type != cd_seq_optional || !test_cd.empty)
+                    ok_sequence(sequences, PARENT_CD_SEQ_INDEX, ret[k].seq, ret[k].context, FALSE);
+            }
+        }
+
+        disable_test_cd();
         DestroyWindow(hwnd);
     }
 
+    #undef check_cd_seq
+
     DeleteObject(hfont2);
     DestroyWindow(parent);
 
-- 
2.20.1




More information about the wine-devel mailing list