2 * The dialog that displays after a crash
4 * Copyright 2008 Mikolaj Zalewski
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(winedbg
);
36 #define MAX_PROGRAM_NAME_LENGTH 80
38 static char *crash_log
;
40 int msgbox_res_id(HWND hwnd
, UINT textId
, UINT captionId
, UINT uType
)
44 LoadStringW(GetModuleHandleW(NULL
), captionId
, caption
, sizeof(caption
)/sizeof(caption
[0]));
45 LoadStringW(GetModuleHandleW(NULL
), textId
, text
, sizeof(text
)/sizeof(text
[0]));
46 return MessageBoxW(hwnd
, text
, caption
, uType
);
49 static WCHAR
*get_program_name(HANDLE hProcess
)
51 WCHAR image_name
[MAX_PATH
];
55 /* GetProcessImageFileNameW gives no way to query the correct buffer size,
56 * but programs with a path longer than MAX_PATH can't be started by the
57 * shell, so we expect they don't happen often */
58 if (!GetProcessImageFileNameW(hProcess
, image_name
, MAX_PATH
))
60 static WCHAR unidentified
[MAX_PROGRAM_NAME_LENGTH
];
61 LoadStringW(GetModuleHandleW(NULL
), IDS_UNIDENTIFIED
,
62 unidentified
, MAX_PROGRAM_NAME_LENGTH
);
66 programname
= strrchrW(image_name
, '\\');
67 if (programname
!= NULL
)
70 programname
= image_name
;
72 /* TODO: if the image has a VERSIONINFO, we could try to find there a more
73 * user-friendly program name */
75 /* don't display a too long string to the user */
76 if (strlenW(programname
) >= MAX_PROGRAM_NAME_LENGTH
)
78 programname
[MAX_PROGRAM_NAME_LENGTH
- 4] = '.';
79 programname
[MAX_PROGRAM_NAME_LENGTH
- 3] = '.';
80 programname
[MAX_PROGRAM_NAME_LENGTH
- 2] = '.';
81 programname
[MAX_PROGRAM_NAME_LENGTH
- 1] = 0;
84 output
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*(lstrlenW(programname
) + 1));
85 lstrcpyW(output
, programname
);
90 static LPWSTR g_ProgramName
;
91 static HFONT g_hBoldFont
;
92 static HMENU g_hDebugMenu
= NULL
;
94 static void set_bold_font(HWND hDlg
)
96 HFONT hNormalFont
= (HFONT
)SendDlgItemMessageW(hDlg
, IDC_STATIC_TXT1
,
99 GetObjectW(hNormalFont
, sizeof(LOGFONTW
), &font
);
100 font
.lfWeight
= FW_BOLD
;
101 g_hBoldFont
= CreateFontIndirectW(&font
);
102 SendDlgItemMessageW(hDlg
, IDC_STATIC_TXT1
, WM_SETFONT
, (WPARAM
)g_hBoldFont
, TRUE
);
105 static void set_fixed_font( HWND dlg
, UINT id
)
107 HFONT hfont
= (HFONT
)SendDlgItemMessageW( dlg
, id
, WM_GETFONT
, 0, 0);
110 GetObjectW(hfont
, sizeof(LOGFONTW
), &font
);
111 font
.lfPitchAndFamily
= FIXED_PITCH
;
112 font
.lfFaceName
[0] = 0;
113 hfont
= CreateFontIndirectW(&font
);
114 SendDlgItemMessageW( dlg
, id
, WM_SETFONT
, (WPARAM
)hfont
, TRUE
);
117 static void set_message_with_filename(HWND hDlg
)
119 WCHAR originalText
[1000];
120 WCHAR newText
[1000 + MAX_PROGRAM_NAME_LENGTH
];
122 GetDlgItemTextW(hDlg
, IDC_STATIC_TXT1
, originalText
,
123 sizeof(originalText
)/sizeof(originalText
[0]));
124 wsprintfW(newText
, originalText
, g_ProgramName
);
125 SetDlgItemTextW(hDlg
, IDC_STATIC_TXT1
, newText
);
128 static void load_crash_log( HANDLE file
)
130 DWORD len
, pos
= 0, size
= 65536;
132 crash_log
= HeapAlloc( GetProcessHeap(), 0, size
);
133 SetFilePointer( file
, 0, NULL
, FILE_BEGIN
);
134 while (ReadFile( file
, crash_log
+ pos
, size
- pos
- 1, &len
, NULL
) && len
)
138 if (pos
== size
- 1) crash_log
= HeapReAlloc( GetProcessHeap(), 0, crash_log
, size
*= 2 );
143 static void save_crash_log( HWND hwnd
)
148 WCHAR
*p
, path
[MAX_PATH
], buffer
[1024];
149 static const WCHAR default_name
[] = { 'b','a','c','k','t','r','a','c','e','.','t','x','t',0 };
150 static const WCHAR default_ext
[] = { 't','x','t',0 };
151 static const WCHAR txt_files
[] = { '*','.','t','x','t',0 };
152 static const WCHAR all_files
[] = { '*','.','*',0 };
154 memset( &save
, 0, sizeof(save
) );
155 lstrcpyW( path
, default_name
);
157 LoadStringW( GetModuleHandleW(0), IDS_TEXT_FILES
, buffer
, sizeof(buffer
) );
158 p
= buffer
+ lstrlenW(buffer
) + 1;
159 lstrcpyW(p
, txt_files
);
160 p
+= lstrlenW(p
) + 1;
161 LoadStringW( GetModuleHandleW(0), IDS_ALL_FILES
, p
, sizeof(buffer
) - (p
- buffer
) );
162 p
+= lstrlenW(p
) + 1;
163 lstrcpyW(p
, all_files
);
164 p
+= lstrlenW(p
) + 1;
167 save
.lStructSize
= sizeof(OPENFILENAMEW
);
168 save
.hwndOwner
= hwnd
;
169 save
.hInstance
= GetModuleHandleW(0);
170 save
.lpstrFilter
= buffer
;
171 save
.lpstrFile
= path
;
172 save
.nMaxFile
= MAX_PATH
;
173 save
.Flags
= OFN_EXPLORER
| OFN_PATHMUSTEXIST
| OFN_OVERWRITEPROMPT
|
174 OFN_HIDEREADONLY
| OFN_ENABLESIZING
;
175 save
.lpstrDefExt
= default_ext
;
177 if (!GetSaveFileNameW( &save
)) return;
178 handle
= CreateFileW( save
.lpstrFile
, GENERIC_WRITE
, FILE_SHARE_READ
,
179 NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0 );
180 if (handle
!= INVALID_HANDLE_VALUE
)
182 if (!WriteFile( handle
, crash_log
, strlen(crash_log
), &written
, NULL
))
183 err
= GetLastError();
184 else if (written
!= strlen(crash_log
))
185 err
= GetLastError();
188 CloseHandle( handle
);
191 CloseHandle( handle
);
192 DeleteFileW( save
.lpstrFile
);
194 else err
= GetLastError();
196 LoadStringW( GetModuleHandleW(0), IDS_SAVE_ERROR
, buffer
, sizeof(buffer
)/sizeof(WCHAR
) );
197 FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
198 NULL
, err
, 0, (LPWSTR
)&p
, 0, NULL
);
199 MessageBoxW( 0, p
, buffer
, MB_OK
| MB_ICONERROR
);
203 static INT_PTR WINAPI
crash_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
205 static const WCHAR openW
[] = {'o','p','e','n',0};
211 set_message_with_filename(hwnd
);
214 case WM_CTLCOLORSTATIC
:
216 /* WM_CTLCOLOR* don't use DWLP_MSGRESULT */
217 INT_PTR id
= GetDlgCtrlID((HWND
)lParam
);
218 if (id
== IDC_STATIC_BG
|| id
== IDC_STATIC_TXT1
)
219 return (LONG_PTR
)GetSysColorBrush(COLOR_WINDOW
);
226 if (!(wParam
& MK_SHIFT
))
228 if (g_hDebugMenu
== NULL
)
229 g_hDebugMenu
= LoadMenuW(GetModuleHandleW(NULL
), MAKEINTRESOURCEW(IDM_DEBUG_POPUP
));
230 GetCursorPos(&mousePos
);
231 TrackPopupMenu(GetSubMenu(g_hDebugMenu
, 0), TPM_RIGHTBUTTON
, mousePos
.x
, mousePos
.y
,
236 switch (((NMHDR
*)lParam
)->code
)
240 if (wParam
== IDC_STATIC_TXT2
)
241 ShellExecuteW( NULL
, openW
, ((NMLINK
*)lParam
)->item
.szUrl
, NULL
, NULL
, SW_SHOW
);
247 switch (LOWORD(wParam
))
253 EndDialog(hwnd
, LOWORD(wParam
));
261 static INT_PTR WINAPI
details_dlg_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
263 static const WCHAR openW
[] = {'o','p','e','n',0};
268 set_fixed_font( hwnd
, IDC_CRASH_TXT
);
269 SetDlgItemTextA( hwnd
, IDC_CRASH_TXT
, crash_log
);
273 switch (((NMHDR
*)lparam
)->code
)
277 if (wparam
== IDC_STATIC_TXT2
)
278 ShellExecuteW( NULL
, openW
, ((NMLINK
*)lparam
)->item
.szUrl
, NULL
, NULL
, SW_SHOW
);
284 switch (LOWORD(wparam
))
287 save_crash_log( hwnd
);
291 EndDialog(hwnd
, LOWORD(wparam
));
299 int display_crash_dialog(void)
301 static const WCHAR winedeviceW
[] = {'w','i','n','e','d','e','v','i','c','e','.','e','x','e',0};
302 static const INITCOMMONCONTROLSEX init
= { sizeof(init
), ICC_LINK_CLASS
};
304 /* dbg_curr_process->handle is not set */
307 if (!DBG_IVAR(ShowCrashDialog
))
310 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, dbg_curr_pid
);
311 g_ProgramName
= get_program_name(hProcess
);
312 CloseHandle(hProcess
);
313 if (!strcmpW( g_ProgramName
, winedeviceW
)) return TRUE
;
314 InitCommonControlsEx( &init
);
315 return DialogBoxW(GetModuleHandleW(NULL
), MAKEINTRESOURCEW(IDD_CRASH_DLG
), NULL
, crash_dlg_proc
);
318 int display_crash_details( HANDLE logfile
)
320 load_crash_log( logfile
);
321 return DialogBoxW( GetModuleHandleW(0), MAKEINTRESOURCEW(IDD_DETAILS_DLG
), 0, details_dlg_proc
);