[PATCH 2/3] comctl32: Basic implementation of TaskDialogIndirect

Joachim Priesner joachim.priesner at web.de
Wed Oct 1 07:35:34 CDT 2014


This is part of an effort to replace the current TaskDialogIndirect stub (which uses MessageBoxW) with an own implementation.

In this patch, the actual basic implementation of TaskDialogIndirect is provided, which for now displays the main instruction and content text, as well as the icon.

Tested on openSuse 13.1.

---
 dlls/comctl32/comctl32.h   |   6 +
 dlls/comctl32/comctl32.rc  |  16 ++
 dlls/comctl32/taskdialog.c | 491 ++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 483 insertions(+), 30 deletions(-)

diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h
index b9b0574..cd6df21 100644
--- a/dlls/comctl32/comctl32.h
+++ b/dlls/comctl32/comctl32.h
@@ -65,6 +65,12 @@ extern HBRUSH  COMCTL32_hPattern55AABrush DECLSPEC_HIDDEN;
 
 #define IDS_SEPARATOR      1024
 
+/* Task dialog */
+#define IDC_MAIN_ICON        510
+#define IDC_MAIN_INSTRUCTION 511
+#define IDC_CONTENT          512
+#define IDC_BUTTON_LINE      513
+
 /* Toolbar imagelist bitmaps */
 #define IDB_STD_SMALL       120
 #define IDB_STD_LARGE       121
diff --git a/dlls/comctl32/comctl32.rc b/dlls/comctl32/comctl32.rc
index 87e2fd1..0f83df6 100644
--- a/dlls/comctl32/comctl32.rc
+++ b/dlls/comctl32/comctl32.rc
@@ -93,6 +93,22 @@ BEGIN
   LISTBOX       IDC_TOOLBARBTN_LBOX, 194,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
 END
 
+TASKDIALOG DIALOG 100, 80, 216, 168
+STYLE DS_MODALFRAME | DS_NOIDLEMSG | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+BEGIN
+  ICON          "",       IDC_MAIN_ICON, 8, 20, 16, 16, WS_CHILD | WS_VISIBLE
+  LTEXT         "",       IDC_MAIN_INSTRUCTION, 32, 4, 176, 48, WS_CHILD | WS_VISIBLE | WS_GROUP | SS_NOPREFIX
+  LTEXT         "",       IDC_CONTENT, 32, 4, 176, 48, WS_CHILD | WS_VISIBLE | WS_GROUP | SS_NOPREFIX
+  LTEXT         "",       IDC_BUTTON_LINE, 7, 129, 278, 1, SS_SUNKEN
+  PUSHBUTTON    "OK",     IDOK, 16, 56, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+  PUSHBUTTON    "&Yes",   IDYES, 306, 56, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+  PUSHBUTTON    "&No",    IDNO, 364, 56, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+  PUSHBUTTON    "Cancel", IDCANCEL, 74, 56, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+  PUSHBUTTON    "&Retry", IDRETRY, 190, 56, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+  PUSHBUTTON    "&Close", IDCLOSE, 132, 56, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+END
+
+
 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 
 #define WINE_FILEDESCRIPTION_STR "Wine Common Controls"
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index 0036202..a92a461 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -32,41 +32,472 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
 
+#define TASKDIALOG_BUTTON_LINE_HEIGHT 2
+#define TASKDIALOG_SPACING            8
+
+#define IMAGERES_QUESTION_ICON    MAKEINTRESOURCEW(0x63)
+#define IMAGERES_ERROR_ICON       MAKEINTRESOURCEW(0x62)
+#define IMAGERES_WARNING_ICON     MAKEINTRESOURCEW(0x54)
+#define IMAGERES_INFORMATION_ICON MAKEINTRESOURCEW(0x51)
+
+HICON TASKDIALOG_GetIcon(HINSTANCE hInstance, PCWSTR pszIcon)
+{
+    /* If hInstance is NULL and pszMainIcon is not one if the TD_*_ICON constants, the icon
+     * is taken from imageres.dll. Until this is implemented, hard-code some of the offsets
+     * for standard icons in imageres.dll. */
+    if (pszIcon == TD_ERROR_ICON || (hInstance == NULL && pszIcon == IMAGERES_ERROR_ICON))
+        return LoadIconW(0, (LPWSTR)IDI_ERROR);
+    else if (pszIcon == TD_WARNING_ICON || (hInstance == NULL && pszIcon == IMAGERES_WARNING_ICON))
+        return LoadIconW(0, (LPWSTR)IDI_WARNING);
+    else if (pszIcon == TD_INFORMATION_ICON || (hInstance == NULL && pszIcon == IMAGERES_INFORMATION_ICON))
+        return LoadIconW(0, (LPWSTR)IDI_INFORMATION);
+    else if (pszIcon == TD_SHIELD_ICON)
+        return LoadIconW(0, (LPWSTR)IDI_SHIELD);
+    else if (hInstance == NULL && pszIcon == IMAGERES_QUESTION_ICON)
+	return LoadIconW(0, (LPWSTR)IDI_QUESTION);
+    else if (hInstance)
+        return LoadIconW(hInstance, pszIcon);
+    return 0;
+}
+
+/*
+ * TaskDialog layout (not everything implemented yet):
+ *
+ * +------------------------------------------------------------+
+ * | Window title (fallback: executable file name)            X |
+ * +------------------------------------------------------------+
+ * | _THE   Main instruction                                    |
+ * | MAIN                                                       |
+ * | ICON   Content                                             |
+ * |                                                            |
+ * |        Expanded information if TDF_EXPAND_FOOTER AREA      |
+ * |        is not set.                                         |
+ * |                                                            |
+ * |        [Progress Bar or Marquee Progress Bar_____________] |
+ * |                                                            |
+ * |        (*) Radio button 1                                  |
+ * |        ( ) Radio button 2                                  |
+ * |                                                            |
+ * |        => User buttons if TDF_USE_COMMAND_LINKS or         |
+ * |           TDF_USE_COMMAND_LINKS_NOICON is set              |
+ * |                                                            |
+ * |        => In this case, the user buttons don't appear      |
+ * |           below.                                           |
+ * |                                                            |
+ * +============================================================+
+ * | (V) Expand/collapse        [User buttons] [Common buttons] |
+ * | [ ] Verification checkbox                                  |
+ * +============================================================+
+ * | ICON  Footer text                                          |
+ * |       which can span multiple lines.                       |
+ * +============================================================+
+ * | Expanded information if TDF_EXPAND_FOOTER_AREA is set      |
+ * +------------------------------------------------------------+
+ */
+static void TASKDIALOG_OnInit(HWND hwnd, TASKDIALOGCONFIG *pConfig)
+{
+    HFONT hNormalFont, hMainInstructionFont;
+    LOGFONTW mainInstructionFontAttributes = {0};
+    HWND hItem, hDefaultButton = 0;
+    HICON hIconMain = 0;
+    HDC hdc;
+    unsigned char hasButton = 0;
+    int i, nButtons, currentX, currentY;
+    int buttonWidth, buttonAreaWidth, buttonHeight;
+    int windowClientWidth, windowClientHeight, windowLeft, windowTop;
+    int windowBorderHeight, windowBorderWidth;
+    int mainIconHeight, mainIconLeft, mainIconWidth;
+    int mainAreaTextLeft, mainAreaTextWidth;
+    int contentTextWidth, contentTextHeight;
+    int mainInstructionWidth, mainInstructionHeight;
+    HMONITOR monitor = 0;
+    MONITORINFO mon_info;
+    LPCWSTR lpszContent, lpszMainInstruction;
+    WCHAR *windowTitleBuffer = NULL, *contentTextBuffer = NULL, *mainInstructionBuffer = NULL;
+    const WCHAR *ptr;
+    RECT rect;
+    static const int commonButtons[6] = { IDOK, IDYES, IDNO, IDCANCEL, IDRETRY, IDCLOSE };
+
+    /* Get the text to display. */
+    TRACE("pszWindowTitle=%s\n", debugstr_w(pConfig->pszWindowTitle));
+    if (IS_INTRESOURCE(pConfig->pszWindowTitle))
+    {
+        UINT len = LoadStringW(pConfig->hInstance, LOWORD(pConfig->pszWindowTitle), (LPWSTR)&ptr, 0);
+        if (len)
+        {
+            windowTitleBuffer = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+            if (!windowTitleBuffer)
+            {
+                EndDialog(hwnd, E_OUTOFMEMORY);
+                return;
+            }
+            memcpy(windowTitleBuffer, ptr, len * sizeof(WCHAR));
+            windowTitleBuffer[len] = 0;
+            SetWindowTextW(hwnd, windowTitleBuffer);
+        }
+        /* If the supplied window title is invalid, display the executable file name instead. */
+        else
+        {
+            windowTitleBuffer = HeapAlloc(GetProcessHeap(), 0, (MAX_PATH + 1) * sizeof(WCHAR));
+            if (!windowTitleBuffer)
+            {
+                EndDialog(hwnd, E_OUTOFMEMORY);
+                return;
+            }
+            GetModuleFileNameW(NULL, windowTitleBuffer, MAX_PATH);
+            windowTitleBuffer[MAX_PATH] = 0;
+            SetWindowTextW(hwnd, PathFindFileNameW(windowTitleBuffer));
+        }
+        HeapFree(GetProcessHeap(), 0, windowTitleBuffer);
+        windowTitleBuffer = NULL;
+    }
+    else SetWindowTextW(hwnd, pConfig->pszWindowTitle);
+
+    TRACE("pszMainInstruction=%s\n", debugstr_w(pConfig->pszMainInstruction));
+    if (IS_INTRESOURCE(pConfig->pszMainInstruction))
+    {
+        UINT len = LoadStringW(pConfig->hInstance, LOWORD(pConfig->pszMainInstruction), (LPWSTR)&ptr, 0);
+        mainInstructionBuffer = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+        if (!mainInstructionBuffer)
+        {
+            EndDialog(hwnd, E_OUTOFMEMORY);
+            return;
+        }
+        memcpy(mainInstructionBuffer, ptr, len * sizeof(WCHAR));
+        mainInstructionBuffer[len] = 0;
+        lpszMainInstruction = mainInstructionBuffer;
+    }
+    else lpszMainInstruction = pConfig->pszMainInstruction;
+    SetWindowTextW(GetDlgItem(hwnd, IDC_MAIN_INSTRUCTION), lpszMainInstruction);
+
+    TRACE("pszContent=%s\n", debugstr_w(pConfig->pszContent));
+    if (IS_INTRESOURCE(pConfig->pszContent))
+    {
+        UINT len = LoadStringW(pConfig->hInstance, LOWORD(pConfig->pszContent), (LPWSTR)&ptr, 0);
+        contentTextBuffer = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+        if (!contentTextBuffer)
+        {
+            EndDialog(hwnd, E_OUTOFMEMORY);
+            return;
+        }
+        memcpy(contentTextBuffer, ptr, len * sizeof(WCHAR));
+        contentTextBuffer[len] = 0;
+        lpszContent = contentTextBuffer;
+    }
+    else lpszContent = pConfig->pszContent;
+    SetWindowTextW(GetDlgItem(hwnd, IDC_CONTENT), lpszContent);
+
+    if (pConfig->pszFooter)
+    {
+        FIXME("pszFooter=%s\n", debugstr_w(pConfig->pszFooter));
+    }
+    if (pConfig->pszVerificationText)
+    {
+        FIXME("pszVerificationText=%s\n", debugstr_w(pConfig->pszVerificationText));
+    }
+    if (pConfig->pszExpandedInformation)
+    {
+        FIXME("pszExpandedInformation=%s\n", debugstr_w(pConfig->pszExpandedInformation));
+    }
+    if (pConfig->pszExpandedControlText)
+    {
+        FIXME("pszExpandedControlText=%s\n", debugstr_w(pConfig->pszExpandedControlText));
+    }
+    if (pConfig->pszCollapsedControlText)
+    {
+        FIXME("pszCollapsedControlText=%s\n", debugstr_w(pConfig->pszCollapsedControlText));
+    }
+
+    /* Destroy unused common buttons. */
+    TRACE("dwCommonButtons=%x\n", pConfig->dwCommonButtons);
+    if (!(pConfig->dwCommonButtons & TDCBF_YES_BUTTON))
+	DestroyWindow(GetDlgItem(hwnd, IDYES));
+    else hasButton = 1;
+    if (!(pConfig->dwCommonButtons & TDCBF_NO_BUTTON))
+	DestroyWindow(GetDlgItem(hwnd, IDNO));
+    else hasButton = 1;
+    if (!(pConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON))
+	DestroyWindow(GetDlgItem(hwnd, IDCANCEL));
+    else hasButton = 1;
+    if (!(pConfig->dwCommonButtons & TDCBF_RETRY_BUTTON))
+	DestroyWindow(GetDlgItem(hwnd, IDRETRY));
+    else hasButton = 1;
+    if (!(pConfig->dwCommonButtons & TDCBF_CLOSE_BUTTON))
+	DestroyWindow(GetDlgItem(hwnd, IDCLOSE));
+    else hasButton = 1;
+
+    /* Set user-defined buttons. */
+    if (pConfig->cButtons)
+        FIXME("Custom task dialog buttons not implemented.\n");
+    if (pConfig->cRadioButtons)
+        FIXME("Task dialog radio buttons not implemented.\n");
+
+    /* If no other buttons are specified, the OK button remains. */
+    if (!(pConfig->dwCommonButtons & TDCBF_OK_BUTTON) && hasButton)
+	DestroyWindow(GetDlgItem(hwnd, IDOK));
+
+    /* Get the main icon. */
+    if (pConfig->dwFlags & TDF_USE_HICON_MAIN)
+        hIconMain = pConfig->hMainIcon;
+    else
+        hIconMain = TASKDIALOG_GetIcon(pConfig->hInstance, pConfig->pszMainIcon);
+
+    /* Position everything. */
+    GetWindowRect(hwnd, &rect);
+    windowBorderHeight = rect.bottom - rect.top;
+    windowBorderWidth  = rect.right - rect.left;
+    GetClientRect(hwnd, &rect);
+    windowBorderHeight -= rect.bottom - rect.top;
+    windowBorderWidth  -= rect.right - rect.left;
+
+    /* Get the main icon size. */
+    if (hIconMain) {
+	SendDlgItemMessageW(hwnd, IDC_MAIN_ICON, STM_SETICON, (WPARAM)hIconMain, 0);
+        GetWindowRect(GetDlgItem(hwnd, IDC_MAIN_ICON), &rect);
+        MapWindowPoints(0, hwnd, (LPPOINT)&rect, 2);
+        mainIconHeight = rect.bottom - rect.top;
+        mainIconLeft = TASKDIALOG_SPACING;
+        mainIconWidth = rect.right - rect.left;
+    } else {
+        mainIconHeight = 0;
+        mainIconLeft = 0;
+        mainIconWidth = 0;
+    }
+
+    /* Set a bold font for the main instruction. */
+    hdc = GetDC(hwnd);
+    hNormalFont = SelectObject(hdc, (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0));
+
+    GetObjectW(hNormalFont, sizeof(mainInstructionFontAttributes), &mainInstructionFontAttributes);
+    mainInstructionFontAttributes.lfWeight = FW_BOLD;
+    hMainInstructionFont = CreateFontIndirectW(&mainInstructionFontAttributes);
+    SendMessageW(GetDlgItem(hwnd, IDC_MAIN_INSTRUCTION), WM_SETFONT, (WPARAM)hMainInstructionFont, 0);
+
+    /* Get the number of visible buttons and their size. */
+    buttonHeight = buttonWidth = 1;
+    nButtons = 0;
+    for (i = 0; i < (sizeof(commonButtons) / sizeof(commonButtons[0])); i++)
+    {
+	hItem = GetDlgItem(hwnd, commonButtons[i]);
+	if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE)
+	{
+	    WCHAR buttonText[1024];
+	    int w, h;
+	    nButtons++;
+	    if (GetWindowTextW(hItem, buttonText, 1024))
+	    {
+		DrawTextW(hdc, buttonText, -1, &rect, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT);
+		h = rect.bottom - rect.top;
+		w = rect.right - rect.left;
+		if (h > buttonHeight) buttonHeight = h;
+		if (w > buttonWidth)  buttonWidth = w ;
+	    }
+	}
+    }
+
+    /* Give the buttons some white space. */
+    buttonHeight *= 2;
+    buttonWidth = max(buttonWidth * 2, buttonHeight);
+    buttonAreaWidth = (buttonWidth + TASKDIALOG_SPACING) * nButtons - TASKDIALOG_SPACING;
+
+    mainAreaTextLeft = TASKDIALOG_SPACING;
+    if (mainIconWidth) mainAreaTextLeft += mainIconWidth + TASKDIALOG_SPACING;
+
+    /* Get the size of the texts in the main area.
+     * Minimum text width corresponds to space for the buttons. */
+    GetClientRect(GetDlgItem(hwnd, IDC_MAIN_INSTRUCTION), &rect);
+    rect.top = rect.left = rect.bottom = 0;
+    rect.right = max(rect.right, buttonAreaWidth);
+    SelectObject(hdc, hMainInstructionFont);
+    DrawTextW(hdc, lpszMainInstruction, -1, &rect,
+              DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
+    mainInstructionWidth = rect.right;
+    mainInstructionHeight = rect.bottom;
+
+    GetClientRect(GetDlgItem(hwnd, IDC_CONTENT), &rect);
+    rect.top = rect.left = rect.bottom = 0;
+    rect.right = max(rect.right, buttonAreaWidth);
+    SelectObject(hdc, hNormalFont);
+    DrawTextW(hdc, lpszContent, -1, &rect,
+	      DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_CALCRECT);
+    contentTextWidth = rect.right;
+    contentTextHeight = rect.bottom;
+
+    ReleaseDC(hwnd, hdc);
+
+    mainAreaTextWidth = max(mainInstructionWidth, contentTextWidth);
+    windowClientWidth = max(TASKDIALOG_SPACING + buttonAreaWidth,
+                            mainAreaTextLeft + mainAreaTextWidth) + TASKDIALOG_SPACING;
+    if (pConfig->cxWidth)
+        FIXME("Ignoring pConfig->cxWidth.\n");
+
+    /* Position everything from top to bottom. */
+    currentY = TASKDIALOG_SPACING;
+
+    /* Position the main icon. */
+    if (hIconMain)
+        SetWindowPos(GetDlgItem(hwnd, IDC_MAIN_ICON), 0, mainIconLeft, currentY, 0, 0,
+	             SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+    else DestroyWindow(GetDlgItem(hwnd, IDC_MAIN_ICON));
+
+    /* Position the texts in the main area. */
+    if (mainInstructionHeight > 0)
+    {
+        SetWindowPos(GetDlgItem(hwnd, IDC_MAIN_INSTRUCTION), 0, mainAreaTextLeft, currentY,
+                     mainInstructionWidth, mainInstructionHeight,
+                     SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+        currentY += mainInstructionHeight + TASKDIALOG_SPACING;
+    }
+    else DestroyWindow(GetDlgItem(hwnd, IDC_MAIN_INSTRUCTION));
+
+    if (contentTextHeight > 0)
+    {
+        SetWindowPos(GetDlgItem(hwnd, IDC_CONTENT), 0, mainAreaTextLeft, currentY,
+                     contentTextWidth, contentTextHeight,
+                     SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+        currentY += contentTextHeight + TASKDIALOG_SPACING;
+    }
+    else DestroyWindow(GetDlgItem(hwnd, IDC_CONTENT));
+
+    currentY = max(currentY, TASKDIALOG_SPACING + mainIconHeight + TASKDIALOG_SPACING);
+
+    /* Position the button separator line. */
+    SetWindowPos(GetDlgItem(hwnd, IDC_BUTTON_LINE), 0,
+                 0, currentY, windowClientWidth, TASKDIALOG_BUTTON_LINE_HEIGHT,
+		 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+
+    currentY += TASKDIALOG_BUTTON_LINE_HEIGHT + TASKDIALOG_SPACING;
+
+    /* Position the buttons: right-aligned */
+    currentX = windowClientWidth - TASKDIALOG_SPACING - buttonAreaWidth;
+    for (i = 0; i < (sizeof(commonButtons) / sizeof(commonButtons[0])); i++)
+    {
+	hItem = GetDlgItem(hwnd, commonButtons[i]);
+	if (GetWindowLongW(hItem, GWL_STYLE) & WS_VISIBLE)
+        {
+            if (hDefaultButton == 0 || pConfig->nDefaultButton == commonButtons[i])
+                hDefaultButton = hItem;
+	    SetWindowPos(hItem, 0, currentX, currentY, buttonWidth, buttonHeight,
+			 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+	    currentX += buttonWidth + TASKDIALOG_SPACING;
+	}
+    }
+
+    if (hDefaultButton)
+    {
+        SetFocus(hDefaultButton);
+        SendMessageW(hDefaultButton, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
+    }
+
+    currentY += buttonHeight + TASKDIALOG_SPACING;
+    windowClientHeight = currentY;
+
+    /* Query parent window/desktop size and center window. */
+    monitor = MonitorFromWindow(pConfig->hwndParent ? pConfig->hwndParent : GetActiveWindow(),
+                                MONITOR_DEFAULTTOPRIMARY);
+    mon_info.cbSize = sizeof(mon_info);
+    GetMonitorInfoW(monitor, &mon_info);
+    windowLeft = (mon_info.rcWork.left + mon_info.rcWork.right
+                  - (windowClientWidth + windowBorderWidth)) / 2;
+    windowTop = (mon_info.rcWork.top + mon_info.rcWork.bottom
+                 - (windowClientHeight + windowBorderHeight)) / 2;
+    SetWindowPos(hwnd, 0, windowLeft, windowTop,
+                 windowClientWidth + windowBorderWidth, windowClientHeight + windowBorderHeight,
+		 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
+
+    DeleteObject(hMainInstructionFont);
+    if (contentTextBuffer)
+        HeapFree(GetProcessHeap(), 0, contentTextBuffer);
+    if (mainInstructionBuffer)
+        HeapFree(GetProcessHeap(), 0, mainInstructionBuffer);
+}
+
+
+/**************************************************************************
+ *           TASKDIALOG_DlgProc
+ *
+ * Dialog procedure for task dialogs.
+ */
+static INT_PTR CALLBACK TASKDIALOG_DlgProc(HWND hwnd, UINT message,
+                                           WPARAM wParam, LPARAM lParam)
+{
+    switch(message) {
+    case WM_INITDIALOG:
+    {
+        TASKDIALOGCONFIG *config = (TASKDIALOGCONFIG*)lParam;
+        TASKDIALOG_OnInit(hwnd, config);
+        break;
+    }
+
+    case WM_COMMAND:
+    {
+        if (LOWORD(wParam) == IDCANCEL)
+            /* IDCANCEL button must be present or TDF_ALLOW_DIALOG_CANCELLATION flag set. */
+            FIXME("Not checking if dialog cancellation is allowed\n");
+        EndDialog(hwnd, wParam);
+        break;
+    }
+
+    default:
+        /* Ignore all the other messages. */
+        TRACE("Message number 0x%04x is being ignored.\n", message);
+        break;
+    }
+    return 0;
+}
+
 /***********************************************************************
  * TaskDialogIndirect [COMCTL32.@]
  */
 HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton,
                                   int *pnRadioButton, BOOL *pfVerificationFlagChecked)
 {
-    UINT uType = 0;
-    INT  ret;
-    FIXME("%p, %p, %p, %p\n", pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked);
-
-    if (pTaskConfig->dwCommonButtons & TDCBF_YES_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_NO_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
-        uType |= MB_YESNOCANCEL;
-    else
-    if (pTaskConfig->dwCommonButtons & TDCBF_YES_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_NO_BUTTON)
-        uType |= MB_YESNO;
-    else
-    if (pTaskConfig->dwCommonButtons & TDCBF_RETRY_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
-        uType |= MB_RETRYCANCEL;
-    else
-    if (pTaskConfig->dwCommonButtons & TDCBF_OK_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
-        uType |= MB_OKCANCEL;
+    LPVOID template;
+    HRSRC hRes;
+    INT_PTR ret;
+    static const WCHAR task_dialog_resource_nameW[] = { 'T','A','S','K','D','I','A','L','O','G',0 };
+
+    if (!pTaskConfig) {
+        TRACE("pTaskConfig = NULL\n");
+        return E_INVALIDARG;
+    }
+
+    TRACE("hWndParent=%p, hInstance=%p, dwCommonButtons=%x, pnButton=%p\n",
+          pTaskConfig->hwndParent, pTaskConfig->hInstance, pTaskConfig->dwCommonButtons,
+          pnButton);
+
+    if (!(hRes = FindResourceExW(COMCTL32_hModule, (LPWSTR)RT_DIALOG,
+                                 task_dialog_resource_nameW, LANG_NEUTRAL)))
+    {
+        ERR("Cannot find TASKDIALOG resource\n");
+        return E_FAIL;
+    }
+    if (!(template = LoadResource(COMCTL32_hModule, hRes)))
+    {
+        ERR("Cannot load TASKDIALOG resource\n");
+        return E_FAIL;
+    }
+
+    ret = DialogBoxIndirectParamW(pTaskConfig->hInstance, template,
+                                  pTaskConfig->hwndParent, TASKDIALOG_DlgProc, (LPARAM)pTaskConfig);
+    if (pnRadioButton)
+    {
+        FIXME("Task dialog radio buttons not implemented.\n");
+        *pnRadioButton = pTaskConfig->nDefaultButton;
+    }
+    if (pfVerificationFlagChecked)
+    {
+        FIXME("Task dialog verification check box not implemented.\n");
+        *pfVerificationFlagChecked = TRUE;
+    }
+    if (ret > 0)
+    {
+        if (pnButton) *pnButton = ret;
+        return S_OK;
+    }
     else
-    if (pTaskConfig->dwCommonButtons & TDCBF_OK_BUTTON)
-        uType |= MB_OK;
-    ret = MessageBoxW(pTaskConfig->hwndParent, pTaskConfig->pszMainInstruction,
-                      pTaskConfig->pszWindowTitle, uType);
-    FIXME("dwCommonButtons=%x uType=%x ret=%x\n", pTaskConfig->dwCommonButtons, uType, ret);
-
-    if (pnButton) *pnButton = ret;
-    if (pnRadioButton) *pnRadioButton = pTaskConfig->nDefaultButton;
-    if (pfVerificationFlagChecked) *pfVerificationFlagChecked = TRUE;
-    return S_OK;
+    {
+        if (pnButton) *pnButton = 0;
+        return E_FAIL;
+    }
 }
-- 
1.8.4.5




More information about the wine-patches mailing list