|  | /* | 
|  | * GUI support | 
|  | * | 
|  | * Copyright 2004 Ferenc Wagner | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include <windows.h> | 
|  | #include <commctrl.h> | 
|  |  | 
|  | #include "resource.h" | 
|  | #include "winetest.h" | 
|  |  | 
|  | /* Event object to signal successful window creation to main thread. | 
|  | */ | 
|  | HANDLE initEvent; | 
|  |  | 
|  | /* Dialog handle | 
|  | */ | 
|  | HWND dialog; | 
|  |  | 
|  | /* Progress data for the text* functions and for scaling. | 
|  | */ | 
|  | unsigned int progressMax, progressCurr; | 
|  | double progressScale; | 
|  |  | 
|  | /* Progress group counter for the gui* functions. | 
|  | */ | 
|  | int progressGroup; | 
|  |  | 
|  | char * | 
|  | renderString (va_list ap) | 
|  | { | 
|  | const char *fmt = va_arg (ap, char*); | 
|  | static char buffer[128]; | 
|  |  | 
|  | vsnprintf (buffer, sizeof buffer, fmt, ap); | 
|  | return buffer; | 
|  | } | 
|  |  | 
|  | int | 
|  | MBdefault (int uType) | 
|  | { | 
|  | static const int matrix[][4] = {{IDOK,    0,        0,        0}, | 
|  | {IDOK,    IDCANCEL, 0,        0}, | 
|  | {IDABORT, IDRETRY,  IDIGNORE, 0}, | 
|  | {IDYES,   IDNO,     IDCANCEL, 0}, | 
|  | {IDYES,   IDNO,     0,        0}, | 
|  | {IDRETRY, IDCANCEL, 0,        0}}; | 
|  | int type = uType & MB_TYPEMASK; | 
|  | int def  = (uType & MB_DEFMASK) / MB_DEFBUTTON2; | 
|  |  | 
|  | return matrix[type][def]; | 
|  | } | 
|  |  | 
|  | /* report (R_STATUS, fmt, ...) */ | 
|  | int | 
|  | textStatus (va_list ap) | 
|  | { | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | fputs (str, stderr); | 
|  | fputc ('\n', stderr); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiStatus (va_list ap) | 
|  | { | 
|  | size_t len; | 
|  | char *str = vstrmake (&len, ap); | 
|  |  | 
|  | if (len > 128) str[129] = 0; | 
|  | SetDlgItemText (dialog, IDC_SB, str); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* report (R_PROGRESS, barnum, steps) */ | 
|  | int | 
|  | textProgress (va_list ap) | 
|  | { | 
|  | progressGroup = va_arg (ap, int); | 
|  | progressMax = va_arg (ap, int); | 
|  | progressCurr = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiProgress (va_list ap) | 
|  | { | 
|  | unsigned int max; | 
|  | HWND pb; | 
|  |  | 
|  | progressGroup = va_arg (ap, int); | 
|  | progressMax = max = va_arg (ap, int); | 
|  | progressCurr = 0; | 
|  | if (max > 0xffff) { | 
|  | progressScale = (double)0xffff / max; | 
|  | max = 0xffff; | 
|  | } | 
|  | else progressScale = 1; | 
|  | pb = GetDlgItem (dialog, IDC_PB0 + progressGroup * 2); | 
|  | SendMessage (pb, PBM_SETRANGE, 0, MAKELPARAM (0, max)); | 
|  | SendMessage (pb, PBM_SETSTEP, (WPARAM)1, 0); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* report (R_STEP, fmt, ...) */ | 
|  | int | 
|  | textStep (va_list ap) | 
|  | { | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | progressCurr++; | 
|  | fputs (str, stderr); | 
|  | fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiStep (va_list ap) | 
|  | { | 
|  | const int pgID = IDC_ST0 + progressGroup * 2; | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | progressCurr++; | 
|  | SetDlgItemText (dialog, pgID, str); | 
|  | SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS, | 
|  | (WPARAM)(progressScale * progressCurr), 0); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* report (R_DELTA, inc, fmt, ...) */ | 
|  | int | 
|  | textDelta (va_list ap) | 
|  | { | 
|  | const int inc = va_arg (ap, int); | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | progressCurr += inc; | 
|  | fputs (str, stderr); | 
|  | fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiDelta (va_list ap) | 
|  | { | 
|  | const int inc = va_arg (ap, int); | 
|  | const int pgID = IDC_ST0 + progressGroup * 2; | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | progressCurr += inc; | 
|  | SetDlgItemText (dialog, pgID, str); | 
|  | SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS, | 
|  | (WPARAM)(progressScale * progressCurr), 0); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* report (R_DIR, fmt, ...) */ | 
|  | int | 
|  | textDir (va_list ap) | 
|  | { | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | fputs ("Temporary directory: ", stderr); | 
|  | fputs (str, stderr); | 
|  | fputc ('\n', stderr); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiDir (va_list ap) | 
|  | { | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | SetDlgItemText (dialog, IDC_DIR, str); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* report (R_OUT, fmt, ...) */ | 
|  | int | 
|  | textOut (va_list ap) | 
|  | { | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | fputs ("Log file: ", stderr); | 
|  | fputs (str, stderr); | 
|  | fputc ('\n', stderr); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiOut (va_list ap) | 
|  | { | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | SetDlgItemText (dialog, IDC_OUT, str); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* report (R_WARNING, fmt, ...) */ | 
|  | int | 
|  | textWarning (va_list ap) | 
|  | { | 
|  | fputs ("Warning: ", stderr); | 
|  | textStatus (ap); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiWarning (va_list ap) | 
|  | { | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | MessageBox (dialog, str, "Warning", MB_ICONWARNING | MB_OK); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* report (R_ERROR, fmt, ...) */ | 
|  | int | 
|  | textError (va_list ap) | 
|  | { | 
|  | fputs ("Error: ", stderr); | 
|  | textStatus (ap); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiError (va_list ap) | 
|  | { | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | MessageBox (dialog, str, "Error", MB_ICONERROR | MB_OK); | 
|  | free (str); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* report (R_FATAL, fmt, ...) */ | 
|  | int | 
|  | textFatal (va_list ap) | 
|  | { | 
|  | textError (ap); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | int | 
|  | guiFatal (va_list ap) | 
|  | { | 
|  | guiError (ap); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | /* report (R_ASK, type, fmt, ...) */ | 
|  | int | 
|  | textAsk (va_list ap) | 
|  | { | 
|  | int uType = va_arg (ap, int); | 
|  | int ret = MBdefault (uType); | 
|  | char *str = vstrmake (NULL, ap); | 
|  |  | 
|  | fprintf (stderr, "Question of type %d: %s\n" | 
|  | "Returning default: %d\n", uType, str, ret); | 
|  | free (str); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int | 
|  | guiAsk (va_list ap) | 
|  | { | 
|  | int uType = va_arg (ap, int); | 
|  | char *str = vstrmake (NULL, ap); | 
|  | int ret = MessageBox (dialog, str, "Question", | 
|  | MB_ICONQUESTION | uType); | 
|  |  | 
|  | free (str); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Quiet functions */ | 
|  | int | 
|  | qNoOp (va_list ap) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | qFatal (va_list ap) | 
|  | { | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | int | 
|  | qAsk (va_list ap) | 
|  | { | 
|  | return MBdefault (va_arg (ap, int)); | 
|  | } | 
|  |  | 
|  | BOOL CALLBACK | 
|  | AboutProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | switch (msg) { | 
|  | case WM_COMMAND: | 
|  | switch (LOWORD (wParam)) { | 
|  | case IDCANCEL: | 
|  | EndDialog (hwnd, IDCANCEL); | 
|  | return TRUE; | 
|  | } | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | BOOL CALLBACK | 
|  | DlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | switch (msg) { | 
|  | case WM_INITDIALOG: | 
|  | SendMessage (hwnd, WM_SETICON, ICON_SMALL, | 
|  | (LPARAM)LoadIcon (GetModuleHandle (NULL), | 
|  | MAKEINTRESOURCE (IDI_WINE))); | 
|  | SendMessage (hwnd, WM_SETICON, ICON_BIG, | 
|  | (LPARAM)LoadIcon (GetModuleHandle (NULL), | 
|  | MAKEINTRESOURCE (IDI_WINE))); | 
|  | dialog = hwnd; | 
|  | if (!SetEvent (initEvent)) { | 
|  | report (R_STATUS, "Can't signal main thread: %d", | 
|  | GetLastError ()); | 
|  | EndDialog (hwnd, 2); | 
|  | } | 
|  | return TRUE; | 
|  | case WM_CLOSE: | 
|  | EndDialog (hwnd, 3); | 
|  | return TRUE; | 
|  | case WM_COMMAND: | 
|  | switch (LOWORD (wParam)) { | 
|  | case IDHELP: | 
|  | DialogBox (GetModuleHandle (NULL), | 
|  | MAKEINTRESOURCE (IDD_ABOUT), hwnd, AboutProc); | 
|  | return TRUE; | 
|  | case IDABORT: | 
|  | report (R_WARNING, "Not implemented"); | 
|  | return TRUE; | 
|  | } | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | DWORD WINAPI | 
|  | DlgThreadProc () | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | InitCommonControls (); | 
|  | ret = DialogBox (GetModuleHandle (NULL), | 
|  | MAKEINTRESOURCE (IDD_STATUS), | 
|  | NULL, DlgProc); | 
|  | switch (ret) { | 
|  | case 0: | 
|  | report (R_WARNING, "Invalid parent handle"); | 
|  | break; | 
|  | case 1: | 
|  | report (R_WARNING, "DialogBox failed: %d", | 
|  | GetLastError ()); | 
|  | break; | 
|  | case 3: | 
|  | exit (0); | 
|  | default: | 
|  | report (R_STATUS, "Dialog exited: %d", ret); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int | 
|  | report (enum report_type t, ...) | 
|  | { | 
|  | typedef int r_fun_t (va_list); | 
|  |  | 
|  | va_list ap; | 
|  | int ret = 0; | 
|  | static r_fun_t * const text_funcs[] = | 
|  | {textStatus, textProgress, textStep, textDelta, | 
|  | textDir, textOut, | 
|  | textWarning, textError, textFatal, textAsk}; | 
|  | static r_fun_t * const GUI_funcs[] = | 
|  | {guiStatus, guiProgress, guiStep, guiDelta, | 
|  | guiDir, guiOut, | 
|  | guiWarning, guiError, guiFatal, guiAsk}; | 
|  | static r_fun_t * const quiet_funcs[] = | 
|  | {qNoOp, qNoOp, qNoOp, qNoOp, | 
|  | qNoOp, qNoOp, | 
|  | qNoOp, qNoOp, qFatal, qAsk}; | 
|  | static r_fun_t * const * funcs = NULL; | 
|  |  | 
|  | switch (t) { | 
|  | case R_TEXTMODE: | 
|  | funcs = text_funcs; | 
|  | return 0; | 
|  | case R_QUIET: | 
|  | funcs = quiet_funcs; | 
|  | return 0; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!funcs) { | 
|  | HANDLE DlgThread; | 
|  | DWORD DlgThreadID; | 
|  |  | 
|  | funcs = text_funcs; | 
|  | initEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | 
|  | if (!initEvent) | 
|  | report (R_STATUS, "Can't create event object: %d", | 
|  | GetLastError ()); | 
|  | else { | 
|  | DlgThread = CreateThread (NULL, 0, DlgThreadProc, | 
|  | NULL, 0, &DlgThreadID); | 
|  | if (!DlgThread) | 
|  | report (R_STATUS, "Can't create GUI thread: %d", | 
|  | GetLastError ()); | 
|  | else { | 
|  | DWORD ret = WaitForSingleObject (initEvent, INFINITE); | 
|  | switch (ret) { | 
|  | case WAIT_OBJECT_0: | 
|  | funcs = GUI_funcs; | 
|  | break; | 
|  | case WAIT_TIMEOUT: | 
|  | report (R_STATUS, "GUI creation timed out"); | 
|  | break; | 
|  | case WAIT_FAILED: | 
|  | report (R_STATUS, "Wait for GUI failed: %d", | 
|  | GetLastError ()); | 
|  | break; | 
|  | default: | 
|  | report (R_STATUS, "Wait returned %d", | 
|  | ret); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | va_start (ap, t); | 
|  | if (t < sizeof text_funcs / sizeof text_funcs[0] && | 
|  | t < sizeof GUI_funcs / sizeof GUI_funcs[0] && | 
|  | t >= 0) ret = funcs[t](ap); | 
|  | else report (R_WARNING, "unimplemented report type: %d", t); | 
|  | va_end (ap); | 
|  | return ret; | 
|  | } |