windows: Restore patches for Task Dialogs and TerminateProcess().
authorRyan C. Gordon <icculus@icculus.org>
Fri, 02 Mar 2018 14:10:25 -0500
changeset 119175ce3f8bf8381
parent 11916 e85247c4a60b
child 11918 c087b18ba812
windows: Restore patches for Task Dialogs and TerminateProcess().

2.0.8 has shipped, these can live in revision control now!
src/SDL_assert.c
src/video/windows/SDL_windowsmessagebox.c
src/video/windows/SDL_windowstaskdialog.h
     1.1 --- a/src/SDL_assert.c	Fri Mar 02 10:56:21 2018 -0800
     1.2 +++ b/src/SDL_assert.c	Fri Mar 02 14:10:25 2018 -0500
     1.3 @@ -123,7 +123,11 @@
     1.4  static SDL_NORETURN void SDL_ExitProcess(int exitcode)
     1.5  {
     1.6  #ifdef __WIN32__
     1.7 -    ExitProcess(exitcode);
     1.8 +    /* "if you do not know the state of all threads in your process, it is
     1.9 +       better to call TerminateProcess than ExitProcess"
    1.10 +       https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
    1.11 +    TerminateProcess(GetCurrentProcess(), exitcode);
    1.12 +
    1.13  #elif defined(__EMSCRIPTEN__)
    1.14      emscripten_cancel_main_loop();  /* this should "kill" the app. */
    1.15      emscripten_force_exit(exitcode);  /* this should "kill" the app. */
     2.1 --- a/src/video/windows/SDL_windowsmessagebox.c	Fri Mar 02 10:56:21 2018 -0800
     2.2 +++ b/src/video/windows/SDL_windowsmessagebox.c	Fri Mar 02 14:10:25 2018 -0500
     2.3 @@ -26,7 +26,7 @@
     2.4  
     2.5  #include "SDL_assert.h"
     2.6  #include "SDL_windowsvideo.h"
     2.7 -
     2.8 +#include "SDL_windowstaskdialog.h"
     2.9  
    2.10  #ifndef SS_EDITCONTROL
    2.11  #define SS_EDITCONTROL  0x2000
    2.12 @@ -341,8 +341,9 @@
    2.13      return dialog;
    2.14  }
    2.15  
    2.16 -int
    2.17 -WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
    2.18 +/* This function is called if a Task Dialog is unsupported. */
    2.19 +static int
    2.20 +WIN_ShowOldMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
    2.21  {
    2.22      WIN_DialogData *dialog;
    2.23      int i, x, y;
    2.24 @@ -491,6 +492,121 @@
    2.25      return 0;
    2.26  }
    2.27  
    2.28 +/* TaskDialogIndirect procedure
    2.29 + * This is because SDL targets Windows XP (0x501), so this is not defined in the platform SDK.
    2.30 + */
    2.31 +typedef HRESULT(FAR WINAPI *TASKDIALOGINDIRECTPROC)(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton, int *pnRadioButton, BOOL *pfVerificationFlagChecked);
    2.32 +
    2.33 +int
    2.34 +WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
    2.35 +{
    2.36 +    HWND ParentWindow = NULL;
    2.37 +    wchar_t *wmessage;
    2.38 +    wchar_t *wtitle;
    2.39 +    TASKDIALOGCONFIG TaskConfig;
    2.40 +    TASKDIALOG_BUTTON *pButtons;
    2.41 +    TASKDIALOG_BUTTON *pButton;
    2.42 +    HMODULE hComctl32;
    2.43 +    TASKDIALOGINDIRECTPROC pfnTaskDialogIndirect;
    2.44 +    HRESULT hr;
    2.45 +    int nButton;
    2.46 +    int nCancelButton;
    2.47 +    int i;
    2.48 +
    2.49 +    /* If we cannot load comctl32.dll use the old messagebox! */
    2.50 +    hComctl32 = LoadLibrary(TEXT("Comctl32.dll"));
    2.51 +    if (hComctl32 == NULL) {
    2.52 +        return WIN_ShowOldMessageBox(messageboxdata,buttonid);
    2.53 +    }
    2.54 +    
    2.55 +    /* If TaskDialogIndirect doesn't exist use the old messagebox!
    2.56 +       This will fail prior to Windows Vista.
    2.57 +       The manifest file in the application may require targeting version 6 of comctl32.dll, even
    2.58 +       when we use LoadLibrary here!
    2.59 +       If you don't want to bother with manifests, put this #pragma in your app's source code somewhere:
    2.60 +       pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0'  processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
    2.61 +     */
    2.62 +    pfnTaskDialogIndirect = (TASKDIALOGINDIRECTPROC) GetProcAddress(hComctl32, "TaskDialogIndirect");
    2.63 +    if (pfnTaskDialogIndirect == NULL) {
    2.64 +        FreeLibrary(hComctl32);
    2.65 +        return WIN_ShowOldMessageBox(messageboxdata, buttonid);
    2.66 +    }
    2.67 +
    2.68 +    /* If we have a parent window, get the Instance and HWND for them
    2.69 +       so that our little dialog gets exclusive focus at all times. */
    2.70 +    if (messageboxdata->window) {
    2.71 +        ParentWindow = ((SDL_WindowData *) messageboxdata->window->driverdata)->hwnd;
    2.72 +    }
    2.73 +
    2.74 +    wmessage = WIN_UTF8ToString(messageboxdata->message);
    2.75 +    wtitle = WIN_UTF8ToString(messageboxdata->title);
    2.76 +
    2.77 +    SDL_zero(TaskConfig);
    2.78 +    TaskConfig.cbSize = sizeof (TASKDIALOGCONFIG);
    2.79 +    TaskConfig.hwndParent = ParentWindow;
    2.80 +    TaskConfig.dwFlags = TDF_SIZE_TO_CONTENT;
    2.81 +    TaskConfig.pszWindowTitle = wtitle;
    2.82 +    if (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) {
    2.83 +        TaskConfig.pszMainIcon = TD_ERROR_ICON;
    2.84 +    } else if (messageboxdata->flags & SDL_MESSAGEBOX_WARNING) {
    2.85 +        TaskConfig.pszMainIcon = TD_WARNING_ICON;
    2.86 +    } else if (messageboxdata->flags & SDL_MESSAGEBOX_INFORMATION) {
    2.87 +        TaskConfig.pszMainIcon = TD_INFORMATION_ICON;
    2.88 +    } else {
    2.89 +        TaskConfig.pszMainIcon = NULL;
    2.90 +    }
    2.91 +
    2.92 +    TaskConfig.pszContent = wmessage;
    2.93 +    TaskConfig.cButtons = messageboxdata->numbuttons;
    2.94 +    pButtons = SDL_malloc(sizeof (TASKDIALOG_BUTTON) * messageboxdata->numbuttons);
    2.95 +    TaskConfig.nDefaultButton = 0;
    2.96 +    for (i = 0; i < messageboxdata->numbuttons; i++)
    2.97 +    {
    2.98 +        pButton = &pButtons[messageboxdata->numbuttons-1-i];
    2.99 +        if (messageboxdata->buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
   2.100 +            nCancelButton = messageboxdata->buttons[i].buttonid;
   2.101 +            pButton->nButtonID = 2;
   2.102 +        } else {
   2.103 +            pButton->nButtonID = messageboxdata->buttons[i].buttonid + 1;
   2.104 +            if (pButton->nButtonID >= 2) {
   2.105 +                pButton->nButtonID++;
   2.106 +            }
   2.107 +        }
   2.108 +        pButton->pszButtonText = WIN_UTF8ToString(messageboxdata->buttons[i].text);
   2.109 +        if (messageboxdata->buttons[i].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
   2.110 +            TaskConfig.nDefaultButton = pButton->nButtonID;
   2.111 +        }
   2.112 +    }
   2.113 +    TaskConfig.pButtons = pButtons;
   2.114 +
   2.115 +    /* Show the Task Dialog */
   2.116 +    hr = pfnTaskDialogIndirect(&TaskConfig, &nButton, NULL, NULL);
   2.117 +
   2.118 +    /* Free everything */
   2.119 +    FreeLibrary(hComctl32);
   2.120 +    SDL_free(wmessage);
   2.121 +    SDL_free(wtitle);
   2.122 +    for (i = 0; i < messageboxdata->numbuttons; i++) {
   2.123 +        SDL_free((wchar_t *) pButtons[i].pszButtonText);
   2.124 +    }
   2.125 +    SDL_free(pButtons);
   2.126 +
   2.127 +    /* Check the Task Dialog was successful and give the result */
   2.128 +    if (SUCCEEDED(hr)) {
   2.129 +        if (nButton == 2) {
   2.130 +            *buttonid = nCancelButton;
   2.131 +        } else if (nButton > 2) {
   2.132 +            *buttonid = nButton-1-1;
   2.133 +        } else {
   2.134 +            *buttonid = nButton-1;
   2.135 +        }
   2.136 +        return 0;
   2.137 +    }
   2.138 +
   2.139 +    /* We failed showing the Task Dialog, use the old message box! */
   2.140 +    return WIN_ShowOldMessageBox(messageboxdata, buttonid);
   2.141 +}
   2.142 +
   2.143  #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   2.144  
   2.145  /* vi: set ts=4 sw=4 expandtab: */
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/video/windows/SDL_windowstaskdialog.h	Fri Mar 02 14:10:25 2018 -0500
     3.3 @@ -0,0 +1,156 @@
     3.4 +/*
     3.5 +  Simple DirectMedia Layer
     3.6 +  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     3.7 +
     3.8 +  This software is provided 'as-is', without any express or implied
     3.9 +  warranty.  In no event will the authors be held liable for any damages
    3.10 +  arising from the use of this software.
    3.11 +
    3.12 +  Permission is granted to anyone to use this software for any purpose,
    3.13 +  including commercial applications, and to alter it and redistribute it
    3.14 +  freely, subject to the following restrictions:
    3.15 +
    3.16 +  1. The origin of this software must not be misrepresented; you must not
    3.17 +     claim that you wrote the original software. If you use this software
    3.18 +     in a product, an acknowledgment in the product documentation would be
    3.19 +     appreciated but is not required.
    3.20 +  2. Altered source versions must be plainly marked as such, and must not be
    3.21 +     misrepresented as being the original software.
    3.22 +  3. This notice may not be removed or altered from any source distribution.
    3.23 +*/
    3.24 +#include <pshpack1.h>
    3.25 +
    3.26 +typedef HRESULT(CALLBACK *PFTASKDIALOGCALLBACK)(_In_ HWND hwnd, _In_ UINT msg, _In_ WPARAM wParam, _In_ LPARAM lParam, _In_ LONG_PTR lpRefData);
    3.27 +
    3.28 +enum _TASKDIALOG_FLAGS
    3.29 +{
    3.30 +    TDF_ENABLE_HYPERLINKS = 0x0001,
    3.31 +    TDF_USE_HICON_MAIN = 0x0002,
    3.32 +    TDF_USE_HICON_FOOTER = 0x0004,
    3.33 +    TDF_ALLOW_DIALOG_CANCELLATION = 0x0008,
    3.34 +    TDF_USE_COMMAND_LINKS = 0x0010,
    3.35 +    TDF_USE_COMMAND_LINKS_NO_ICON = 0x0020,
    3.36 +    TDF_EXPAND_FOOTER_AREA = 0x0040,
    3.37 +    TDF_EXPANDED_BY_DEFAULT = 0x0080,
    3.38 +    TDF_VERIFICATION_FLAG_CHECKED = 0x0100,
    3.39 +    TDF_SHOW_PROGRESS_BAR = 0x0200,
    3.40 +    TDF_SHOW_MARQUEE_PROGRESS_BAR = 0x0400,
    3.41 +    TDF_CALLBACK_TIMER = 0x0800,
    3.42 +    TDF_POSITION_RELATIVE_TO_WINDOW = 0x1000,
    3.43 +    TDF_RTL_LAYOUT = 0x2000,
    3.44 +    TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000,
    3.45 +    TDF_CAN_BE_MINIMIZED = 0x8000,
    3.46 +    //#if (NTDDI_VERSION >= NTDDI_WIN8)
    3.47 +    TDF_NO_SET_FOREGROUND = 0x00010000, // Don't call SetForegroundWindow() when activating the dialog
    3.48 +                                        //#endif // (NTDDI_VERSION >= NTDDI_WIN8)
    3.49 +                                        TDF_SIZE_TO_CONTENT = 0x01000000  // used by ShellMessageBox to emulate MessageBox sizing behavior
    3.50 +};
    3.51 +typedef int TASKDIALOG_FLAGS;                         // Note: _TASKDIALOG_FLAGS is an int
    3.52 +
    3.53 +typedef enum _TASKDIALOG_MESSAGES
    3.54 +{
    3.55 +    TDM_NAVIGATE_PAGE = WM_USER + 101,
    3.56 +    TDM_CLICK_BUTTON = WM_USER + 102, // wParam = Button ID
    3.57 +    TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER + 103, // wParam = 0 (nonMarque) wParam != 0 (Marquee)
    3.58 +    TDM_SET_PROGRESS_BAR_STATE = WM_USER + 104, // wParam = new progress state
    3.59 +    TDM_SET_PROGRESS_BAR_RANGE = WM_USER + 105, // lParam = MAKELPARAM(nMinRange, nMaxRange)
    3.60 +    TDM_SET_PROGRESS_BAR_POS = WM_USER + 106, // wParam = new position
    3.61 +    TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER + 107, // wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints)
    3.62 +    TDM_SET_ELEMENT_TEXT = WM_USER + 108, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
    3.63 +    TDM_CLICK_RADIO_BUTTON = WM_USER + 110, // wParam = Radio Button ID
    3.64 +    TDM_ENABLE_BUTTON = WM_USER + 111, // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID
    3.65 +    TDM_ENABLE_RADIO_BUTTON = WM_USER + 112, // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID
    3.66 +    TDM_CLICK_VERIFICATION = WM_USER + 113, // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus)
    3.67 +    TDM_UPDATE_ELEMENT_TEXT = WM_USER + 114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
    3.68 +    TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER + 115, // wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required)
    3.69 +    TDM_UPDATE_ICON = WM_USER + 116  // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise)
    3.70 +} TASKDIALOG_MESSAGES;
    3.71 +
    3.72 +typedef enum _TASKDIALOG_NOTIFICATIONS
    3.73 +{
    3.74 +    TDN_CREATED = 0,
    3.75 +    TDN_NAVIGATED = 1,
    3.76 +    TDN_BUTTON_CLICKED = 2,            // wParam = Button ID
    3.77 +    TDN_HYPERLINK_CLICKED = 3,            // lParam = (LPCWSTR)pszHREF
    3.78 +    TDN_TIMER = 4,            // wParam = Milliseconds since dialog created or timer reset
    3.79 +    TDN_DESTROYED = 5,
    3.80 +    TDN_RADIO_BUTTON_CLICKED = 6,            // wParam = Radio Button ID
    3.81 +    TDN_DIALOG_CONSTRUCTED = 7,
    3.82 +    TDN_VERIFICATION_CLICKED = 8,             // wParam = 1 if checkbox checked, 0 if not, lParam is unused and always 0
    3.83 +    TDN_HELP = 9,
    3.84 +    TDN_EXPANDO_BUTTON_CLICKED = 10            // wParam = 0 (dialog is now collapsed), wParam != 0 (dialog is now expanded)
    3.85 +} TASKDIALOG_NOTIFICATIONS;
    3.86 +
    3.87 +typedef struct _TASKDIALOG_BUTTON
    3.88 +{
    3.89 +    int     nButtonID;
    3.90 +    PCWSTR  pszButtonText;
    3.91 +} TASKDIALOG_BUTTON;
    3.92 +
    3.93 +typedef enum _TASKDIALOG_ELEMENTS
    3.94 +{
    3.95 +    TDE_CONTENT,
    3.96 +    TDE_EXPANDED_INFORMATION,
    3.97 +    TDE_FOOTER,
    3.98 +    TDE_MAIN_INSTRUCTION
    3.99 +} TASKDIALOG_ELEMENTS;
   3.100 +
   3.101 +typedef enum _TASKDIALOG_ICON_ELEMENTS
   3.102 +{
   3.103 +    TDIE_ICON_MAIN,
   3.104 +    TDIE_ICON_FOOTER
   3.105 +} TASKDIALOG_ICON_ELEMENTS;
   3.106 +
   3.107 +#define TD_WARNING_ICON         MAKEINTRESOURCEW(-1)
   3.108 +#define TD_ERROR_ICON           MAKEINTRESOURCEW(-2)
   3.109 +#define TD_INFORMATION_ICON     MAKEINTRESOURCEW(-3)
   3.110 +#define TD_SHIELD_ICON          MAKEINTRESOURCEW(-4)
   3.111 +
   3.112 +enum _TASKDIALOG_COMMON_BUTTON_FLAGS
   3.113 +{
   3.114 +    TDCBF_OK_BUTTON = 0x0001, // selected control return value IDOK
   3.115 +    TDCBF_YES_BUTTON = 0x0002, // selected control return value IDYES
   3.116 +    TDCBF_NO_BUTTON = 0x0004, // selected control return value IDNO
   3.117 +    TDCBF_CANCEL_BUTTON = 0x0008, // selected control return value IDCANCEL
   3.118 +    TDCBF_RETRY_BUTTON = 0x0010, // selected control return value IDRETRY
   3.119 +    TDCBF_CLOSE_BUTTON = 0x0020  // selected control return value IDCLOSE
   3.120 +};
   3.121 +typedef int TASKDIALOG_COMMON_BUTTON_FLAGS;           // Note: _TASKDIALOG_COMMON_BUTTON_FLAGS is an int
   3.122 +
   3.123 +typedef struct _TASKDIALOGCONFIG
   3.124 +{
   3.125 +    UINT        cbSize;
   3.126 +    HWND        hwndParent;                             // incorrectly named, this is the owner window, not a parent.
   3.127 +    HINSTANCE   hInstance;                              // used for MAKEINTRESOURCE() strings
   3.128 +    TASKDIALOG_FLAGS                dwFlags;            // TASKDIALOG_FLAGS (TDF_XXX) flags
   3.129 +    TASKDIALOG_COMMON_BUTTON_FLAGS  dwCommonButtons;    // TASKDIALOG_COMMON_BUTTON (TDCBF_XXX) flags
   3.130 +    PCWSTR      pszWindowTitle;                         // string or MAKEINTRESOURCE()
   3.131 +    union
   3.132 +    {
   3.133 +        HICON   hMainIcon;
   3.134 +        PCWSTR  pszMainIcon;
   3.135 +    } DUMMYUNIONNAME;
   3.136 +    PCWSTR      pszMainInstruction;
   3.137 +    PCWSTR      pszContent;
   3.138 +    UINT        cButtons;
   3.139 +    const TASKDIALOG_BUTTON  *pButtons;
   3.140 +    int         nDefaultButton;
   3.141 +    UINT        cRadioButtons;
   3.142 +    const TASKDIALOG_BUTTON  *pRadioButtons;
   3.143 +    int         nDefaultRadioButton;
   3.144 +    PCWSTR      pszVerificationText;
   3.145 +    PCWSTR      pszExpandedInformation;
   3.146 +    PCWSTR      pszExpandedControlText;
   3.147 +    PCWSTR      pszCollapsedControlText;
   3.148 +    union
   3.149 +    {
   3.150 +        HICON   hFooterIcon;
   3.151 +        PCWSTR  pszFooterIcon;
   3.152 +    } DUMMYUNIONNAME2;
   3.153 +    PCWSTR      pszFooter;
   3.154 +    PFTASKDIALOGCALLBACK pfCallback;
   3.155 +    LONG_PTR    lpCallbackData;
   3.156 +    UINT        cxWidth;                                // width of the Task Dialog's client area in DLU's. If 0, Task Dialog will calculate the ideal width.
   3.157 +} TASKDIALOGCONFIG;
   3.158 +
   3.159 +#include <poppack.h>