source: trunk/Utilities/LogProcessExceptions/MainWizard.h @ 64

Last change on this file since 64 was 64, checked in by roman, 10 years ago
  • skip initial exception on re-attaching to process
  • email notification code (hardcoded)
  • cosmetic
  • Property svn:keywords set to Id
File size: 49.5 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2012
3// Created by Roman Ryltsov roman@alax.info
4//
5// $Id: MainWizard.h 64 2012-05-12 17:23:26Z roman $
6
7#pragma once
8
9#include <psapi.h>
10#include <tlhelp32.h>
11#include <atlsecurity.h>
12#include "AboutDialog.h"
13#include "..\..\..\Repository-Private\Utilities\EmailTools\Message.h"
14
15#if PSAPI_VERSION == 1
16#pragma comment(lib, "psapi.lib")
17#endif // PSAPI_VERSION == 1
18
19////////////////////////////////////////////////////////////
20// CMainWizard
21
22class CMainWizard : 
23        public CWizardPropertySheetT<CMainWizard>
24{
25public:
26
27BEGIN_MSG_MAP_EX(CMainWizard)
28        CHAIN_MSG_MAP(CWizardPropertySheet)
29        MSG_WM_SYSCOMMAND(OnSysCommand)
30END_MSG_MAP()
31
32        ////////////////////////////////////////////////////////
33        // CIntroductionPropertyPage
34
35        class CIntroductionPropertyPage :
36                public CWizardPropertyPageT<CIntroductionPropertyPage>
37        {
38        public:
39                enum { IDD = IDD_MAIN_INTRODUCTION };
40
41        BEGIN_MSG_MAP_EX(CIntroductionPropertyPage)
42                CHAIN_MSG_MAP(CWizardPropertyPageT<CIntroductionPropertyPage>)
43                MSG_WM_INITDIALOG(OnInitDialog)
44                REFLECT_NOTIFICATIONS()
45        END_MSG_MAP()
46
47        private:
48                CMainWizard& m_Wizard;
49                CRoHyperStatic m_DescriptionHyperStatic;
50                CButton m_SkipButton;
51                BOOL m_bActivated;
52
53        public:
54        // CIntroductionPropertyPage
55                CIntroductionPropertyPage(CMainWizard* pWizard) throw() :
56                        m_Wizard(*pWizard),
57                        m_bActivated(FALSE)
58                {
59                        m_psp.dwFlags |= PSP_HIDEHEADER;
60                }
61
62        // Window message handlers
63                LRESULT OnInitDialog(HWND, LPARAM) throw()
64                {
65                        //_W(GetPropertySheet().ModifyStyle(0, WS_MINIMIZEBOX));
66                        GetPropertySheet().SetIcon(AtlLoadIcon(IDI_MODULE), TRUE);
67                        GetPropertySheet().SetIcon(AtlLoadIconImage(IDI_MODULE, LR_DEFAULTCOLOR, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)), FALSE);
68                        CMenuHandle Menu = GetPropertySheet().GetSystemMenu(FALSE);
69                        _W(Menu.AppendMenu(MF_SEPARATOR));
70                        _W(Menu.AppendMenu(MF_STRING, ID_APP_ABOUT, _T("&About...")));
71                        CStatic(GetDlgItem(IDC_WIZARDINTRODUCTION_TITLE)).SetFont(m_Wizard.GetMessageTitleFont());
72                        _W(m_DescriptionHyperStatic.SubclassWindow(GetDlgItem(IDC_WIZARDINTRODUCTION_DESCRIPTION)));
73                        m_SkipButton = GetDlgItem(IDC_WIZARDINTRODUCTION_SKIP);
74                        return TRUE;
75                }
76                INT OnSetActive() throw()
77                {
78                        SetWizardButtons(PSWIZB_NEXT);
79                        BOOL bActivated = m_bActivated;
80                        m_bActivated = TRUE;
81                        if(!bActivated && m_Wizard.GetConfirmation(_T("CMainWizard::CIntroductionPropertyPage")) == 1)
82                        {
83                                m_SkipButton.SetCheck(BST_CHECKED);
84                                return -1;
85                        }
86                        return 0;
87                }
88                INT OnWizardNext() throw()
89                {
90                        m_Wizard.SetConfirmation(_T("CMainWizard::CIntroductionPropertyPage"), m_SkipButton.GetCheck());
91                        return 0;
92                }
93        };
94
95        ////////////////////////////////////////////////////////
96        // CProcessPropertyPage
97
98        class CProcessPropertyPage :
99                public CWizardPropertyPageT<CProcessPropertyPage>
100        {
101        public:
102                enum { IDD = IDD_MAIN_PROCESS };
103
104        BEGIN_MSG_MAP_EX(CProcessPropertyPage)
105                CHAIN_MSG_MAP(CWizardPropertyPageT<CProcessPropertyPage>)
106                MSG_WM_INITDIALOG(OnInitDialog)
107                MSG_LVN_GETDISPINFO(IDC_MAIN_PROCESSES, OnProcessListViewGetDispInfo)
108                MSG_LVN_GETINFOTIP(IDC_MAIN_PROCESSES, OnProcessListViewGetInfoTip)
109                MSG_LVN_ITEMCHANGED(IDC_MAIN_PROCESSES, OnProcessListItemChanged)
110                MSG_LVN_DBLCLK(IDC_MAIN_PROCESSES, OnProcessListViewDblClk)
111                COMMAND_ID_HANDLER_EX(IDC_MAIN_REFRESHPROCESSES, OnRefreshButtonClicked)
112                REFLECT_NOTIFICATIONS()
113        END_MSG_MAP()
114
115        public:
116
117                ////////////////////////////////////////////////////
118                // CProcessData
119
120                class CProcessData
121                {
122                public:
123                        DWORD m_nIdentifier;
124                        CHandle m_Handle;
125                        CPath m_sFilePath;
126                        CPath m_sImageFilePath;
127                        BOOL m_bIsWow64;
128                        CString m_sAccount;
129                        PROCESS_MEMORY_COUNTERS_EX m_MemoryCounters;
130                        CString m_sWindowCaption;
131                        BOOL m_bValid;
132                        BOOL UpdateMemoryCounters()
133                        {
134                                ZeroMemory(&m_MemoryCounters, sizeof m_MemoryCounters);
135                                m_MemoryCounters.cb = sizeof m_MemoryCounters;
136                                if(!GetProcessMemoryInfo(m_Handle, (PROCESS_MEMORY_COUNTERS*) &m_MemoryCounters, m_MemoryCounters.cb))
137                                {
138                                        m_MemoryCounters.cb = sizeof (PROCESS_MEMORY_COUNTERS);
139                                        if(!GetProcessMemoryInfo(m_Handle, (PROCESS_MEMORY_COUNTERS*) &m_MemoryCounters, m_MemoryCounters.cb))
140                                                return FALSE;
141                                }
142                                return TRUE;
143                        }
144
145                public:
146                // CProcessData
147                        static BOOL CompareIdentifier(const CProcessData& ProcessData, DWORD nIdentifier) throw()
148                        {
149                                return ProcessData.m_nIdentifier == nIdentifier;
150                        }
151                        static BOOL ComparePartialFileName(const CProcessData& ProcessData, LPCTSTR pszFileName) throw()
152                        {
153                                _A(pszFileName);
154                                CString sProcessFileName = ProcessData.GetFileName();
155                                sProcessFileName.MakeLower();
156                                CString sPartialFileName = pszFileName;
157                                sPartialFileName.MakeLower();
158                                return sProcessFileName.Find(sPartialFileName) >= 0;
159                        }
160                        static BOOL ResetValid(CProcessData& ProcessData)
161                        {
162                                ProcessData.m_bValid = FALSE;
163                                return TRUE;
164                        }
165                        VOID Initialize(DWORD nProcessIdentifier, CHandle& Process, const CPath& sFilePath)
166                        {
167                                m_nIdentifier = nProcessIdentifier;
168                                m_Handle = Process;
169                                _A(!Process);
170                                m_sFilePath = sFilePath;
171                                TCHAR pszPath[MAX_PATH] = { 0 };
172                                if(GetProcessImageFileName(m_Handle, pszPath, DIM(pszPath)))
173                                        m_sImageFilePath = pszPath;
174                                m_bIsWow64 = SafeIsWow64Process(m_Handle);
175                                #pragma region
176                                _ATLTRY
177                                {
178                                        CAccessToken ProcessToken;
179                                        __E(ProcessToken.GetProcessToken(TOKEN_QUERY, m_Handle));
180                                        CSid Sid;
181                                        __E(ProcessToken.GetUser(&Sid));
182                                        m_sAccount = Sid.AccountName();
183                                        LPCTSTR pszDomain = Sid.Domain();
184                                        if(pszDomain && _tcslen(pszDomain))
185                                                m_sAccount = AtlFormatString(_T("%s\\%s"), pszDomain, m_sAccount);
186                                }
187                                _ATLCATCHALL()
188                                {
189                                        _Z_EXCEPTION();
190                                }
191                                #pragma endregion
192                                UpdateMemoryCounters();
193                                m_bValid = TRUE;
194                        }
195                        VOID Update()
196                        {
197                                UpdateMemoryCounters();
198                                m_bValid = TRUE;
199                        }
200                        LPCTSTR GetFileName() const throw()
201                        {
202                                return (LPCTSTR) m_sFilePath + m_sFilePath.FindFileName();
203                        }
204                        const CPath& GetImageFilePath() const throw()
205                        {
206                                return m_sImageFilePath;
207                        }
208                        const PROCESS_MEMORY_COUNTERS_EX& GetMemoryCounters() const throw()
209                        {
210                                return m_MemoryCounters;
211                        }
212                };
213
214                ////////////////////////////////////////////////////
215                // CProcessDataList
216
217                class CProcessDataList :
218                        public CRoListT<CProcessData>
219                {
220                public:
221                        CRoMapT<DWORD, CWindow> m_ProcessWindowMap;
222
223                        BOOL ProcessWindow(CWindow Window) throw()
224                        {
225                                const DWORD nProcessIdentifier = Window.GetWindowProcessID();
226                                if(!m_ProcessWindowMap.Lookup(nProcessIdentifier))
227                                        _W(m_ProcessWindowMap.SetAt(nProcessIdentifier, Window));
228                                return TRUE;
229                        }
230                        static BOOL CALLBACK ProcessWindow(HWND hWindow, LPARAM lParam)
231                        {
232                                return ((CProcessDataList*) lParam)->ProcessWindow(hWindow);
233                        }
234
235                public:
236                // CProcessDataList
237                        VOID ResetValid()
238                        {
239                                ForEach(&CProcessData::ResetValid);
240                        }
241                        VOID UpdateWindows()
242                        {
243                                m_ProcessWindowMap.RemoveAll();
244                                EnumWindows(&CProcessDataList::ProcessWindow, (LPARAM) this);
245                                for(POSITION Position = GetHeadPosition(); Position; GetNext(Position))
246                                {
247                                        CProcessData& ProcessData = GetAt(Position);
248                                        ProcessData.m_sWindowCaption.Empty();
249                                        CWindow Window;
250                                        if(m_ProcessWindowMap.Lookup(ProcessData.m_nIdentifier, Window))
251                                                Window.GetWindowText(ProcessData.m_sWindowCaption);
252                                }
253                        }
254                };
255
256        private:
257                CMainWizard& m_Wizard;
258                BOOL m_bActivating;
259                CRoHyperStatic m_DbghelpVersionStatic;
260                CRoListViewT<POSITION> m_ProcessListView;
261                ULONGLONG m_nDbghelpVersion;
262                CProcessDataList m_ProcessDataList;
263                POSITION m_SelectedPosition;
264
265                VOID UpdateButtons() throw()
266                {
267                        const BOOL bAllowBack = !m_Wizard.m_OperationPropertyPage.IsActive();
268                        const BOOL bAllowNext = m_ProcessListView.GetSelectedCount() == 1;
269                        SetWizardButtons((bAllowBack ? PSWIZB_BACK : 0) | (bAllowNext ? PSWIZB_NEXT : 0));
270                }
271                VOID UpdateProcessListView()
272                {
273                        CWindowRedraw ProcessListViewRedraw(m_ProcessListView);
274                        m_ProcessDataList.ResetValid();
275#if TRUE
276                        static const SIZE_T g_nDefaultProcessCount = 1 << 10;
277                        static const SIZE_T g_nMaximalProcessCount = 128 << 10;
278                        CTempBufferT<DWORD, g_nDefaultProcessCount * sizeof (DWORD)> pnProcessIdentifers(g_nDefaultProcessCount);
279                        SIZE_T nProcessCount = g_nDefaultProcessCount;
280                        DWORD nAvailableProcessCount = 0;
281                        for(; ; )
282                        {
283                                __D(nProcessCount <= g_nMaximalProcessCount, E_UNNAMED);
284                                if(EnumProcesses(pnProcessIdentifers, (DWORD) (nProcessCount * sizeof (DWORD)), &nAvailableProcessCount))
285                                        break;
286                                _Z4(atlTraceGeneral, 4, _T("GetLastError() 0x%08x\n"), GetLastError());
287                                pnProcessIdentifers.Free();
288                                nProcessCount <<= 1;
289                        }
290                        nAvailableProcessCount /= sizeof (DWORD);
291                        for(SIZE_T nProcessIndex = 0; nProcessIndex < nAvailableProcessCount; nProcessIndex++)
292                                _ATLTRY
293                                {
294                                        const DWORD nProcessIdentifier = pnProcessIdentifers[nProcessIndex];
295                                        if(nProcessIdentifier == GetCurrentThreadId())
296                                                continue; // We Won't Debug Ourself
297                                        POSITION Position;
298                                        if(m_ProcessDataList.FindFirstThatT<DWORD>(&CProcessData::CompareIdentifier, nProcessIdentifier, &Position))
299                                        {
300                                                m_ProcessDataList.GetAt(Position).Update();
301                                                continue; // Already a Known One
302                                        }
303                                        CHandle Process(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, nProcessIdentifier));
304                                        if(!Process)
305                                        {
306                                                _Z3(atlTraceGeneral, 3, _T("Error 0x%08x (%s) opening process %d\n"), AtlHresultFromLastError(), AtlFormatSystemMessage(GetLastError()).TrimRight(_T("\t\n\r .")), nProcessIdentifier);
307                                                continue; // Access Denied?
308                                        }
309                                        Position = m_ProcessDataList.AddTail();
310                                        _ATLTRY
311                                        {
312                                                TCHAR pszFilePath[MAX_PATH] = { 0 };
313                                                _W(GetProcessImageFileName(Process, pszFilePath, DIM(pszFilePath)));
314                                                CProcessData& ProcessData = m_ProcessDataList.GetAt(Position);
315                                                ProcessData.Initialize(nProcessIdentifier, Process, pszFilePath);
316                                                _A(!Process);
317                                                const INT nItem = m_ProcessListView.InsertItem(m_ProcessListView.GetItemCount(), Position, ProcessData.GetFileName());
318                                                _A(nItem >= 0);
319                                        }
320                                        _ATLCATCHALL()
321                                        {
322                                                m_ProcessDataList.RemoveAt(Position);
323                                                _ATLRETHROW;
324                                        }
325                                }
326                                _ATLCATCHALL()
327                                {
328                                        _Z_EXCEPTION();
329                                }
330#else
331                        CHandle Snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
332                        __E(Snapshot);
333                        PROCESSENTRY32 ProcessEntry = { sizeof ProcessEntry };
334                        for(BOOL bHaveProcess = Process32First(Snapshot, &ProcessEntry); bHaveProcess; bHaveProcess = Process32Next(Snapshot, &ProcessEntry))
335                                _ATLTRY
336                                {
337                                        const DWORD nProcessIdentifier = ProcessEntry.th32ProcessID;
338                                        if(nProcessIdentifier == GetCurrentThreadId())
339                                                continue; // We Won't Debug Ourself
340                                        POSITION Position;
341                                        if(m_ProcessDataList.FindFirstThatT<DWORD>(&CProcessData::CompareIdentifier, nProcessIdentifier, &Position))
342                                        {
343                                                m_ProcessDataList.GetAt(Position).Update();
344                                                continue; // Already a Known One
345                                        }
346                                        const CPath sFilePath = ProcessEntry.szExeFile;
347                                        CHandle Process(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, nProcessIdentifier));
348                                        if(!Process)
349                                        {
350                                                _Z3(atlTraceGeneral, 3, _T("Error 0x%08x (%s) opening process %d, %s\n"), AtlHresultFromLastError(), AtlFormatSystemMessage(GetLastError()).TrimRight(_T("\t\n\r .")), nProcessIdentifier, sFilePath);
351                                                continue; // Access Denied?
352                                        }
353                                        Position = m_ProcessDataList.AddTail();
354                                        _ATLTRY
355                                        {
356                                                CProcessData& ProcessData = m_ProcessDataList.GetAt(Position);
357                                                ProcessData.Initialize(nProcessIdentifier, Process, sFilePath);
358                                                _A(!Process);
359                                                const INT nItem = m_ProcessListView.InsertItem(m_ProcessListView.GetItemCount(), Position, ProcessData.GetFileName());
360                                                _A(nItem >= 0);
361                                        }
362                                        _ATLCATCHALL()
363                                        {
364                                                m_ProcessDataList.RemoveAt(Position);
365                                                _ATLRETHROW;
366                                        }
367                                }
368                                _ATLCATCHALL()
369                                {
370                                        _Z_EXCEPTION();
371                                }
372                        __E(GetLastError() == ERROR_NO_MORE_FILES);
373#endif
374                        for(INT nItem = m_ProcessListView.GetItemCount() - 1; nItem >= 0; nItem--)
375                        {
376                                const POSITION Position = m_ProcessListView.GetItemData(nItem);
377                                CProcessData& ProcessData = m_ProcessDataList.GetAt(Position);
378                                if(ProcessData.m_bValid)
379                                        continue;
380                                m_ProcessListView.DeleteItem(nItem);
381                                m_ProcessDataList.RemoveAt(Position);
382                        }
383                        m_ProcessDataList.UpdateWindows();
384                }
385
386        public:
387        // CProcessPropertyPage
388                CProcessPropertyPage(CMainWizard* pWizard) throw() :
389                        m_Wizard(*pWizard)
390                {
391                        SetHeaderTitles();
392                }
393                ULONGLONG GetDbghelpVersion() const throw()
394                {
395                        return m_nDbghelpVersion;
396                }
397                CProcessData& GetSelectedProcessData() throw()
398                {
399                        _A(m_SelectedPosition);
400                        return m_ProcessDataList.GetAt(m_SelectedPosition);
401                }
402                BOOL IsSelectedProcessActive() const throw()
403                {
404                        if(!m_SelectedPosition)
405                                return FALSE;
406                        const CProcessData& ProcessData = m_ProcessDataList.GetAt(m_SelectedPosition);
407                        return WaitForSingleObject(ProcessData.m_Handle, 0) != WAIT_TIMEOUT;
408                }
409
410        // Window message handlers
411                LRESULT OnInitDialog(HWND, LPARAM)
412                {
413                        m_bActivating = TRUE;
414                        _ATLTRY
415                        {
416                                CWaitCursor WaitCursor;
417                                #pragma region Debug Help Library Availability and Version
418                                m_nDbghelpVersion = 0;
419                                CStatic DbghelpVersionStatic = GetDlgItem(IDC_MAIN_DBGHELPVERSION);
420                                _ATLTRY
421                                {
422                                        CString sDefaultDbghelpVersionStaticText, sText;
423                                        _W(DbghelpVersionStatic.GetWindowText(sDefaultDbghelpVersionStaticText));
424                                        const HMODULE hModule = LoadLibrary(_T("dbghelp.dll"));
425                                        if(hModule)
426                                        {
427                                                _ATLTRY
428                                                {
429                                                        TCHAR pszPath[MAX_PATH] = { 0 };
430                                                        _W(GetModuleFileName(hModule, pszPath, DIM(pszPath)));
431                                                        const ULONGLONG nVersion = _VersionInfoHelper::GetFileVersion(_VersionInfoHelper::GetModulePath(hModule));
432                                                        if(nVersion)
433                                                                sText = AtlFormatString(_StringHelper::GetLine(sDefaultDbghelpVersionStaticText, 0), _VersionInfoHelper::GetVersionString(nVersion));
434                                                        m_nDbghelpVersion = nVersion;
435                                                }
436                                                _ATLCATCHALL()
437                                                {
438                                                        _W(FreeLibrary(hModule));
439                                                        _ATLRETHROW;
440                                                }
441                                                _W(FreeLibrary(hModule));
442                                        }
443                                        if(sText.IsEmpty())
444                                                sText = AtlFormatString(_StringHelper::GetLine(sDefaultDbghelpVersionStaticText, 0), _StringHelper::GetLine(sDefaultDbghelpVersionStaticText, 1));
445                                        DbghelpVersionStatic.SetWindowText(sText);
446                                        _W(m_DbghelpVersionStatic.SubclassWindow(DbghelpVersionStatic));
447                                        const CSize IdealExtent = m_DbghelpVersionStatic.GetIdealExtent();
448                                        CRect Position;
449                                        _W(m_DbghelpVersionStatic.GetWindowRect(Position));
450                                        _W(ScreenToClient(Position));
451                                        Position.left = Position.right - IdealExtent.cx - 2;
452                                        _W(m_DbghelpVersionStatic.MoveWindow(Position));
453                                }
454                                _ATLCATCHALL()
455                                {
456                                        _Z_EXCEPTION();
457                                        DbghelpVersionStatic.ShowWindow(SW_HIDE);
458                                }
459                                #pragma endregion
460                                m_ProcessListView.Initialize(GetDlgItem(IDC_MAIN_PROCESSES));
461                                #if !defined(_WIN64)
462                                // NOTE: 32-bit Application which is not a WOW64 process is running on 32-bit OS
463                                if(!SafeIsWow64Process())
464                                        _W(m_ProcessListView.DeleteColumn(2));
465                                #endif // !defined(_WIN64)
466                                // NOTE: We need to enable Debug privilege prior to enumerating processes, so that we could see service processes
467                                EnableTokenDebugPrivilege();
468                                UpdateProcessListView();
469                                #pragma region Initial Selection Using Command Line
470                                CString sCommandLine = GetCommandLine();
471                                sCommandLine.TrimLeft();
472                                if(!sCommandLine.IsEmpty())
473                                {
474                                        #pragma region Delete Application Path
475                                        if(sCommandLine[0] == _T('\"'))
476                                        {
477                                                const INT nPosition = sCommandLine.Find(_T('\"'), 1);
478                                                if(nPosition >= 0)
479                                                        sCommandLine.Delete(0, nPosition + 1);
480                                                else
481                                                        sCommandLine.Empty();
482                                        } else
483                                        {
484                                                const INT nPosition = sCommandLine.Find(_T(' '), 0);
485                                                if(nPosition >= 0)
486                                                        sCommandLine.Delete(0, nPosition + 1);
487                                                else
488                                                        sCommandLine.Empty();
489                                        }
490                                        sCommandLine.TrimLeft();
491                                        #pragma endregion
492                                        CString sProcess = sCommandLine;
493                                        sProcess.Trim();
494                                        if(!sProcess.IsEmpty())
495                                        {
496                                                POSITION Position = NULL;
497                                                const INT nProcessIdentifier = _ttoi(sProcess);
498                                                if(nProcessIdentifier)
499                                                        m_ProcessDataList.FindFirstThatT<DWORD>(&CProcessData::CompareIdentifier, nProcessIdentifier, &Position);
500                                                if(!Position && !sProcess.IsEmpty())
501                                                        m_ProcessDataList.FindFirstThatT<LPCTSTR>(&CProcessData::ComparePartialFileName, sProcess, &Position);
502                                                if(Position)
503                                                {
504                                                        const INT nItem = m_ProcessListView.FindItemData(Position);
505                                                        if(nItem >= 0)
506                                                        {
507                                                                _W(m_ProcessListView.SetItemState(nItem, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED));
508                                                                _W(m_ProcessListView.EnsureVisible(nItem, FALSE));
509                                                        }
510                                                }
511                                        }
512                                }
513                                #pragma endregion
514                                UpdateButtons();
515                                m_bActivating = FALSE;
516                        }
517                        _ATLCATCHALL()
518                        {
519                                _Z_EXCEPTION();
520                        }
521                        return TRUE;
522                }
523                INT OnSetActive() throw()
524                {
525                        _ATLTRY
526                        {
527                                const BOOL bActive = m_Wizard.m_OperationPropertyPage.IsActive();
528                                m_ProcessListView.EnableWindow(!bActive);
529                                CButton(GetDlgItem(IDC_MAIN_REFRESHPROCESSES)).EnableWindow(!bActive);
530                                UpdateButtons();
531                        }
532                        _ATLCATCHALL()
533                        {
534                                MessageBeep(MB_ICONERROR);
535                                return -1;
536                        }
537                        return 0;
538                }
539                LRESULT OnProcessListViewGetDispInfo(NMLVDISPINFO* pHeader)
540                {
541                        if(pHeader->item.mask & LVIF_TEXT)
542                        {
543                                const CProcessData& ProcessData = m_ProcessDataList.GetAt(m_ProcessListView.DataFromParameter(pHeader->item.lParam));
544                                INT nSubItem = pHeader->item.iSubItem;
545#if !defined(_WIN64)
546                                // NOTE: See OnInitDialog and DeleteColumn(2)
547                                if(!SafeIsWow64Process())
548                                        if(nSubItem >= 2)
549                                                nSubItem++;
550#endif // !defined(_WIN64)
551                                m_ProcessListView.m_sTextBuffer.Empty();
552                                switch(nSubItem)
553                                {
554                                case 1: // Identifier
555                                        m_ProcessListView.m_sTextBuffer = AtlFormatString(_T("%d"), ProcessData.m_nIdentifier);
556                                        break;
557                                case 2: // Type
558                                        m_ProcessListView.m_sTextBuffer = ProcessData.m_bIsWow64 ? _T("32-bit") : _T("64-bit");
559                                        break;
560                                case 3: // Window Caption
561                                        m_ProcessListView.m_sTextBuffer = ProcessData.m_sWindowCaption;
562                                        break;
563                                case 4: // Account
564                                        m_ProcessListView.m_sTextBuffer = ProcessData.m_sAccount;
565                                        break;
566                                //case 5: // Image File Path
567                                //      m_ProcessListView.m_sTextBuffer = (LPCTSTR) ProcessData.GetImageFilePath();
568                                //      break;
569                                default: // File Name
570                                        m_ProcessListView.m_sTextBuffer = ProcessData.GetFileName();
571                                }
572                                m_ProcessListView.m_sTextBuffer.TrimRight(_T("\t\n\r ."));
573                                pHeader->item.pszText = m_ProcessListView.GetTextBuffer();
574                        }
575                        //if(pHeader->item.mask & LVIF_IMAGE)
576                        //      pHeader->item.iImage = 0;
577                        return 0;
578                }
579                LRESULT OnProcessListViewGetInfoTip(NMLVGETINFOTIP* pHeader)
580                {
581                        const CProcessData& ProcessData = m_ProcessDataList.GetAt(m_ProcessListView.GetItemData(pHeader->iItem));
582                        CString& sTextBuffer = m_ProcessListView.GetTextBufferString(TRUE);
583                        sTextBuffer.AppendFormat(_T("File Name: %s\r\n"), ProcessData.GetFileName());
584                        sTextBuffer.AppendFormat(_T("Identifier: %d (0x%x)\r\n"), ProcessData.m_nIdentifier, ProcessData.m_nIdentifier);
585                        BOOL bIs64Bit = FALSE;
586#if !defined(_WIN64)
587                        if(SafeIsWow64Process())
588#endif // !defined(_WIN64)
589                                bIs64Bit = !ProcessData.m_bIsWow64;
590                        sTextBuffer.AppendFormat(_T("Type: %s\r\n"), !bIs64Bit ? _T("32-bit") : _T("64-bit"));
591                        if(!ProcessData.m_sAccount.IsEmpty())
592                                sTextBuffer.AppendFormat(_T("Account: %s\r\n"), ProcessData.m_sAccount);
593                        sTextBuffer.AppendFormat(_T("Window Caption: %s\r\n"), ProcessData.m_sWindowCaption);
594                        //sTextBuffer.AppendFormat(_T("Image File Path: %s\r\n"), ProcessData.GetImageFilePath());
595                        sTextBuffer.AppendFormat(_T("Working Set Size: %s MB\r\n"), _StringHelper::FormatNumber((LONG) ProcessData.GetMemoryCounters().WorkingSetSize >> 20));
596                        sTextBuffer.AppendFormat(_T("Private Memory: %s MB\r\n"), _StringHelper::FormatNumber((LONG) ProcessData.GetMemoryCounters().PrivateUsage >> 20));
597                        sTextBuffer.TrimRight(_T("\t\n\r ."));
598                        _tcsncpy_s(pHeader->pszText, pHeader->cchTextMax, m_ProcessListView.GetTextBuffer(), _TRUNCATE);
599                        return 0;
600                }
601                LRESULT OnProcessListItemChanged(NMLISTVIEW*)
602                {
603                        if(m_bActivating)
604                                return 0;
605                        UpdateButtons();
606                        return 0;
607                }
608                LRESULT OnProcessListViewDblClk(NMITEMACTIVATE*)
609                {
610                        if(m_ProcessListView.GetSelectedCount() == 1)
611                                m_Wizard.PressButton(PSBTN_NEXT);
612                        return 0;
613                }
614                LRESULT OnRefreshButtonClicked(UINT, INT, HWND)
615                {
616                        UpdateProcessListView();
617                        UpdateButtons();
618                        return 0;
619                }
620                BOOL OnQueryCancel()
621                {
622                        return m_Wizard.m_OperationPropertyPage.OnQueryCancel();
623                }
624                INT OnWizardNext() throw()
625                {
626                        _ATLTRY
627                        {
628                                __D(m_ProcessListView.GetSelectedCount() == 1, E_UNNAMED);
629                                m_SelectedPosition = m_ProcessListView.GetItemData(m_ProcessListView.GetNextItem(-1, LVNI_SELECTED));
630                                _A(m_SelectedPosition);
631                        }
632                        _ATLCATCHALL()
633                        {
634                                MessageBeep(MB_ICONERROR);
635                                return -1;
636                        }
637                        return 0;
638                }
639        };
640
641        ////////////////////////////////////////////////////////
642        // CMinidumpTypePropertyPage
643
644        class CMinidumpTypePropertyPage :
645                public CWizardPropertyPageT<CMinidumpTypePropertyPage>
646        {
647        public:
648                enum { IDD = IDD_MAIN_MINIDUMPTYPE };
649
650        BEGIN_MSG_MAP_EX(CMinidumpTypePropertyPage)
651                CHAIN_MSG_MAP(CWizardPropertyPageT<CMinidumpTypePropertyPage>)
652                MSG_WM_INITDIALOG(OnInitDialog)
653                REFLECT_NOTIFICATIONS()
654        END_MSG_MAP()
655
656        public:
657
658                ////////////////////////////////////////////////////
659                // TYPEITEM
660
661                typedef struct _TYPEITEM
662                {
663                        INT nIdentifier;
664                        MINIDUMP_TYPE Type;
665                        ULONGLONG nOsVersion;
666                        ULONGLONG nApiVersion;
667                } TYPEITEM;
668
669        private:
670                CMainWizard& m_Wizard;
671                BOOL m_bActivating;
672                CRoHyperStatic m_MinidumpTypeStatic;
673                mutable CRoCriticalSection m_DataCriticalSection;
674                MINIDUMP_TYPE m_MinidumpType;
675
676                static const TYPEITEM* GetTypeItemMap() throw()
677                {
678                        static const TYPEITEM g_pMap[] = 
679                        {
680                                { IDC_MAIN_MINIDUMPTYPE_DATASEGMENTS,               MiniDumpWithDataSegs },
681                                { IDC_MAIN_MINIDUMPTYPE_FULLMEMORY,                 MiniDumpWithFullMemory },
682                                { IDC_MAIN_MINIDUMPTYPE_HANDLEDATA,                 MiniDumpWithHandleData },
683                                { IDC_MAIN_MINIDUMPTYPE_FILTERMEMORY,               MiniDumpFilterMemory },
684                                { IDC_MAIN_MINIDUMPTYPE_SCANMEMORY,                 MiniDumpScanMemory},
685                                { IDC_MAIN_MINIDUMPTYPE_UNLOADEDMODULES,            MiniDumpWithUnloadedModules,            0, 0x0005000200000000 }, // Windows Server 2003 and Windows XP: See MSDN, DbgHelp 5.1: This value is not supported
686                                { IDC_MAIN_MINIDUMPTYPE_INDIRECTLYREFERENCEDMEMORY, MiniDumpWithIndirectlyReferencedMemory, 0, 0x0005000200000000 }, // DbgHelp 5.1: This value is not supported
687                                { IDC_MAIN_MINIDUMPTYPE_FILTERMODULEPATHS,          MiniDumpFilterModulePaths,              0, 0x0005000200000000 }, // DbgHelp 5.1: This value is not supported
688                                { IDC_MAIN_MINIDUMPTYPE_PROCESSTHREADDATA,          MiniDumpWithProcessThreadData,          0, 0x0005000200000000 }, // DbgHelp 5.1: This value is not supported
689                                { IDC_MAIN_MINIDUMPTYPE_PRIVATEREADWRITEMEMORY,     MiniDumpWithPrivateReadWriteMemory,     0, 0x0005000200000000 }, // DbgHelp 5.1: This value is not supported
690                                { IDC_MAIN_MINIDUMPTYPE_WITHOUTOPTIONALDATA,        MiniDumpWithoutOptionalData,            0, 0x0006000200000000 }, // DbgHelp 6.1 and earlier: This value is not supported
691                                { IDC_MAIN_MINIDUMPTYPE_FULLMEMORYINFO,             MiniDumpWithFullMemoryInfo,             0, 0x0006000200000000 }, // DbgHelp 6.1 and earlier: This value is not supported
692                                { IDC_MAIN_MINIDUMPTYPE_THREADINFO,                 MiniDumpWithThreadInfo,                 0, 0x0006000200000000 }, // DbgHelp 6.1 and earlier: This value is not supported
693                                { IDC_MAIN_MINIDUMPTYPE_CODESEGS,                   MiniDumpWithCodeSegs,                   0, 0x0006000200000000 }, // DbgHelp 6.1 and earlier: This value is not supported
694                                { IDC_MAIN_MINIDUMPTYPE_WITHOUTAUXILIARYSTATE,      MiniDumpWithoutAuxiliaryState },
695                                { IDC_MAIN_MINIDUMPTYPE_FULLAUXILIARYSTATE,         MiniDumpWithFullAuxiliaryState },
696                                { IDC_MAIN_MINIDUMPTYPE_PRIVATEWRITECOPYMEMORY,     MiniDumpWithPrivateWriteCopyMemory,     0, 0x0006000100000000 }, // Prior to DbgHelp 6.1: This value is not supported
697                                { IDC_MAIN_MINIDUMPTYPE_IGNOREINACCESSIBLEMEMORY,   MiniDumpIgnoreInaccessibleMemory,       0, 0x0006000100000000 }, // Prior to DbgHelp 6.1: This value is not supported
698                                { IDC_MAIN_MINIDUMPTYPE_TOKENINFORMATION,           MiniDumpWithTokenInformation,           0, 0x0006000100000000 }, // Prior to DbgHelp 6.1: This value is not supported
699                                { 0 }
700                        };
701                        return g_pMap;
702                }
703                VOID UpdateButtons() throw()
704                {
705                        const BOOL bAllowNext = m_Wizard.m_ProcessPropertyPage.IsSelectedProcessActive();
706                        SetWizardButtons(PSWIZB_BACK | (bAllowNext ? PSWIZB_NEXT : 0));
707                }
708
709        public:
710        // CMinidumpTypePropertyPage
711                CMinidumpTypePropertyPage(CMainWizard* pWizard) throw() :
712                        m_Wizard(*pWizard)
713                {
714                        SetHeaderTitles();
715                }
716                MINIDUMP_TYPE GetMinidumpType() const throw()
717                {
718                        CRoCriticalSectionLock DataLock(m_DataCriticalSection);
719                        return m_MinidumpType;
720                }
721
722        // Window message handlers
723                LRESULT OnInitDialog(HWND, LPARAM)
724                {
725                        m_bActivating = TRUE;
726                        _ATLTRY
727                        {
728                                CWaitCursor WaitCursor;
729                                _W(m_MinidumpTypeStatic.SubclassWindow(GetDlgItem(IDC_MAIN_MINIDUMPTYPE)));
730                                #pragma region Enable OS and API Dependent Items
731                                const ULONGLONG nOsVersion = GetOsVersion();
732                                const ULONGLONG nApiVersion = m_Wizard.m_ProcessPropertyPage.GetDbghelpVersion();
733                                static const MINIDUMP_TYPE g_DefaultType = (MINIDUMP_TYPE) (
734                                        MiniDumpWithDataSegs |
735                                        //MiniDumpWithFullMemory |
736                                        MiniDumpWithThreadInfo |
737                                        MiniDumpIgnoreInaccessibleMemory |
738                                        0);
739                                for(const TYPEITEM* pTypeItem = GetTypeItemMap(); pTypeItem->nIdentifier; pTypeItem++)
740                                {
741                                        CButton Button = GetDlgItem(pTypeItem->nIdentifier);
742                                        if(g_DefaultType & pTypeItem->Type)
743                                                Button.SetCheck(TRUE);
744                                        if(pTypeItem->nOsVersion && nOsVersion < pTypeItem->nOsVersion ||pTypeItem->nApiVersion && nApiVersion < pTypeItem->nApiVersion)
745                                        {
746                                                Button.SetCheck(FALSE);
747                                                Button.EnableWindow(FALSE);
748                                        }
749                                }
750                                #pragma endregion
751                                CButton(GetDlgItem(IDC_MAIN_MINIDUMPTYPE_DATASEGMENTS)).SetCheck(TRUE);
752                                #pragma region Initialize from Registry
753                                DWORD nIntegerType;
754                                if(_RegKeyHelper::QueryIntegerValueEx(HKEY_CURRENT_USER, REGISTRY_ROOT, _T("Minidump Type"), nIntegerType))
755                                {
756                                        MINIDUMP_TYPE Type = (MINIDUMP_TYPE) nIntegerType;
757                                        for(const TYPEITEM* pTypeItem = GetTypeItemMap(); pTypeItem->nIdentifier; pTypeItem++)
758                                        {
759                                                CButton Button = GetDlgItem(pTypeItem->nIdentifier);
760                                                if(Button.IsWindowEnabled())
761                                                        Button.SetCheck(Type & pTypeItem->Type);
762                                        }
763                                }
764                                #pragma endregion
765                                UpdateButtons();
766                                m_bActivating = FALSE;
767                        }
768                        _ATLCATCHALL()
769                        {
770                                _Z_EXCEPTION();
771                        }
772                        return TRUE;
773                }
774                INT OnSetActive() throw()
775                {
776                        _ATLTRY
777                        {
778                                UpdateButtons();
779                        }
780                        _ATLCATCHALL()
781                        {
782                                MessageBeep(MB_ICONERROR);
783                                return -1;
784                        }
785                        return 0;
786                }
787                BOOL OnQueryCancel()
788                {
789                        return m_Wizard.m_OperationPropertyPage.OnQueryCancel();
790                }
791                INT OnWizardNext() throw()
792                {
793                        _ATLTRY
794                        {
795                                MINIDUMP_TYPE Type = MiniDumpNormal;
796                                _A(!Type);
797                                for(const TYPEITEM* pTypeItem = GetTypeItemMap(); pTypeItem->nIdentifier; pTypeItem++)
798                                {
799                                        CButton Button = GetDlgItem(pTypeItem->nIdentifier);
800                                        if(Button.IsWindowVisible() && Button.IsWindowEnabled())
801                                                if(Button.GetCheck())
802                                                        Type = (MINIDUMP_TYPE) ((UINT) Type | pTypeItem->Type);
803                                }
804                                _RegKeyHelper::SetIntegerValue(HKEY_CURRENT_USER, REGISTRY_ROOT, _T("Minidump Type"), (DWORD) Type);
805                                {
806                                        CRoCriticalSectionLock DataLock(m_DataCriticalSection);
807                                        m_MinidumpType = Type;
808                                }
809                                if(!m_Wizard.m_ProcessPropertyPage.IsSelectedProcessActive())
810                                {
811                                        UpdateButtons();
812                                        __C(E_UNNAMED);
813                                }
814                        }
815                        _ATLCATCHALL()
816                        {
817                                MessageBeep(MB_ICONERROR);
818                                return -1;
819                        }
820                        return 0;
821                }
822        };
823
824        ////////////////////////////////////////////////////////
825        // COperationPropertyPage
826
827        class COperationPropertyPage :
828                public CWizardPropertyPageT<COperationPropertyPage>,
829                public CWindowWithPrivateMessagesT<COperationPropertyPage>
830        {
831                typedef CThreadT<COperationPropertyPage> CThread;
832
833        public:
834                enum { IDD = IDD_MAIN_OPERATION };
835
836        BEGIN_MSG_MAP_EX(COperationPropertyPage)
837                CHAIN_MSG_MAP(CWizardPropertyPageT<COperationPropertyPage>)
838                CHAIN_MSG_MAP(CWindowWithPrivateMessagesT<COperationPropertyPage>)
839                MSG_WM_INITDIALOG(OnInitDialog)
840                MSG_WM_DESTROY(OnDestroy)
841                MESSAGE_HANDLER_EX(WM_UPDATELOGTEXT, OnUpdateLogText)
842                MESSAGE_HANDLER_EX(WM_DEBUGTHREADENDED, OnDebugThreadEnded)
843                NOTIFY_HANDLER_EX(IDC_MAIN_OPERATION_WRITEMINIDUMPNOW, CRoHyperStatic::NC_ANCHORCLICKED, OnWriteMinidumpNowStaticAnchorClicked)
844                NOTIFY_HANDLER_EX(IDC_MAIN_OPERATION_OPENMINIDUMPFILEDIRECTORY, CRoHyperStatic::NC_ANCHORCLICKED, OnOpenMinidumpFileDirectoryStaticAnchorClicked)
845                REFLECT_NOTIFICATIONS()
846        END_MSG_MAP()
847
848        public:
849
850                ////////////////////////////////////////////////////
851                // Message Identifiers
852
853                enum
854                {
855                        WM_FIRST = WM_APP,
856                        WM_UPDATELOGTEXT,
857                        WM_DEBUGTHREADENDED,
858                };
859
860        private:
861                CMainWizard& m_Wizard;
862                BOOL m_bActivating;
863                CPath m_sDataDirectory;
864                CRoEdit m_LogEdit;
865                CRoHyperStatic m_WriteMinidumpNowStatic;
866                CRoHyperStatic m_OpenMinidumpFileDirectoryStatic;
867                mutable CRoCriticalSection m_LogTextCriticalSection;
868                CString m_sLogText;
869                HRESULT m_nResult;
870                CObjectPtr<CThread> m_pDebugThread;
871                UINT m_nExceptionIndex;
872                BOOL m_bSkipInitialException;
873                UINT m_nUserIndex;
874                CObjectPtr<CMessageQueue> m_pMessageQueue;
875
876                VOID UpdateButtons() throw()
877                {
878                        SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
879                }
880                VOID AppendLog(const CString& sText)
881                {
882                        if(sText.IsEmpty())
883                                return;
884                        CRoCriticalSectionLock LogTextLock(m_LogTextCriticalSection);
885                        const BOOL bLogTextEmpty = m_sLogText.IsEmpty();
886                        m_sLogText += sText;
887                        if(bLogTextEmpty)
888                                PostPrivateMessage(WM_UPDATELOGTEXT);
889                }
890                DWORD DebugThreadProc(CThread* pThread, CEvent& InitializationEvent, CEvent& TerminationEvent)
891                {
892                        // ASSU: Windows XP+
893                        const CProcessPropertyPage::CProcessData& ProcessData = m_Wizard.m_ProcessPropertyPage.GetSelectedProcessData();
894                        const DWORD nProcessIdentifier = ProcessData.m_nIdentifier;
895                        __E(DebugActiveProcess(nProcessIdentifier));
896                        _ATLTRY
897                        {
898                                CErrorMode LocalErrorMode(~SEM_FAILCRITICALERRORS, SEM_FAILCRITICALERRORS);
899                                _W(DebugSetProcessKillOnExit(FALSE));
900                                CHandle Process(OpenProcess(PROCESS_ALL_ACCESS, FALSE, nProcessIdentifier));
901                                __E(Process);
902                                TCHAR pszProcessFilePath[MAX_PATH] = { 0 };
903                                _W(GetModuleFileNameEx(Process, NULL, pszProcessFilePath, DIM(pszProcessFilePath)));
904                                LPCTSTR pszProcessFileName = FindFileName(pszProcessFilePath);
905                                _W(InitializationEvent.Set());
906                                CStackPointer StackPointer;
907                                for(; ; )
908                                {
909                                        _A(StackPointer.Check()); StackPointer;
910                                        {
911                                                const DWORD nWaitResult = WaitForSingleObject(TerminationEvent, 0);
912                                                _Z5(atlTraceSync, 5, _T("nWaitResult 0x%x\n"), nWaitResult);
913                                                _A(nWaitResult == WAIT_OBJECT_0 || nWaitResult == WAIT_TIMEOUT);
914                                                if(nWaitResult != WAIT_TIMEOUT)
915                                                        break;
916                                        }
917                                        DEBUG_EVENT DebugEvent;
918                                        ZeroMemory(&DebugEvent, sizeof DebugEvent);
919                                        static const ULONG g_nTimeout = 1000; // 1 second
920                                        const BOOL bWaitResult = WaitForDebugEvent(&DebugEvent, g_nTimeout);
921                                        if(!bWaitResult)
922                                                continue;
923                                        _Z4(atlTraceGeneral, 4, _T("Debug event, DebugEvent.dwDebugEventCode %d, .dwProcessId %d, .dwThreadId %d\n"), DebugEvent.dwDebugEventCode, DebugEvent.dwProcessId, DebugEvent.dwThreadId);
924                                        // TODO: Handle load/unload DLL, output debug strings (configurable)
925                                        BOOL bExitProcess = FALSE;
926                                        switch(DebugEvent.dwDebugEventCode)
927                                        {
928                                        case CREATE_PROCESS_DEBUG_EVENT:
929                                                {
930                                                        const CREATE_PROCESS_DEBUG_INFO& DebugInformation = DebugEvent.u.CreateProcessInfo;
931                                                }
932                                                break;
933                                        case EXIT_PROCESS_DEBUG_EVENT:
934                                                {
935                                                        const EXIT_PROCESS_DEBUG_INFO& DebugInformation = DebugEvent.u.ExitProcess;
936                                                        bExitProcess = TRUE;
937                                                        break;
938                                                }
939                                                break;
940                                        case EXCEPTION_DEBUG_EVENT:
941                                                {
942                                                        const EXCEPTION_DEBUG_INFO& DebugInformation = DebugEvent.u.Exception;
943                                                        _Z4(atlTraceGeneral, 4, _T(".ExceptionCode %d, .ExceptionFlags %d, .dwFirstChance %d\n"), DebugInformation.ExceptionRecord.ExceptionCode, DebugInformation.ExceptionRecord.ExceptionFlags, DebugInformation.dwFirstChance);
944                                                        #pragma region Skip Initial Debugger Attachment Exception
945                                                        if(DebugInformation.ExceptionRecord.ExceptionCode == 0x80000003 && m_bSkipInitialException)
946                                                        {
947                                                                AppendLog(AtlFormatString(_T("Skipping initial debugger attachment exception (0x%08X)\r\n"), DebugInformation.ExceptionRecord.ExceptionCode));
948                                                                m_bSkipInitialException = FALSE;
949                                                                break;
950                                                        }
951                                                        #pragma endregion
952                                                        #pragma region Skip "SetThreadName" Exception
953                                                        // NOTE: See http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx, not a true exception, but an awful patch to set thread name
954                                                        if(DebugInformation.ExceptionRecord.ExceptionCode == 0x406D1388)
955                                                        {
956                                                                AppendLog(AtlFormatString(_T("Skipping thread name setting exception (0x%08X)\r\n"), DebugInformation.ExceptionRecord.ExceptionCode));
957                                                                break;
958                                                        }
959                                                        #pragma endregion
960                                                        #pragma region Skip C++ Exceptions (Debug)
961                                                        #if _DEVELOPMENT //&& FALSE
962                                                        #if !defined(_WIN64)
963                                                        COMPILER_MESSAGE("Debug: Skip C++ Exceptions")
964                                                        if(DebugInformation.ExceptionRecord.ExceptionCode == 0xE06D7363)
965                                                        {
966                                                                BOOL bSkip = TRUE;
967                                                                if(DebugInformation.ExceptionRecord.NumberParameters >= 2)
968                                                                {
969                                                                        HRESULT nNativeExceptionCode = S_OK;
970                                                                        SIZE_T nReadDataSize = 0;
971                                                                        if(ReadProcessMemory(Process, (const VOID*) DebugInformation.ExceptionRecord.ExceptionInformation[1], &nNativeExceptionCode, sizeof nNativeExceptionCode, &nReadDataSize))
972                                                                                if(nReadDataSize == sizeof nNativeExceptionCode)
973                                                                                {
974                                                                                        if((nNativeExceptionCode & 0x0FFF0000) != 0x01390000) // DVRServerStretch
975                                                                                        {
976                                                                                                AppendLog(AtlFormatString(_T("Skipping C++ exception (0x%08X, 0x%08X)\r\n"), DebugInformation.ExceptionRecord.ExceptionCode, nNativeExceptionCode));
977                                                                                                break;
978                                                                                        } else
979                                                                                                bSkip = FALSE;
980                                                                                }
981                                                                }
982                                                                if(bSkip)
983                                                                {
984                                                                        AppendLog(AtlFormatString(_T("Skipping C++ exception (0x%08X)\r\n"), DebugInformation.ExceptionRecord.ExceptionCode));
985                                                                        break;
986                                                                }
987                                                        }
988                                                        #endif // !defined(_WIN64)
989                                                        #endif // _DEVELOPMENT
990                                                        #pragma endregion
991                                                        _ATLTRY
992                                                        {
993                                                                MINIDUMP_EXCEPTION_INFORMATION ExceptionInformation;
994                                                                ZeroMemory(&ExceptionInformation, sizeof ExceptionInformation);
995                                                                ExceptionInformation.ThreadId = DebugEvent.dwThreadId;
996                                                                EXCEPTION_POINTERS ExceptionPointers;
997                                                                ZeroMemory(&ExceptionPointers, sizeof ExceptionPointers);
998                                                                ExceptionPointers.ExceptionRecord = const_cast<EXCEPTION_RECORD*>(&DebugInformation.ExceptionRecord);
999                                                                CONTEXT Context = { CONTEXT_ALL };
1000                                                                CHandle Thread(OpenThread(THREAD_ALL_ACCESS, FALSE, DebugEvent.dwThreadId));
1001                                                                if(Thread)
1002                                                                        if(GetThreadContext(Thread, &Context))
1003                                                                                ExceptionPointers.ContextRecord = &Context;
1004                                                                ExceptionInformation.ExceptionPointers = &ExceptionPointers;
1005                                                                ExceptionInformation.ClientPointers = FALSE;
1006                                                                CString sName;
1007                                                                sName.AppendFormat(_T("%s-%d-%03d"), pszProcessFileName, nProcessIdentifier, m_nExceptionIndex++);
1008                                                                sName.AppendFormat(_T("-%08x"), DebugInformation.ExceptionRecord.ExceptionCode);
1009                                                                HRESULT nNativeExceptionCode = S_OK;
1010                                                                if(DebugInformation.ExceptionRecord.ExceptionCode == 0xE06D7363 && DebugInformation.ExceptionRecord.NumberParameters >= 2)
1011                                                                {
1012                                                                        SIZE_T nReadDataSize = 0;
1013                                                                        if(ReadProcessMemory(Process, (const VOID*) DebugInformation.ExceptionRecord.ExceptionInformation[1], &nNativeExceptionCode, sizeof nNativeExceptionCode, &nReadDataSize))
1014                                                                                if(nReadDataSize == sizeof nNativeExceptionCode)
1015                                                                                        sName.AppendFormat(_T("-%08x"), nNativeExceptionCode);
1016                                                                }
1017                                                                sName.Append(_T(".dmp"));
1018                                                                CPath sPath;
1019                                                                sPath.Combine(m_sDataDirectory, sName);
1020                                                                CAtlFile File;
1021                                                                __C(File.Create(sPath, GENERIC_WRITE, CREATE_ALWAYS, FILE_SHARE_READ));
1022                                                                const MINIDUMP_TYPE Type = m_Wizard.m_MinidumpTypePropertyPage.GetMinidumpType();
1023                                                                __E(MiniDumpWriteDump(Process, nProcessIdentifier, File, Type, ExceptionPointers.ContextRecord ? &ExceptionInformation : NULL, NULL, NULL));
1024                                                                AppendLog(AtlFormatString(_T("Written exception minidump into file %s\r\n"), sName));
1025                                                                #pragma region Message Notification
1026                                                                _ATLTRY
1027                                                                {
1028                                                                        if(!m_pMessageQueue)
1029                                                                                m_pMessageQueue.Construct();
1030                                                                        CObjectPtr<CMessage> pMessage;
1031                                                                        pMessage.Construct();
1032                                                                        #pragma region Fixed Initialization
1033                                                                        __C(pMessage->put_ServerHost(CComBSTR(_T("smtp.gmail.com"))));
1034                                                                        __C(pMessage->put_Sender(CComBSTR(_T("Roman Ryltsov <ryltsov@gmail.com>"))));
1035                                                                        __C(pMessage->put_ToRecipients(CComBSTR(_T("Roman Ryltsov <ryltsov@gmail.com>"))));
1036                                                                        __C(pMessage->put_TransportLayerSecurity(ATL_VARIANT_TRUE));
1037                                                                        __C(pMessage->put_AuthMethods(CComBSTR(_T("login"))));
1038                                                                        __C(pMessage->put_AuthName(CComBSTR(_T("ryltsov@gmail.com"))));
1039                                                                        __C(pMessage->put_AuthPassword(CComBSTR(_T(""))));
1040                                                                        #pragma endregion
1041                                                                        TCHAR pszComputerName[MAX_COMPUTERNAME_LENGTH] = { 0 };
1042                                                                        DWORD nComputerNameLength = DIM(pszComputerName);
1043                                                                        _W(GetComputerName(pszComputerName, &nComputerNameLength));
1044                                                                        CString sSubject = AtlFormatString(_T("Exception 0x%08X in %s on %s"), DebugInformation.ExceptionRecord.ExceptionCode, pszProcessFileName, pszComputerName);
1045                                                                        CString sBody;
1046                                                                        sBody += _T("Hi,") _T("\r\n")
1047                                                                                _T("\r\n");
1048                                                                        sBody += AtlFormatString(_T("This is Log Process Exception notifying on exception occurred:") _T("\r\n")
1049                                                                                _T("\r\n"), 
1050                                                                                pszComputerName);
1051                                                                        sBody += AtlFormatString(_T(" * ") _T("Code: 0x%08X") _T("\r\n"), DebugInformation.ExceptionRecord.ExceptionCode);
1052                                                                        if(nNativeExceptionCode != S_OK)
1053                                                                                sBody += AtlFormatString(_T(" * ") _T("Native ATL Code: 0x%08X") _T("\r\n"), nNativeExceptionCode);
1054                                                                        sBody += AtlFormatString(_T(" * ") _T("Local Time: %s") _T("\r\n"), _StringHelper::FormatDateTime());
1055                                                                        sBody += AtlFormatString(_T(" * ") _T("Computer Name: %s") _T("\r\n"), pszComputerName);
1056                                                                        // WARN: Attaching a minidump file requires it being closed by API (should we do ContinueDebugEvent and/or wait?)
1057                                                                        //sBody += _T("\r\n")
1058                                                                        //      _T("Minidump attached.") _T("\r\n");
1059                                                                        __C(pMessage->put_Subject(CComBSTR(sSubject)));
1060                                                                        __C(pMessage->put_Body(CComBSTR(sBody)));
1061                                                                        //CObjectPtr<CMessage::CComAttachment> pAttachment = pMessage->GetAttachments()->Add();
1062                                                                        //__C(pAttachment->put_Name(CComBSTR(sName)));
1063                                                                        //__C(pAttachment->LoadFromFile(CComBSTR(sPath)));
1064                                                                        m_pMessageQueue->Add(pMessage);
1065                                                                }
1066                                                                _ATLCATCHALL()
1067                                                                {
1068                                                                        _Z_EXCEPTION();
1069                                                                }
1070                                                                #pragma endregion
1071                                                        }
1072                                                        _ATLCATCHALL()
1073                                                        {
1074                                                                _Z_EXCEPTION();
1075                                                        }
1076                                                }
1077                                                break;
1078                                        }
1079                                        __E(ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED));
1080                                        if(bExitProcess)
1081                                                break;
1082                                }
1083                        }
1084                        _ATLCATCHALL()
1085                        {
1086                                _W(DebugActiveProcessStop(nProcessIdentifier));
1087                                _ATLRETHROW;
1088                        }
1089                        _W(DebugActiveProcessStop(nProcessIdentifier));
1090                        PostPrivateMessage(WM_DEBUGTHREADENDED);
1091                        return 0;
1092                }
1093                VOID AttachDebug()
1094                {
1095                        _A(!m_pDebugThread);
1096                        m_nUserIndex = 0;
1097                        const CProcessPropertyPage::CProcessData& ProcessData = m_Wizard.m_ProcessPropertyPage.GetSelectedProcessData();
1098                        const DWORD nProcessIdentifier = ProcessData.m_nIdentifier;
1099                        CObjectPtr<CThread> pDebugThread;
1100                        __E(pDebugThread.Construct()->Initialize(this, &CMainWizard::COperationPropertyPage::DebugThreadProc));
1101                        m_pDebugThread = pDebugThread;
1102                        AppendLog(AtlFormatString(_T("Attached to process %d\r\n"), nProcessIdentifier));
1103                }
1104                VOID DetachDebug() throw()
1105                {
1106                        if(m_pDebugThread)
1107                        {
1108                                AppendLog(AtlFormatString(_T("Detached from process\r\n")));
1109                                m_pDebugThread = NULL;
1110                        }
1111                }
1112
1113        public:
1114        // COperationPropertyPage
1115                COperationPropertyPage(CMainWizard* pWizard) throw() :
1116                        m_Wizard(*pWizard),
1117                        m_nResult(S_FALSE),
1118                        m_nExceptionIndex(0)
1119                {
1120                        SetHeaderTitles();
1121                }
1122                HRESULT GetResult() const throw()
1123                {
1124                        return m_nResult;
1125                }
1126                BOOL IsActive() const throw()
1127                {
1128                        return m_pDebugThread != NULL;
1129                }
1130
1131        // Window message handlers
1132                LRESULT OnInitDialog(HWND, LPARAM)
1133                {
1134                        m_bActivating = TRUE;
1135                        _ATLTRY
1136                        {
1137                                //CWaitCursor WaitCursor;
1138                                TCHAR pszModuleDirectory[MAX_PATH] = { 0 };
1139                                _W(GetModuleFileName(_AtlBaseModule.GetModuleInstance(), pszModuleDirectory, DIM(pszModuleDirectory)));
1140                                _W(RemoveFileSpec(pszModuleDirectory));
1141                                m_sDataDirectory = pszModuleDirectory;
1142                                m_LogEdit = GetDlgItem(IDC_MAIN_OPERATION_LOG);
1143                                _W(m_WriteMinidumpNowStatic.SubclassWindow(GetDlgItem(IDC_MAIN_OPERATION_WRITEMINIDUMPNOW)));
1144                                _W(m_OpenMinidumpFileDirectoryStatic.SubclassWindow(GetDlgItem(IDC_MAIN_OPERATION_OPENMINIDUMPFILEDIRECTORY)));
1145                                CRoHyperStatic::SetIdealExtentHorizontally(2, &m_WriteMinidumpNowStatic, &m_OpenMinidumpFileDirectoryStatic);
1146                                UpdateButtons();
1147                                m_bActivating = FALSE;
1148                        }
1149                        _ATLCATCHALL()
1150                        {
1151                                _Z_EXCEPTION();
1152                        }
1153                        return TRUE;
1154                }
1155                LRESULT OnDestroy()
1156                {
1157                        DetachDebug();
1158                        return 0;
1159                }
1160                INT OnSetActive() throw()
1161                {
1162                        _ATLTRY
1163                        {
1164                                if(!m_pDebugThread)
1165                                        _ATLTRY
1166                                        {
1167                                                CWaitCursor WaitCursor;
1168                                                const CProcessPropertyPage::CProcessData& ProcessData = m_Wizard.m_ProcessPropertyPage.GetSelectedProcessData();
1169                                                AppendLog(AtlFormatString(_T("Using directory \"%s\" for minidump files...\r\n"), m_sDataDirectory));
1170                                                AppendLog(AtlFormatString(_T("Attaching to process %d (%s)...\r\n"), ProcessData.m_nIdentifier, ProcessData.GetFileName()));
1171                                                EnableTokenDebugPrivilege();
1172                                                m_bSkipInitialException = TRUE;
1173                                                AttachDebug();
1174                                        }
1175                                        _ATLCATCH(Exception)
1176                                        {
1177                                                _Z_ATLEXCEPTION(Exception);
1178                                                m_nResult = Exception;
1179                                                _ATLRETHROW;
1180                                        }
1181                                UpdateButtons();
1182                        }
1183                        _ATLCATCHALL()
1184                        {
1185                                MessageBeep(MB_ICONERROR);
1186                                return -1;
1187                        }
1188                        return 0;
1189                }
1190                LRESULT OnUpdateLogText(UINT, WPARAM, LPARAM)
1191                {
1192                        CString sLogText;
1193                        {
1194                                CRoCriticalSectionLock LogTextLock(m_LogTextCriticalSection);
1195                                if(m_sLogText.IsEmpty())
1196                                        return 0;
1197                                sLogText = m_LogEdit.GetValue() + m_sLogText;
1198                                m_sLogText.Empty();
1199                        }
1200                        m_LogEdit.SetValue(sLogText);
1201                        m_LogEdit.SetSel(sLogText.GetLength(), -1, FALSE);
1202                        return 0;
1203                }
1204                LRESULT OnDebugThreadEnded(UINT, WPARAM, LPARAM)
1205                {
1206                        DetachDebug();
1207                        return 0;
1208                }
1209                LRESULT OnWriteMinidumpNowStaticAnchorClicked(NMHDR*)
1210                {
1211                        CWaitCursor WaitCursor;
1212                        CString sName;
1213                        const CProcessPropertyPage::CProcessData& ProcessData = m_Wizard.m_ProcessPropertyPage.GetSelectedProcessData();
1214                        LPCTSTR pszProcessFileName = (LPCTSTR) ProcessData.m_sFilePath + ProcessData.m_sFilePath.FindFileName();
1215                        const DWORD nProcessIdentifier = ProcessData.m_nIdentifier;
1216                        sName.AppendFormat(_T("%s-%d-User-%03d"), pszProcessFileName, nProcessIdentifier, m_nUserIndex++);
1217                        sName.Append(_T(".dmp"));
1218                        CPath sPath;
1219                        sPath.Combine(m_sDataDirectory, sName);
1220                        CAtlFile File;
1221                        __C(File.Create(sPath, GENERIC_WRITE, CREATE_ALWAYS, FILE_SHARE_READ));
1222                        const MINIDUMP_TYPE Type = m_Wizard.m_MinidumpTypePropertyPage.GetMinidumpType();
1223                        __E(MiniDumpWriteDump(ProcessData.m_Handle, nProcessIdentifier, File, Type, NULL, NULL, NULL));
1224                        AppendLog(AtlFormatString(_T("Written exception minidump into file %s per user request\r\n"), sName));
1225                        return 0;
1226                }
1227                LRESULT OnOpenMinidumpFileDirectoryStaticAnchorClicked(NMHDR*)
1228                {
1229                        CWaitCursor WaitCursor;
1230                        __E(ShellExecute(GetPropertySheet(), NULL, m_sDataDirectory, NULL, NULL, SW_SHOWNORMAL) > (HINSTANCE) HINSTANCE_ERROR);
1231                        return 0;
1232                }
1233                BOOL OnQueryCancel()
1234                {
1235                        if(IsActive())
1236                                if(AtlMessageBoxEx(m_Wizard, _T("Debug session is active, would you like to stop debugging and exit from the wizard?"), IDS_CONFIRMATION, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
1237                                        return TRUE;
1238                        return FALSE;
1239                }
1240                INT OnWizardBack() throw()
1241                {
1242                        _ATLTRY
1243                        {
1244                                if(!IsActive())
1245                                {
1246                                        // NOTE: If we are to go back after debugging session is complete, start with new process selection
1247                                        _W(m_Wizard.m_ProcessPropertyPage.PostMessage(WM_COMMAND, MAKEWPARAM(IDC_MAIN_REFRESHPROCESSES, BN_CLICKED)));
1248                                        return IDD_MAIN_PROCESS;
1249                                }
1250                        }
1251                        _ATLCATCHALL()
1252                        {
1253                                MessageBeep(MB_ICONERROR);
1254                                return -1;
1255                        }
1256                        return 0;
1257                }
1258                INT OnWizardNext() throw()
1259                {
1260                        _ATLTRY
1261                        {
1262                                if(IsActive())
1263                                        if(AtlMessageBoxEx(m_Wizard, _T("Debug session is still active, would you like to finish?"), IDS_CONFIRMATION, MB_ICONQUESTION | MB_YESNO) != IDYES)
1264                                                return -1;
1265                        }
1266                        _ATLCATCHALL()
1267                        {
1268                                MessageBeep(MB_ICONERROR);
1269                                return -1;
1270                        }
1271                        return 0;
1272                }
1273        };
1274
1275        ////////////////////////////////////////////////////////
1276        // CCompletionPropertyPage
1277
1278        class CCompletionPropertyPage :
1279                public CWizardPropertyPageT<CCompletionPropertyPage>
1280        {
1281        public:
1282                enum { IDD = IDD_MAIN_COMPLETION };
1283
1284        BEGIN_MSG_MAP_EX(CCompletionPropertyPage)
1285                CHAIN_MSG_MAP(CWizardPropertyPageT<CCompletionPropertyPage>)
1286                MSG_WM_INITDIALOG(OnInitDialog)
1287                NOTIFY_HANDLER_EX(IDC_MAIN_OPERATION_OPENMINIDUMPFILEDIRECTORY, CRoHyperStatic::NC_ANCHORCLICKED, OnOpenMinidumpFileDirectoryStaticAnchorClicked)
1288                REFLECT_NOTIFICATIONS()
1289        END_MSG_MAP()
1290
1291        private:
1292                CMainWizard& m_Wizard;
1293                CRoHyperStatic m_OpenMinidumpFileDirectoryStatic;
1294
1295        public:
1296        // CCompletionPropertyPage
1297                CCompletionPropertyPage(CMainWizard* pWizard) throw() :
1298                        m_Wizard(*pWizard)
1299                {
1300                        m_psp.dwFlags |= PSP_HIDEHEADER;
1301                }
1302
1303        // Window message handlers
1304                LRESULT OnInitDialog(HWND, LPARAM) throw()
1305                {
1306                        CStatic(GetDlgItem(IDC_WIZARDCOMPLETION_ICON)).SetIcon(AtlLoadSysIcon(IDI_INFORMATION));
1307                        CStatic(GetDlgItem(IDC_WIZARDCOMPLETION_TITLE)).SetFont(m_Wizard.GetMessageTitleFont());
1308                        _W(m_OpenMinidumpFileDirectoryStatic.SubclassWindow(GetDlgItem(IDC_MAIN_OPERATION_OPENMINIDUMPFILEDIRECTORY)));
1309                        _W(m_OpenMinidumpFileDirectoryStatic.SetWindowPos(NULL, CRect(CPoint(0, 0), m_OpenMinidumpFileDirectoryStatic.GetIdealExtent()), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE));
1310                        return TRUE;
1311                }
1312                INT OnSetActive() throw()
1313                {
1314                        SetWizardButtons(PSWIZB_FINISH);
1315                        m_Wizard.GetDlgItem(IDCANCEL).EnableWindow(FALSE);
1316                        const HRESULT nResult = m_Wizard.m_OperationPropertyPage.GetResult();
1317                        if(FAILED(nResult))
1318                        {
1319                                CStatic(GetDlgItem(IDC_WIZARDCOMPLETION_ICON)).SetIcon(AtlLoadSysIcon(IDI_ERROR));
1320                                GetDlgItem(IDC_WIZARDCOMPLETION_RESULT).SetWindowText(AtlFormatString(_T("Error: %s (0x%08x)"), AtlFormatSystemMessage(nResult), nResult));
1321                        }
1322                        return 0;
1323                }
1324                LRESULT OnOpenMinidumpFileDirectoryStaticAnchorClicked(NMHDR* pHeader)
1325                {
1326                        return m_Wizard.m_OperationPropertyPage.OnOpenMinidumpFileDirectoryStaticAnchorClicked(pHeader);
1327                }
1328        };
1329
1330private:
1331        CFont m_LargerBoldFont;
1332        CIntroductionPropertyPage m_IntroductionPropertyPage;
1333        CProcessPropertyPage m_ProcessPropertyPage;
1334        CMinidumpTypePropertyPage m_MinidumpTypePropertyPage;
1335        COperationPropertyPage m_OperationPropertyPage;
1336        CCompletionPropertyPage m_CompletionPropertyPage;
1337
1338        const CFont& CreateLargerBoldFont()
1339        {
1340                CFontHandle BaseFont = AtlGetDefaultGuiFont();
1341                CLogFont LogFont;
1342                _W(BaseFont.GetLogFont(LogFont));
1343                LogFont.SetBold();
1344                LogFont.MakeLarger(2);
1345                m_LargerBoldFont = LogFont.CreateFontIndirect();
1346                return m_LargerBoldFont;
1347        }
1348
1349public:
1350// CMainWizard
1351        static BOOL EnableTokenDebugPrivilege()
1352        {
1353                _ATLTRY
1354                {
1355                        CAccessToken Token;
1356                if(!Token.GetThreadToken(TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES))
1357                        {
1358                                const HRESULT nResult = AtlHresultFromLastError();
1359                                __D(nResult == HRESULT_FROM_WIN32(ERROR_NO_TOKEN), nResult);
1360                                __E(Token.GetProcessToken(TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES));
1361                        }
1362                        __E(Token.EnablePrivilege(SE_DEBUG_NAME));
1363                }
1364                _ATLCATCHALL()
1365                {
1366                        _Z_EXCEPTION();
1367                        return FALSE;
1368                }
1369                return TRUE;
1370        }
1371        CMainWizard() :
1372                CWizardPropertySheetT<CMainWizard>(),
1373                m_IntroductionPropertyPage(this),
1374                m_ProcessPropertyPage(this),
1375                m_MinidumpTypePropertyPage(this),
1376                m_OperationPropertyPage(this),
1377                m_CompletionPropertyPage(this)
1378        {
1379                SetCaption(AtlLoadString(IDS_MAINWIZARD_CAPTION));
1380                SetHeader(MAKEINTRESOURCE(IDB_WIZARDHEADER));
1381                SetWatermark(MAKEINTRESOURCE(IDB_WIZARDWATERMARK));
1382                CreateLargerBoldFont();
1383                AddPage(m_IntroductionPropertyPage);
1384                AddPage(m_ProcessPropertyPage);
1385                AddPage(m_MinidumpTypePropertyPage);
1386                AddPage(m_OperationPropertyPage);
1387                AddPage(m_CompletionPropertyPage);
1388        }
1389        const CFont& GetLargerBoldFont() const throw()
1390        {
1391                return m_LargerBoldFont;
1392        }
1393
1394// Window message handelrs
1395        LRESULT OnSysCommand(UINT nCommand, CPoint)
1396        {
1397                switch(nCommand)
1398                {
1399                case ID_APP_ABOUT:
1400                        {
1401                                CAboutDialog Dialog;
1402                                Dialog.DoModal(m_hWnd);
1403                        }
1404                        break;
1405                default:
1406                        SetMsgHandled(FALSE);
1407                }
1408                return 0;
1409        }
1410};
Note: See TracBrowser for help on using the repository browser.