source: trunk/DirectShowSpy/GraphBuilderCallbackPropertySheet.h @ 937

Last change on this file since 937 was 831, checked in by roman, 4 years ago

Upgrade to VS2017; removed exception filter (hook); improved tracing

  • Property svn:keywords set to Id
File size: 51.8 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2015
3// Created by Roman Ryltsov roman@alax.info, http://alax.info
4//
5// This source code is published to complement DirectShowSpy developer powertoy
6// and demonstrate the internal use of APIs and tricks powering the tool. It is
7// allowed to freely re-use the portions of the code in other projects, commercial
8// or otherwise (provided that you don’t pretend that you wrote the original tool).
9//
10// Please keep in mind that DirectShowSpy is a developer tool, it is strongly recommended
11// that it is not shipped with release grade software. It is allowed to distribute
12// DirectShowSpy if only it is not registered with Windows by default and either
13// used privately, or registered on specific throubleshooting request. The advice applies
14// to hooking methods used by DirectShowSpy in general as well.
15
16#pragma once
17
18#include <atlctrlx.h>
19#include <atlsplit.h>
20#include "rofiles.h"
21#include "FilterGraphSpy.h"
22#include "AboutDialog.h"
23
24////////////////////////////////////////////////////////////
25// CGraphBuilderCallbackPropertySheet
26
27class CGraphBuilderCallbackPropertySheet :
28        public CSizablePropertySheetT<CGraphBuilderCallbackPropertySheet>
29{
30public:
31
32BEGIN_MSG_MAP_EX(CGraphBuilderCallbackPropertySheet)
33        CHAIN_MSG_MAP(CSizablePropertySheet)
34        MSG_WM_SYSCOMMAND(OnSysCommand)
35END_MSG_MAP()
36
37public:
38
39        ////////////////////////////////////////////////////////
40        // CGraphPropertyPage
41
42        class CGraphPropertyPage :
43                public CPropertyPageT<CGraphPropertyPage>,
44                public CDialogResize<CGraphPropertyPage>,
45                public CWindowWithPrivateMessagesT<CGraphPropertyPage>
46        {
47                typedef CThreadT<CGraphPropertyPage> CThread;
48
49        public:
50
51                enum { IDD = IDD_GRAPHBUILDERCALLBACK_GRAPH_PROPERTYPAGE };
52
53        BEGIN_MSG_MAP_EX(CGraphPropertyPage)
54                CHAIN_MSG_MAP(CPropertyPage)
55                CHAIN_MSG_MAP(CDialogResize<CGraphPropertyPage>)
56                CHAIN_MSG_MAP(CWindowWithPrivateMessages)
57                MSG_WM_INITDIALOG(OnInitDialog)
58                MSG_WM_DESTROY(OnDestroy)
59                MESSAGE_HANDLER_EX(WM_THREADPROGRESS, OnThreadProgress)
60                MESSAGE_HANDLER_EX(WM_THREADCOMPLETED, OnThreadCompleted)
61                MSG_LVN_GETDISPINFO(IDC_GRAPHBUILDERCALLBACK_GRAPH_GRAPH, OnGraphListViewGetDispInfo)
62                MSG_LVN_GETINFOTIP(IDC_GRAPHBUILDERCALLBACK_GRAPH_GRAPH, OnGraphListViewGetInfoTip)
63                MSG_LVN_ITEMCHANGED(IDC_GRAPHBUILDERCALLBACK_GRAPH_GRAPH, OnGraphListViewItemChanged)
64                MSG_LVN_GETDISPINFO(IDC_GRAPHBUILDERCALLBACK_GRAPH_LOG, OnLogListViewGetDispInfo)
65                MSG_LVN_GETINFOTIP(IDC_GRAPHBUILDERCALLBACK_GRAPH_LOG, OnLogListViewGetInfoTip)
66                NOTIFY_HANDLER_EX(IDC_GRAPHBUILDERCALLBACK_GRAPH_COPYTOCLIPBOARD, CRoHyperStatic::NC_ANCHORCLICKED, OnCopyToClipboardStaticAnchorClicked)
67                REFLECT_NOTIFICATIONS()
68        END_MSG_MAP()
69
70        BEGIN_DLGRESIZE_MAP(CGraphPropertyPage)
71                DLGRESIZE_CONTROL(IDC_GRAPHBUILDERCALLBACK_GRAPH_INTRODUCTION, DLSZ_SIZE_X)
72                DLGRESIZE_CONTROL(IDC_GRAPHBUILDERCALLBACK_GRAPH_SPLITTER, DLSZ_SIZE_X | DLSZ_SIZE_Y)
73                DLGRESIZE_CONTROL(IDC_GRAPHBUILDERCALLBACK_GRAPH_COPYTOCLIPBOARD, DLSZ_MOVE_Y)
74                //DLGRESIZE_CONTROL(IDC_GRAPHBUILDERCALLBACK_GRAPH_PROGRESS, ...
75        END_DLGRESIZE_MAP()
76
77        public:
78
79                ////////////////////////////////////////////////////
80                // Window message identifiers
81
82                enum 
83                {
84                        WM_FIRST = WM_APP,
85                        WM_THREADPROGRESS,
86                        WM_THREADCOMPLETED,
87                };
88
89                ////////////////////////////////////////////////////
90                // CLogData
91
92                class CLogData
93                {
94                public:
95
96                        ////////////////////////////////////////////////
97                        // TYPE
98
99                        typedef enum _TYPE
100                        {
101                                TYPE_SELECTEDFILTER,
102                                TYPE_CREATEDFILTER,
103                                TYPE_ADDFILTER,
104                                TYPE_REMOVEFILTER,
105                        } TYPE;
106
107                public:
108                        ULONGLONG m_nTime;
109                        TYPE m_Type;
110                        CStringA m_sMonikerDisplayName;
111                        SIZE_T m_nFilterPointer;
112                        CLSID m_FilterClassIdentifier;
113                        CStringA m_sFilterName;
114                        HRESULT m_nSiteResult;
115                        BOOL m_bSiteResultValid;
116
117                public:
118                // CLogData
119                        CLogData() throw() :
120                                m_nTime(0),
121                                m_bSiteResultValid(FALSE)
122                        {
123                        }
124                        CLogData(ULONGLONG nTime, const CStringA& sMonikerDisplayName) throw() :
125                                m_nTime(nTime),
126                                m_Type(TYPE_SELECTEDFILTER),
127                                m_sMonikerDisplayName(sMonikerDisplayName),
128                                m_FilterClassIdentifier(CLSID_NULL),
129                                m_bSiteResultValid(FALSE)
130                        {
131                        }
132                        CLogData(ULONGLONG nTime, TYPE Type, SIZE_T nFilterPointer, const CLSID& FilterClassIdentifier, const CStringA& sFilterName) throw() :
133                                m_nTime(nTime),
134                                m_Type(Type),
135                                m_nFilterPointer(nFilterPointer), 
136                                m_FilterClassIdentifier(FilterClassIdentifier), 
137                                m_sFilterName(sFilterName),
138                                m_bSiteResultValid(FALSE)
139                        {
140                                _A(Type == TYPE_CREATEDFILTER || Type == TYPE_ADDFILTER);
141                        }
142                        CLogData(ULONGLONG nTime, SIZE_T nFilterPointer) throw() :
143                                m_nTime(nTime),
144                                m_Type(TYPE_REMOVEFILTER),
145                                m_nFilterPointer(nFilterPointer),
146                                m_FilterClassIdentifier(CLSID_NULL),
147                                m_bSiteResultValid(FALSE)
148                        {
149                        }
150                        BOOL GetSiteResult(HRESULT& nResult) const throw()
151                        {
152                                if(!m_bSiteResultValid)
153                                        return FALSE;
154                                nResult = m_nSiteResult;
155                                return TRUE;
156                        }
157                        VOID SetSiteResult(HRESULT nResult) throw()
158                        {
159                                _A(!m_bSiteResultValid);
160                                m_nSiteResult = nResult;
161                                m_bSiteResultValid = TRUE;
162                        }
163                        CString GetFriendlyEventName() const
164                        {
165                                switch(m_Type)
166                                {
167                                case TYPE_SELECTEDFILTER:
168                                        _A(!m_sMonikerDisplayName.IsEmpty());
169                                        return _T("Selected Filter");
170                                case TYPE_CREATEDFILTER:
171                                        _A(m_nFilterPointer);
172                                        return _T("Created Filter");
173                                case TYPE_ADDFILTER:
174                                        _A(m_nFilterPointer);
175                                        return _T("Add Filter");
176                                case TYPE_REMOVEFILTER:
177                                        _A(m_nFilterPointer);
178                                        return _T("Remove Filter");
179                                }
180                                _A(FALSE);
181                                return _T("");
182                        }
183                        CComPtr<IPropertyBag> GetMonikerPropertyBag() const throw()
184                        {
185                                if(!m_sMonikerDisplayName.IsEmpty())
186                                        _ATLTRY
187                                        {
188                                                USES_CONVERSION;
189                                                CComPtr<IBindCtx> pBindCtx;
190                                                __C(CreateBindCtx(0, &pBindCtx));
191                                                ULONG nConsumedCount;
192                                                CComPtr<IMoniker> pMoniker;
193                                                const HRESULT nMkParseDisplayNameResult = MkParseDisplayName(pBindCtx, CA2W(m_sMonikerDisplayName), &nConsumedCount, &pMoniker);
194                                                if(SUCCEEDED(nMkParseDisplayNameResult))
195                                                {
196                                                        CComPtr<IPropertyBag> pPropertyBag;
197                                                        const HRESULT nBindToStorageResult = pMoniker->BindToStorage(pBindCtx, NULL, __uuidof(IPropertyBag), (VOID**) &pPropertyBag);
198                                                        if(SUCCEEDED(nBindToStorageResult))
199                                                        {
200                                                                _A(pPropertyBag);
201                                                                return pPropertyBag;
202                                                        } else
203                                                                _Z4(atlTraceGeneral, 4, _T("nBindToStorageResult 0x%08x\n"), nBindToStorageResult);
204                                                               
205                                                } else
206                                                        _Z4(atlTraceGeneral, 4, _T("nMkParseDisplayNameResult 0x%08x\n"), nMkParseDisplayNameResult);
207                                        }
208                                        _ATLCATCHALL()
209                                        {
210                                                _Z_EXCEPTION();
211                                        }
212                                return NULL;
213                        }
214                        CString GetFriendlyMonikerName() const
215                        {
216                                _ATLTRY
217                                {
218                                        const CComPtr<IPropertyBag> pPropertyBag = GetMonikerPropertyBag();
219                                        if(pPropertyBag)
220                                                return _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, L"FriendlyName");
221                                }
222                                _ATLCATCHALL()
223                                {
224                                        _Z_EXCEPTION();
225                                }
226                                return _T("");
227                        }
228                        CString GetFriendlyApplicationResult() const
229                        {
230                                if(m_bSiteResultValid)
231                                        return AtlFormatString(_T("0x%08x"), m_nSiteResult);
232                                return _T("");
233                        }
234                };
235
236                ////////////////////////////////////////////////////
237                // CLogDataList
238
239                class CLogDataList :
240                        public CRoListT<CLogData>
241                {
242                public:
243                // CLogDataList
244                };
245
246                ////////////////////////////////////////////////////
247                // CFilterData
248
249                class CFilterData
250                {
251                public:
252                        SIZE_T m_nPointer;
253                        CLSID m_ClassIdentifier;
254                        CStringA m_sName;
255
256                public:
257                // CFilterData
258                        CFilterData() throw()
259                        {
260                        }
261                        CFilterData(SIZE_T nPointer, const CLSID& ClassIdentifier, const CStringA& sName) throw() :
262                                m_nPointer(nPointer),
263                                m_ClassIdentifier(ClassIdentifier),
264                                m_sName(sName)
265                        {
266                        }
267                };
268
269                ////////////////////////////////////////////////////
270                // CFilterDataMap
271
272                class CFilterDataMap :
273                        public CRoMapT<SIZE_T, CFilterData>
274                {
275                };
276
277                ////////////////////////////////////////////////////
278                // CGraphData
279
280                class CGraphData
281                {
282                public:
283                        INT m_nProcessIdentifier;
284                        CStringA m_sProcessPath;
285                        ULONGLONG m_nTime;
286                        SIZE_T m_nPointer;
287                        SIZE_T m_nCallbackPointer;
288                        CLogDataList m_LogDataList;
289                        CFilterDataMap m_FilterDataMap;
290                        INT m_nImageIndex;
291
292                public:
293                // CGraphData
294                        //static BOOL ComparePointer(const CGraphData& GraphData, SIZE_T nPointer) throw()
295                        //{
296                        //      return GraphData.m_nPointer == nPointer;
297                        //}
298                        //static BOOL CompareCallbackPointer(const CGraphData& GraphData, SIZE_T nCallbackPointer) throw()
299                        //{
300                        //      return GraphData.m_nCallbackPointer == nCallbackPointer;
301                        //}
302                        CString GetProcessName() const
303                        {
304                                if(m_sProcessPath.IsEmpty())
305                                        return _T("");
306                                CPath sPath = CA2CT(m_sProcessPath);
307                                return (LPCTSTR) sPath + sPath.FindFileName();
308                        }
309                        CString GetProcessDirectory() const
310                        {
311                                if(m_sProcessPath.IsEmpty())
312                                        return _T("");
313                                CPath sPath = CA2CT(m_sProcessPath);
314                                _W(sPath.RemoveFileSpec());
315                                return (LPCTSTR) sPath;
316                        }
317                };
318
319                ////////////////////////////////////////////////////
320                // CGraphDataList
321
322                class CGraphDataList :
323                        public CRoListT<CGraphData>
324                {
325                public:
326                // CGraphDataList
327                        //BOOL FindFirstPointer(SIZE_T nPointer, POSITION* pPosition = NULL) const throw()
328                        //{
329                        //      return FindFirstThatT<SIZE_T>(&CGraphData::ComparePointer, nPointer, pPosition);
330                        //}
331                        BOOL FindFirstPointer(INT nProcessIdentifier, SIZE_T nPointer, POSITION* pPosition = NULL) const throw()
332                        {
333                                for(POSITION Position = GetHeadPosition(); Position; GetNext(Position))
334                                {
335                                        const CGraphData& GraphData = GetAt(Position);
336                                        if(GraphData.m_nProcessIdentifier == nProcessIdentifier && GraphData.m_nPointer == nPointer)
337                                        {
338                                                if(pPosition)
339                                                        *pPosition = Position;
340                                                return TRUE;
341                                        }
342                                }
343                                return FALSE;
344                        }
345                        BOOL FindFirstPointer(INT nProcessIdentifier, SIZE_T nPointer, CGraphData*& pGraphData) throw()
346                        {
347                                POSITION Position = NULL;
348                                if(!FindFirstPointer(nProcessIdentifier, nPointer, &Position))
349                                        return FALSE;
350                                _A(Position);
351                                pGraphData = &GetAt(Position);
352                                return TRUE;
353                        }
354                        BOOL FindLastPointer(INT nProcessIdentifier, SIZE_T nPointer, POSITION* pPosition = NULL) const throw()
355                        {
356                                for(POSITION Position = GetTailPosition(); Position; GetPrev(Position))
357                                {
358                                        const CGraphData& GraphData = GetAt(Position);
359                                        if(GraphData.m_nProcessIdentifier == nProcessIdentifier && GraphData.m_nPointer == nPointer)
360                                        {
361                                                if(pPosition)
362                                                        *pPosition = Position;
363                                                return TRUE;
364                                        }
365                                }
366                                return FALSE;
367                        }
368                        BOOL FindLastPointer(INT nProcessIdentifier, SIZE_T nPointer, CGraphData*& pGraphData) throw()
369                        {
370                                POSITION Position = NULL;
371                                if(!FindLastPointer(nProcessIdentifier, nPointer, &Position))
372                                        return FALSE;
373                                _A(Position);
374                                pGraphData = &GetAt(Position);
375                                return TRUE;
376                        }
377                        //BOOL FindFirstCallbackPointer(SIZE_T nCallbackPointer, POSITION* pPosition = NULL) const throw()
378                        //{
379                        //      return FindFirstThatT<SIZE_T>(&CGraphData::CompareCallbackPointer, nCallbackPointer, pPosition);
380                        //}
381                        BOOL FindFirstCallbackPointer(INT nProcessIdentifier, SIZE_T nCallbackPointer, POSITION* pPosition = NULL) const throw()
382                        {
383                                for(POSITION Position = GetHeadPosition(); Position; GetNext(Position))
384                                {
385                                        const CGraphData& GraphData = GetAt(Position);
386                                        if(GraphData.m_nProcessIdentifier == nProcessIdentifier && GraphData.m_nCallbackPointer == nCallbackPointer)
387                                        {
388                                                if(pPosition)
389                                                        *pPosition = Position;
390                                                return TRUE;
391                                        }
392                                }
393                                return FALSE;
394                        }
395                        BOOL FindFirstCallbackPointer(INT nProcessIdentifier, SIZE_T nCallbackPointer, CGraphData*& pGraphData) throw()
396                        {
397                                POSITION Position = NULL;
398                                if(!FindFirstCallbackPointer(nProcessIdentifier, nCallbackPointer, &Position))
399                                        return FALSE;
400                                _A(Position);
401                                pGraphData = &GetAt(Position);
402                                return TRUE;
403                        }
404                        BOOL FindLastCallbackPointer(INT nProcessIdentifier, SIZE_T nCallbackPointer, POSITION* pPosition = NULL) const throw()
405                        {
406                                for(POSITION Position = GetTailPosition(); Position; GetPrev(Position))
407                                {
408                                        const CGraphData& GraphData = GetAt(Position);
409                                        if(GraphData.m_nProcessIdentifier == nProcessIdentifier && GraphData.m_nCallbackPointer == nCallbackPointer)
410                                        {
411                                                if(pPosition)
412                                                        *pPosition = Position;
413                                                return TRUE;
414                                        }
415                                }
416                                return FALSE;
417                        }
418                        BOOL FindLastCallbackPointer(INT nProcessIdentifier, SIZE_T nCallbackPointer, CGraphData*& pGraphData) throw()
419                        {
420                                POSITION Position = NULL;
421                                if(!FindLastCallbackPointer(nProcessIdentifier, nCallbackPointer, &Position))
422                                        return FALSE;
423                                _A(Position);
424                                pGraphData = &GetAt(Position);
425                                return TRUE;
426                        }
427                };
428
429                //////////////////////////////////////////////////////////
430                // CClassData
431
432                class CClassData
433                {
434                public:
435                        CString m_sDescription;
436                        CPath m_sFilePath;
437                        LPCTSTR m_pszFileName;
438                        CPath m_sFileDirectory;
439                        TCHAR m_pszFileProductVersion[32];
440                        TCHAR m_pszFileVersion[32];
441                        ULONGLONG m_nFileSize;
442
443                public:
444                // CClassData
445                        CClassData() throw()
446                        {
447                                Initialize();
448                        }
449                        CClassData(const CLSID& ClassIdentifier)
450                        {
451                                Initialize(ClassIdentifier);
452                        }
453                        VOID Initialize() throw()
454                        {
455                                m_sDescription.Empty();
456                                m_sFilePath = NULL;
457                                m_pszFileName = NULL;
458                                m_sFileDirectory = NULL;
459                                m_pszFileProductVersion[0] = 0;
460                                m_pszFileVersion[0] = 0;
461                                m_nFileSize = 0;
462                        }
463                        VOID Initialize(const CLSID& ClassIdentifier)
464                        {
465                                Initialize();
466                                m_sDescription = _RegKeyHelper::QueryStringValue(HKEY_CLASSES_ROOT, AtlFormatString(_T("CLSID\\%ls"), _PersistHelper::StringFromIdentifier(ClassIdentifier)));
467                                m_sFilePath = (LPCTSTR) _RegKeyHelper::QueryStringValue(HKEY_CLASSES_ROOT, AtlFormatString(_T("CLSID\\%ls\\InprocServer32"), _PersistHelper::StringFromIdentifier(ClassIdentifier)));
468                                if(_tcslen(m_sFilePath))
469                                {
470                                        m_pszFileName = (LPCTSTR) m_sFilePath + m_sFilePath.FindFileName();
471                                        m_sFileDirectory = m_sFilePath;
472                                        _W(m_sFileDirectory.RemoveFileSpec());
473                                        // SUGG: File times
474                                        _VersionInfoHelper::GetVersionStrings(m_sFilePath, m_pszFileProductVersion, m_pszFileVersion);
475                                        CFindFiles FindFiles;
476                                        if(FindFiles.FindFirstFile(m_sFilePath))
477                                                m_nFileSize = ((ULONGLONG) FindFiles.GetFindData().nFileSizeHigh << 32) + FindFiles.GetFindData().nFileSizeLow;
478                                }
479                        }
480                };
481
482        private:
483                CGraphBuilderCallbackPropertySheet& m_PropertySheet;
484                CRoHyperStatic m_IntroductionStatic;
485                CRoListViewT<CGraphData*, CRoListControlDataTraitsT> m_GraphListView;
486                CRoListViewT<CLogData*, CRoListControlDataTraitsT> m_LogListView;
487                CHorSplitterWindow m_Splitter;
488                CRoHyperStatic m_CopyToClipboardStatic;
489                CProgressBarCtrl m_ProgressBar;
490                CAtlMap<INT, BOOL> m_ChangeMap;
491                CObjectPtr<CThread> m_pThread;
492                BOOL m_bThreadCompleted;
493                mutable CRoCriticalSection m_DataCriticalSection;
494                CGraphDataList m_GraphDataList;
495
496                VOID UpdateControls()
497                {
498                        m_LogListView.EnableWindow(m_GraphListView.GetSelectedCount() == 1);
499                }
500                static SIZE_T StringToPointer(const CHAR* pszString)
501                {
502                        INT nValue;
503                        __D(StrToIntExA(pszString, STIF_SUPPORT_HEX, &nValue), E_UNNAMED);
504                        return (SIZE_T) nValue;
505                }
506                static HRESULT StringToResult(const CHAR* pszString)
507                {
508                        return (HRESULT) StringToPointer(pszString);
509                }
510                DWORD ThreadProc(CThread*, CEvent& InitializationEvent, CEvent& TerminationEvent)
511                {
512                        CMultiThreadedApartment MultiThreadedApartment;
513                        const CPath sPath = m_PropertySheet.m_sPath;
514                        _W(InitializationEvent.Set());
515                        CRoMapT<INT, CStringA> ProcessPathMap;
516                        CGraphDataList GraphDataList;
517                        _ATLTRY
518                        {
519                                CAtlFile File;
520                                __C(File.Create(sPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING));
521                                ULONGLONG nFileSize;
522                                __C(File.GetSize(nFileSize));
523                                __C(File.LockRange(0, nFileSize));
524                                _ATLTRY
525                                {
526                                        CHeapPtr<CHAR> pszData;
527                                        static const SIZE_T g_nDataCapacity = 4 << 20; // 4 MB
528                                        __D(pszData.Reallocate(g_nDataCapacity), E_OUTOFMEMORY);
529                                        SIZE_T nDataSize = 0, nDataPosition = 0;
530                                        BOOL bDataReadComplete = FALSE;
531                                        HRESULT nResult = S_OK;
532                                        for(UINT nLineIndex = 0; ; nLineIndex++)
533                                        {
534                                                #pragma region Termination Check
535                                                if(nLineIndex % (4 << 10) == 0)
536                                                {
537                                                        const DWORD nWaitResult = WaitForSingleObject(TerminationEvent, 0);
538                                                        _Z5(atlTraceSync, 5, _T("nWaitResult 0x%x\n"), nWaitResult);
539                                                        _A(nWaitResult == WAIT_OBJECT_0 || nWaitResult == WAIT_TIMEOUT);
540                                                        if(nWaitResult != WAIT_TIMEOUT)
541                                                        {
542                                                                nResult = S_FALSE;
543                                                                break;
544                                                        }
545                                                }
546                                                #pragma endregion
547                                                _A(nDataPosition <= nDataSize);
548                                                #pragma region Read Data
549                                                if(!bDataReadComplete && (nDataSize - nDataPosition) < g_nDataCapacity / 4)
550                                                {
551                                                        #pragma region Compact Data
552                                                        const SIZE_T nCarryOverDataSize = nDataSize - nDataPosition;
553                                                        if(nCarryOverDataSize)
554                                                                _W(!memmove_s(pszData, g_nDataCapacity, pszData + nDataPosition, nCarryOverDataSize));
555                                                        nDataSize -= nDataPosition;
556                                                        nDataPosition = 0;
557                                                        pszData[nDataSize] = 0;
558                                                        #pragma endregion
559                                                        #pragma region Progress
560                                                        ULONGLONG nFilePosition;
561                                                        __C(File.GetPosition(nFilePosition));
562                                                        _W(PostPrivateMessage(WM_THREADPROGRESS, (WPARAM) ((16 << 10) * nFilePosition / nFileSize)));
563                                                        #pragma endregion
564                                                        const SIZE_T nReadableDataSize = g_nDataCapacity - nDataSize - 1;
565                                                        DWORD nReadDataSize = 0;
566                                                        __C(File.Read(pszData + nDataSize, (DWORD) nReadableDataSize, nReadDataSize));
567                                                        _Z5(atlTraceGeneral, 5, _T("nDataSize %d, nReadableDataSize %d, nReadDataSize %d\n"), nDataSize, nReadableDataSize, nReadDataSize);
568                                                        bDataReadComplete = (SIZE_T) nReadDataSize < nReadableDataSize;
569                                                        nDataSize += nReadDataSize;
570                                                        _A(nDataSize < g_nDataCapacity);
571                                                        pszData[nDataSize] = 0;
572                                                }
573                                                #pragma endregion
574                                                LPSTR pszLineData = pszData + nDataPosition;
575                                                LPSTR pszSeparator = strchr(pszLineData, '\n');
576                                                // NOTE: Valid lines are terminated with \r\n, so we can skip incomplete line
577                                                if(!pszSeparator)
578                                                        break;
579                                                nDataPosition = (pszSeparator + 1) - pszData;
580                                                _A(nDataPosition <= nDataSize);
581                                                pszSeparator[0] = 0;
582                                                if(pszSeparator[-1] == '\r')
583                                                        pszSeparator[-1] = 0;
584                                                #pragma region Process Line
585                                                _ATLTRY
586                                                {
587                                                        #pragma region Parse Data
588                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_LineExpression("^" 
589                                                                "{[0-9]+}" "\\-" // Year
590                                                                "{[0-9]+}" "\\-" // Month
591                                                                "{[0-9]+}" " " // Day
592                                                                "{[0-9]+}" "\\:" // Hour
593                                                                "{[0-9]+}" "\\:" // Minute
594                                                                "{[0-9]+}" "\t" // Second
595                                                                "{[0-9]+}" "\t" // Process Identifier
596                                                                "{[0-9]+}" "\t" // Thread Identifier
597                                                                "{.+}" // Payload
598                                                                "$", FALSE);
599                                                        CAtlREMatchContext<CAtlRECharTraitsA> MatchContext;
600                                                        __D(g_LineExpression.Match(pszLineData, &MatchContext), E_UNNAMED);
601                                                        INT pnValues[8];
602                                                        for(SIZE_T nIndex = 0; nIndex < DIM(pnValues); nIndex++)
603                                                                __D(AtlStringToInteger(_ReHelper::GetMatchString(MatchContext, (INT) nIndex), pnValues[nIndex]), E_UNNAMED);
604                                                        SYSTEMTIME Time;
605                                                        ZeroMemory(&Time, sizeof Time);
606                                                        Time.wYear = (WORD) pnValues[0];
607                                                        Time.wMonth = (WORD) pnValues[1];
608                                                        Time.wDay = (WORD) pnValues[2];
609                                                        Time.wHour = (WORD) pnValues[3];
610                                                        Time.wMinute = (WORD) pnValues[4];
611                                                        Time.wSecond = (WORD) pnValues[5];
612                                                        ULONGLONG nTime;
613                                                        _W(SystemTimeToFileTime(&Time, &reinterpret_cast<FILETIME&>(nTime)));
614                                                        const INT& nProcessIdentifier = pnValues[6];
615                                                        const INT& nThreadIdentifier = pnValues[7];
616                                                        _Y1(AtlFormatString(_T("nTime %s, nProcessIdentifier %d, nThreadIdentifier %d"), _StringHelper::FormatDateTime(nTime), nProcessIdentifier, nThreadIdentifier));
617                                                        LPCSTR pszPayloadLineData, pszPayloadLineDataSeparator;
618                                                        MatchContext.GetMatch(8, &pszPayloadLineData, &pszPayloadLineDataSeparator);
619                                                        _A(!*pszPayloadLineDataSeparator);
620                                                        #pragma endregion
621                                                        //CAtlREMatchContext<CAtlRECharTraitsA> MatchContext;
622                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionA("::CAmGraphBuilderCallback::Initialize: this {0x[0-9A-F]+}, pSpy {0x[0-9A-F]+}", FALSE);
623                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionB("::CAmGraphBuilderCallback::SelectedFilter: this {0x[0-9A-F]+}, pMoniker {.+}", FALSE);
624                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionC("::CAmGraphBuilderCallback::SelectedFilter: this {0x[0-9A-F]+}, nSelectedFilterResult {0x[0-9A-F]+}", FALSE);
625                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionD("::CAmGraphBuilderCallback::CreatedFilter: this {0x[0-9A-F]+}, pBaseFilter {0x[0-9A-F]+} {\\{[^\\}]+\\}} \\\"{[^\\\"]*}\\\"", FALSE);
626                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionE("::CAmGraphBuilderCallback::CreatedFilter: this {0x[0-9A-F]+}, nCreatedFilterResult {0x[0-9A-F]+}", FALSE);
627                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionF("::AddFilter: this {0x[0-9A-F]+}, pBaseFilter {0x[0-9A-F]+} {\\{[^\\}]+\\}}, pszName \\\"{[^\\\"]*}\\\"", FALSE);
628                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionG("::AddFilter: this {0x[0-9A-F]+}, sName \\\"{[^\\\"]*}\\\"", FALSE);
629                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionH("::RemoveFilter: this {0x[0-9A-F]+}, pBaseFilter {0x[0-9A-F]+}", FALSE);
630                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionI("::RemoveFilter: this {0x[0-9A-F]+}, sName \\\"{[^\\\"]*}\\\"", FALSE);
631                                                        static CAtlStaticRegExp<CAtlRECharTraitsA> g_ExpressionJ("version is [0-9\\.\\,]+, running in \\\"{[^\\\"]+}\\\" at ", FALSE);
632                                                        // TODO: Connect
633                                                        if(g_ExpressionA.Match(pszPayloadLineData, &MatchContext))
634                                                        {
635                                                                #pragma region Status Callback Initialization
636                                                                const SIZE_T nCallbackPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
637                                                                const SIZE_T nPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 1));
638                                                                _Z5(atlTraceGeneral, 5, _T("nCallbackPointer 0x%p, nPointer 0x%p\n"), nCallbackPointer, nPointer);
639                                                                const POSITION Position = GraphDataList.AddTail();
640                                                                CGraphData& GraphData = GraphDataList.GetAt(Position);
641                                                                GraphData.m_nProcessIdentifier = nProcessIdentifier;
642                                                                #pragma region Process Path
643                                                                {
644                                                                        _A(GraphData.m_sProcessPath.IsEmpty());
645                                                                        const POSITION Position = ProcessPathMap.Lookup(nProcessIdentifier);
646                                                                        if(Position)
647                                                                                GraphData.m_sProcessPath = CA2CT(ProcessPathMap.GetValueAt(Position));
648                                                                }
649                                                                #pragma endregion
650                                                                GraphData.m_nTime = nTime;
651                                                                GraphData.m_nPointer = nPointer;
652                                                                GraphData.m_nCallbackPointer = nCallbackPointer;
653                                                                #pragma endregion
654                                                        } else
655                                                        if(g_ExpressionB.Match(pszPayloadLineData, &MatchContext))
656                                                        {
657                                                                #pragma region IAMGraphBuilderCallback::SelectedFilter Call
658                                                                const SIZE_T nCallbackPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
659                                                                const CStringA sMonikerDisplayName = _ReHelper::GetMatchString(MatchContext, 1);
660                                                                _Z5(atlTraceGeneral, 5, _T("nCallbackPointer 0x%p, sMonikerDisplayName \"%hs\"\n"), nCallbackPointer, sMonikerDisplayName);
661                                                                CGraphData* pGraphData = NULL;
662                                                                if(GraphDataList.FindLastCallbackPointer(nProcessIdentifier, nCallbackPointer, pGraphData))
663                                                                {
664                                                                        _A(pGraphData);
665                                                                        _W(pGraphData->m_LogDataList.AddTail(CLogData(nTime, sMonikerDisplayName)));
666                                                                }
667                                                                #pragma endregion
668                                                        } else
669                                                        if(g_ExpressionC.Match(pszPayloadLineData, &MatchContext))
670                                                        {
671                                                                #pragma region Site IAMGraphBuilderCallback::SelectedFilter Return
672                                                                const SIZE_T nCallbackPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
673                                                                const HRESULT nSelectedFilterResult = StringToResult(_ReHelper::GetMatchString(MatchContext, 1));
674                                                                _Z5(atlTraceGeneral, 5, _T("nCallbackPointer 0x%p, nSelectedFilterResult 0x%08x\n"), nCallbackPointer, nSelectedFilterResult);
675                                                                CGraphData* pGraphData = NULL;
676                                                                if(GraphDataList.FindLastCallbackPointer(nProcessIdentifier, nCallbackPointer, pGraphData))
677                                                                {
678                                                                        _A(pGraphData);
679                                                                        if(!pGraphData->m_LogDataList.IsEmpty())
680                                                                        {
681                                                                                // WARN: A bit unsafe, we could also check thread identifier match
682                                                                                pGraphData->m_LogDataList.GetTail().SetSiteResult(nSelectedFilterResult);
683                                                                        }
684                                                                }
685                                                                #pragma endregion
686                                                        } else
687                                                        if(g_ExpressionD.Match(pszPayloadLineData, &MatchContext))
688                                                        {
689                                                                #pragma region IAMGraphBuilderCallback::CreatedFilter Call
690                                                                const SIZE_T nCallbackPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
691                                                                const SIZE_T nFilterPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 1));
692                                                                const CLSID FilterClassIdentifier = _PersistHelper::ClassIdentifierFromString(CStringW(_ReHelper::GetMatchString(MatchContext, 2)));
693                                                                const CStringA sFilterName = _ReHelper::GetMatchString(MatchContext, 3);
694                                                                _Z5(atlTraceGeneral, 5, _T("nCallbackPointer 0x%p, nFilterPointer 0x%p, FilterClassIdentifier %ls, sFilterName \"%hs\"\n"), nCallbackPointer, nFilterPointer, _PersistHelper::StringFromIdentifier(FilterClassIdentifier), sFilterName);
695                                                                CGraphData* pGraphData = NULL;
696                                                                if(GraphDataList.FindLastCallbackPointer(nProcessIdentifier, nCallbackPointer, pGraphData))
697                                                                {
698                                                                        _A(pGraphData);
699                                                                        _W(pGraphData->m_LogDataList.AddTail(CLogData(nTime, CLogData::TYPE_CREATEDFILTER, nFilterPointer, FilterClassIdentifier, sFilterName)));
700                                                                }
701                                                                #pragma endregion
702                                                        } else
703                                                        if(g_ExpressionE.Match(pszPayloadLineData, &MatchContext))
704                                                        {
705                                                                #pragma region Site IAMGraphBuilderCallback::CreatedFilter Return
706                                                                const SIZE_T nCallbackPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
707                                                                const HRESULT nCreatedFilterResult = StringToResult(_ReHelper::GetMatchString(MatchContext, 1));
708                                                                _Z5(atlTraceGeneral, 5, _T("nCallbackPointer 0x%p, nCreatedFilterResult 0x%08x\n"), nCallbackPointer, nCreatedFilterResult);
709                                                                CGraphData* pGraphData = NULL;
710                                                                if(GraphDataList.FindLastCallbackPointer(nProcessIdentifier, nCallbackPointer, pGraphData))
711                                                                {
712                                                                        _A(pGraphData);
713                                                                        if(!pGraphData->m_LogDataList.IsEmpty())
714                                                                        {
715                                                                                // WARN: A bit unsafe, we could also check thread identifier match
716                                                                                pGraphData->m_LogDataList.GetTail().SetSiteResult(nCreatedFilterResult);
717                                                                        }
718                                                                }
719                                                                #pragma endregion
720                                                        } else
721                                                        if(g_ExpressionF.Match(pszPayloadLineData, &MatchContext))
722                                                        {
723                                                                #pragma region AddFilter
724                                                                const SIZE_T nPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
725                                                                const SIZE_T nFilterPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 1));
726                                                                const CLSID FilterClassIdentifier = _PersistHelper::ClassIdentifierFromString(CStringW(_ReHelper::GetMatchString(MatchContext, 2)));
727                                                                const CStringA sFilterName = _ReHelper::GetMatchString(MatchContext, 3);
728                                                                _Z5(atlTraceGeneral, 5, _T("nPointer 0x%p, nFilterPointer 0x%p, FilterClassIdentifier %ls, sFilterName \"%hs\"\n"), nPointer, nFilterPointer, _PersistHelper::StringFromIdentifier(FilterClassIdentifier), sFilterName);
729                                                                CGraphData* pGraphData = NULL;
730                                                                if(GraphDataList.FindLastPointer(nProcessIdentifier, nPointer, pGraphData))
731                                                                {
732                                                                        _A(pGraphData);
733                                                                        _W(pGraphData->m_FilterDataMap.SetAt(nFilterPointer, CFilterData(nFilterPointer, FilterClassIdentifier, sFilterName)));
734                                                                        _W(pGraphData->m_LogDataList.AddTail(CLogData(nTime, CLogData::TYPE_ADDFILTER, nFilterPointer, FilterClassIdentifier, sFilterName)));
735                                                                }
736                                                                #pragma endregion
737                                                        } else
738                                                        if(g_ExpressionG.Match(pszPayloadLineData, &MatchContext))
739                                                        {
740                                                                #pragma region AddFilter Name
741                                                                const SIZE_T nPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
742                                                                const CStringA sName = _ReHelper::GetMatchString(MatchContext, 1);
743                                                                _Z5(atlTraceGeneral, 5, _T("nPointer 0x%p, sName \"%hs\"\n"), nPointer, sName);
744                                                                CGraphData* pGraphData = NULL;
745                                                                if(GraphDataList.FindLastPointer(nProcessIdentifier, nPointer, pGraphData))
746                                                                {
747                                                                        _A(pGraphData);
748                                                                        if(!pGraphData->m_LogDataList.IsEmpty())
749                                                                        {
750                                                                                // WARN: A bit unsafe, we could also check thread identifier match
751                                                                                CLogData* pLogData = &pGraphData->m_LogDataList.GetTail();
752                                                                                if(pLogData->m_Type == CLogData::TYPE_ADDFILTER) // && pLogData->m_sFilterName.IsEmpty())
753                                                                                        pLogData->m_sFilterName = sName;
754                                                                        }
755                                                                }
756                                                                #pragma endregion
757                                                        } else
758                                                        if(g_ExpressionH.Match(pszPayloadLineData, &MatchContext))
759                                                        {
760                                                                #pragma region RemoveFilter
761                                                                const SIZE_T nPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
762                                                                const SIZE_T nFilterPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 1));
763                                                                _Z5(atlTraceGeneral, 5, _T("nPointer 0x%p, nFilterPointer 0x%p\n"), nPointer, nFilterPointer);
764                                                                CGraphData* pGraphData = NULL;
765                                                                if(GraphDataList.FindLastPointer(nProcessIdentifier, nPointer, pGraphData))
766                                                                {
767                                                                        _A(pGraphData);
768                                                                        _W(pGraphData->m_LogDataList.AddTail(CLogData(nTime, nFilterPointer)));
769                                                                }
770                                                                #pragma endregion
771                                                        } else
772                                                        if(g_ExpressionI.Match(pszPayloadLineData, &MatchContext))
773                                                        {
774                                                                #pragma region RemoveFilter Name
775                                                                const SIZE_T nPointer = StringToPointer(_ReHelper::GetMatchString(MatchContext, 0));
776                                                                const CStringA sName = _ReHelper::GetMatchString(MatchContext, 1);
777                                                                _Z5(atlTraceGeneral, 5, _T("nPointer 0x%p, sName \"%hs\"\n"), nPointer, sName);
778                                                                CGraphData* pGraphData = NULL;
779                                                                if(GraphDataList.FindLastPointer(nProcessIdentifier, nPointer, pGraphData))
780                                                                {
781                                                                        _A(pGraphData);
782                                                                        if(!pGraphData->m_LogDataList.IsEmpty())
783                                                                        {
784                                                                                // WARN: A bit unsafe, we could also check thread identifier match
785                                                                                CLogData* pLogData = &pGraphData->m_LogDataList.GetTail();
786                                                                                if(pLogData->m_Type == CLogData::TYPE_REMOVEFILTER && pLogData->m_sFilterName.IsEmpty())
787                                                                                        pLogData->m_sFilterName = sName;
788                                                                        }
789                                                                }
790                                                                #pragma endregion
791                                                        } else
792                                                        if(g_ExpressionJ.Match(pszPayloadLineData, &MatchContext))
793                                                        {
794                                                                #pragma region Library Initialization
795                                                                const CStringA sPath = _ReHelper::GetMatchString(MatchContext, 0);
796                                                                _Z5(atlTraceGeneral, 5, _T("sPath \"%hs\"\n"), sPath);
797                                                                ProcessPathMap[nProcessIdentifier] = sPath;
798                                                                #pragma endregion
799                                                        } else
800                                                                ;
801                                                        _Y2();
802                                                }
803                                                _ATLCATCHALL()
804                                                {
805                                                        _Z_EXCEPTION();
806                                                }
807                                                #pragma endregion
808                                        }
809                                        {
810                                                CRoCriticalSectionLock DataLock(m_DataCriticalSection);
811                                                SwapMemory(&m_GraphDataList, &GraphDataList);
812                                        }
813                                        PostPrivateMessage(WM_THREADCOMPLETED, (WPARAM) nResult);
814                                }
815                                _ATLCATCHALL()
816                                {
817                                        __C(File.UnlockRange(0, nFileSize));
818                                        _ATLRETHROW;
819                                }
820                                __C(File.UnlockRange(0, nFileSize));
821                        }
822                        _ATLCATCH(Exception)
823                        {
824                                PostPrivateMessage(WM_THREADCOMPLETED, (WPARAM) (HRESULT) Exception);
825                        }
826                        return 0;
827                }
828
829        public:
830        // CGraphPropertyPage
831                CGraphPropertyPage(CGraphBuilderCallbackPropertySheet* pPropertySheet) throw() :
832                        m_PropertySheet(*pPropertySheet)
833                {
834                }
835
836        // CDialogResize                               
837                VOID DlgResize_UpdateLayout(INT nWidth, INT nHeight)
838                {
839                        __super::DlgResize_UpdateLayout(nWidth, nHeight);
840                        CRect SplitterPosition, ProgressPosition;
841                        _W(m_Splitter.GetWindowRect(SplitterPosition));
842                        _W(ScreenToClient(SplitterPosition));
843                        _W(m_ProgressBar.GetWindowRect(ProgressPosition));
844                        _W(ScreenToClient(ProgressPosition));
845                        const LONG nX = (SplitterPosition.Height() - ProgressPosition.Height()) / 2;
846                        ProgressPosition = SplitterPosition;
847                        ProgressPosition.DeflateRect(0, nX);
848                        _W(m_ProgressBar.MoveWindow(ProgressPosition));
849                }
850                       
851        // Window message handlers
852                LRESULT OnInitDialog(HWND, LPARAM)
853                {
854                        _ATLTRY
855                        {
856                                _W(m_IntroductionStatic.SubclassWindow(GetDlgItem(IDC_GRAPHBUILDERCALLBACK_GRAPH_INTRODUCTION)));
857                                CSize IconSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
858                                #pragma region Log List View
859                                {
860                                        m_GraphListView.Initialize(GetDlgItem(IDC_GRAPHBUILDERCALLBACK_GRAPH_GRAPH));
861                                        CImageList ImageList;
862                                        _W(ImageList.Create(IconSize.cx, IconSize.cy, ILC_COLOR32 | ILC_MASK, 1, 1));
863                                        _W(!m_GraphListView.SetImageList(ImageList.Detach(), LVSIL_SMALL));
864                                }
865                                #pragma endregion
866                                #pragma region Log List View
867                                {
868                                        m_LogListView.Initialize(GetDlgItem(IDC_GRAPHBUILDERCALLBACK_GRAPH_LOG));
869                                        CImageList ImageList;
870                                        _W(ImageList.Create(IconSize.cx, IconSize.cy, ILC_COLOR32 | ILC_MASK, 1, 1));
871                                        _W(ImageList.AddIcon(AtlLoadIconImage(IDI_LISTVIEW_SUCCESS, LR_DEFAULTCOLOR, IconSize.cx, IconSize.cy)) == 0);
872                                        _W(ImageList.AddIcon(AtlLoadIconImage(IDI_LISTVIEW_FAILURE, LR_DEFAULTCOLOR, IconSize.cx, IconSize.cy)) == 1);
873                                        _W(ImageList.AddIcon(AtlLoadIconImage(IDI_GRAPHBUILDERCALLBACK_LISTVIEW_ADDFILTER, LR_DEFAULTCOLOR, IconSize.cx, IconSize.cy)) == 2);
874                                        _W(ImageList.AddIcon(AtlLoadIconImage(IDI_GRAPHBUILDERCALLBACK_LISTVIEW_REMOVEFILTER, LR_DEFAULTCOLOR, IconSize.cx, IconSize.cy)) == 3);
875                                        _W(ImageList.AddIcon(AtlLoadIconImage(IDI_GRAPHBUILDERCALLBACK_LISTVIEW_SELECTEDFILTER, LR_DEFAULTCOLOR, IconSize.cx, IconSize.cy)) == 4);
876                                        _W(ImageList.AddIcon(AtlLoadIconImage(IDI_GRAPHBUILDERCALLBACK_LISTVIEW_CREATEDFILTER, LR_DEFAULTCOLOR, IconSize.cx, IconSize.cy)) == 5);
877                                        _W(!m_LogListView.SetImageList(ImageList.Detach(), LVSIL_SMALL));
878                                        CToolTipCtrl ToolTip = m_LogListView.GetToolTips();
879                                        ToolTip.SetMaxTipWidth(GetSystemMetrics(SM_CXSCREEN) / 2);
880                                        ToolTip.SetDelayTime(TTDT_AUTOPOP, 30 * 1000); // 30 seconds
881                                }
882                                #pragma endregion
883                                #pragma region Splitter
884                                CRect GraphPosition, LogPosition, SplitterPosition;
885                                _W(m_GraphListView.GetWindowRect(GraphPosition));
886                                _W(ScreenToClient(GraphPosition));
887                                _W(m_LogListView.GetWindowRect(LogPosition));
888                                _W(ScreenToClient(LogPosition));
889                                _W(SplitterPosition.UnionRect(GraphPosition, LogPosition));
890                                _W(m_Splitter.Create(m_hWnd, SplitterPosition, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CONTROLPARENT, IDC_GRAPHBUILDERCALLBACK_GRAPH_SPLITTER));
891                                m_GraphListView.SetParent(m_Splitter);
892                                m_LogListView.SetParent(m_Splitter);
893                                m_Splitter.SetSplitterPanes(m_GraphListView, m_LogListView);
894                                m_Splitter.SetSplitterPos(GraphPosition.Height());
895                                m_Splitter.ShowWindow(SW_HIDE);
896                                #pragma endregion
897                                _W(m_CopyToClipboardStatic.SubclassWindow(GetDlgItem(IDC_GRAPHBUILDERCALLBACK_GRAPH_COPYTOCLIPBOARD)));
898                                CRoHyperStatic::ArrangeHorizontally(&m_CopyToClipboardStatic, NULL);
899                                m_ProgressBar = GetDlgItem(IDC_GRAPHBUILDERCALLBACK_GRAPH_PROGRESS);
900                                m_ProgressBar.SetRange(0, 16 << 10);
901                                m_ProgressBar.SetStep(256);
902                                m_ProgressBar.ShowWindow(SW_SHOW);
903                                DlgResize_Init(FALSE, FALSE);
904                                {
905                                        CRect Position;
906                                        _W(GetClientRect(Position));
907                                        DlgResize_UpdateLayout(Position.Width(), Position.Height());
908                                }
909                                m_bThreadCompleted = FALSE;
910                                m_ChangeMap.RemoveAll();
911                                UpdateControls();
912                                #pragma region Default Property Sheet Size
913                                CRect Position;
914                                _W(m_PropertySheet.GetWindowRect(Position));
915                                Position.InflateRect(6 * Position.Width() / 8, 5 * Position.Width() / 8);
916                                CSize ScreenExtent(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
917                                ScreenExtent.cx -= ScreenExtent.cx / 8;
918                                ScreenExtent.cy -= ScreenExtent.cy / 8;
919                                if(Position.Width() > ScreenExtent.cx)
920                                        Position.right = Position.left + ScreenExtent.cx;
921                                if(Position.Height() > ScreenExtent.cy)
922                                        Position.bottom = Position.top + ScreenExtent.cy;
923                                _W(m_PropertySheet.MoveWindow(Position));
924                                _W(m_PropertySheet.CenterWindow());
925                                #pragma endregion
926                        }
927                        _ATLCATCHALL()
928                        {
929                                for(CWindow Window = GetWindow(GW_CHILD); Window.IsWindow(); Window = Window.GetWindow(GW_HWNDNEXT))
930                                        Window.EnableWindow(FALSE);
931                                _ATLRETHROW;
932                        }
933                        return TRUE;
934                }
935                LRESULT OnDestroy()
936                {
937                        m_pThread = NULL;
938                        return 0;
939                }
940                INT OnSetActive() throw()
941                {
942                        _ATLTRY
943                        {
944                                if(!m_bThreadCompleted)
945                                {
946                                        _A(!m_pThread);
947                                        m_ProgressBar.SetPos(0);
948                                        CObjectPtr<CThread> pThread;
949                                        __E(pThread.Construct()->Initialize(this, &CGraphPropertyPage::ThreadProc));
950                                        m_pThread = pThread;
951                                }
952                        }
953                        _ATLCATCHALL()
954                        {
955                                _Z_EXCEPTION();
956                                return -1;
957                        }
958                        return 0;
959                }
960                LRESULT OnThreadProgress(UINT, WPARAM wParam, LPARAM)
961                {
962                        m_ProgressBar.SetPos((INT) wParam);
963                        return 0;
964                }
965                LRESULT OnThreadCompleted(UINT, WPARAM wParam, LPARAM)
966                {
967                        const HRESULT nResult = (HRESULT) wParam;
968                        _ATLTRY
969                        {
970                                __C(nResult);
971                                CWaitCursor WaitCursor;
972                                CWindowRedraw NoGraphListViewRedraw(m_GraphListView);
973                                m_GraphListView.DeleteAllItems();
974                                CImageList ImageList = m_GraphListView.GetImageList(LVSIL_SMALL);
975                                CRoMapT<CStringA, INT, CStringElementTraitsI<CStringA> > PathIconIndexMap;
976                                for(POSITION Position = m_GraphDataList.GetHeadPosition(); Position; m_GraphDataList.GetNext(Position))
977                                {
978                                        CGraphData* pGraphData = &m_GraphDataList.GetAt(Position);
979                                        // NOTE: Reverse order
980                                        const INT nItem = m_GraphListView.InsertItem(0, pGraphData);
981                                        _A(nItem >= 0);
982                                        #pragma region Retrieve File Icon
983                                        pGraphData->m_nImageIndex = -1;
984                                        if(!pGraphData->m_sProcessPath.IsEmpty())
985                                                _ATLTRY
986                                                { 
987                                                        if(!PathIconIndexMap.Lookup(pGraphData->m_sProcessPath, pGraphData->m_nImageIndex))
988                                                        {
989                                                                SHFILEINFO FileInformation;
990                                                                ZeroMemory(&FileInformation, sizeof FileInformation);
991                                                                if(SHGetFileInfo(CA2CT(pGraphData->m_sProcessPath), 0, &FileInformation, sizeof FileInformation, SHGFI_ICON | SHGFI_SMALLICON))
992                                                                {
993                                                                        CIcon Icon;
994                                                                        Icon.Attach(FileInformation.hIcon);
995                                                                        pGraphData->m_nImageIndex = ImageList.AddIcon(Icon);
996                                                                        _A(pGraphData->m_nImageIndex >= 0);
997                                                                        PathIconIndexMap[pGraphData->m_sProcessPath] = pGraphData->m_nImageIndex;
998                                                                }
999                                                        }
1000                                                }
1001                                                _ATLCATCHALL()
1002                                                {
1003                                                        _Z_EXCEPTION();
1004                                                        _A(pGraphData->m_nImageIndex == -1);
1005                                                }
1006                                        #pragma endregion
1007                                }
1008                                UpdateControls();
1009                                m_ProgressBar.ShowWindow(SW_HIDE);
1010                                m_Splitter.ShowWindow(SW_SHOW);
1011                                m_GraphListView.SetFocus();
1012                        }
1013                        _ATLCATCH(Exception)
1014                        {
1015                                _Z_ATLEXCEPTION(Exception);
1016                                AtlExceptionMessageBox(m_hWnd, Exception);
1017                        }
1018                        m_bThreadCompleted = TRUE;
1019                        m_pThread = NULL;
1020                        return 0;
1021                }
1022                //LRESULT OnChanged(UINT, INT nIdentifier, HWND)
1023                //{
1024                //      m_ChangeMap[nIdentifier] = TRUE;
1025                //      SetModified();
1026                //      UpdateControls();
1027                //      return 0;
1028                //}
1029                LRESULT OnGraphListViewGetDispInfo(NMLVDISPINFO* pHeader)
1030                {
1031                        const CGraphData* pGraphData = m_GraphListView.DataFromParameter(pHeader->item.lParam);
1032                        if(pHeader->item.mask & LVIF_TEXT)
1033                        {
1034                                CString& sTextBuffer = m_GraphListView.GetTextBufferString(TRUE);
1035                                switch(pHeader->item.iSubItem)
1036                                {
1037                                case 1: // Process
1038                                        sTextBuffer = AtlFormatString(_T("%d"), pGraphData->m_nProcessIdentifier);
1039                                        break;
1040                                case 2: // Name
1041                                        sTextBuffer = pGraphData->GetProcessName();
1042                                        break;
1043                                case 3: // Directory
1044                                        sTextBuffer = pGraphData->GetProcessDirectory();
1045                                        break;
1046                                default: // Time
1047                                        sTextBuffer = _StringHelper::FormatDateTime(pGraphData->m_nTime);
1048                                }
1049                                pHeader->item.pszText = m_GraphListView.GetTextBuffer();
1050                        }
1051                        if(pHeader->item.mask & LVIF_IMAGE)
1052                                pHeader->item.iImage = pGraphData->m_nImageIndex;
1053                        return 0;
1054                }
1055                LRESULT OnGraphListViewGetInfoTip(NMLVGETINFOTIP* pHeader)
1056                {
1057                        const CGraphData* pGraphData = m_GraphListView.GetItemData(pHeader->iItem);
1058                        CString& sTextBuffer = m_GraphListView.GetTextBufferString(TRUE);
1059                        sTextBuffer.AppendFormat(_T("Time: %s\r\n"), _StringHelper::FormatDateTime(pGraphData->m_nTime));
1060                        sTextBuffer.AppendFormat(_T("Process: %d\r\n"), pGraphData->m_nProcessIdentifier);
1061                        if(!pGraphData->m_sProcessPath.IsEmpty())
1062                        {
1063                                sTextBuffer.AppendFormat(_T("Process Name: %s\r\n"), pGraphData->GetProcessName());
1064                                sTextBuffer.AppendFormat(_T("Process Directory: %s\r\n"), pGraphData->GetProcessDirectory());
1065                        }
1066                        sTextBuffer.TrimRight(_T("\t\n\r ."));
1067                        #pragma region Clipboard Copy
1068                        if(GetKeyState(VK_CONTROL) < 0 && GetKeyState(VK_SHIFT) < 0)
1069                                _ATLTRY
1070                                {
1071                                        SetClipboardText(m_hWnd, sTextBuffer);
1072                                        MessageBeep(MB_OK);
1073                                }
1074                                _ATLCATCHALL()
1075                                {
1076                                        _Z_EXCEPTION();
1077                                        MessageBeep(MB_ICONERROR);
1078                                }
1079                        #pragma endregion
1080                        _tcsncpy_s(pHeader->pszText, pHeader->cchTextMax, m_GraphListView.GetTextBuffer(), _TRUNCATE);
1081                        return 0;
1082                }
1083                LRESULT OnGraphListViewItemChanged(NMLISTVIEW* pHeader)
1084                {
1085                        UpdateControls();
1086                        if(pHeader->iItem >= 0 && ((pHeader->uOldState ^ pHeader->uNewState) & LVIS_SELECTED) && m_GraphListView.GetSelectedCount() == 1)
1087                        {
1088                                CWindowRedraw NoLogListViewRedraw(m_LogListView);
1089                                m_LogListView.DeleteAllItems();
1090                                CGraphData* pGraphData = m_GraphListView.GetItemData(m_GraphListView.GetNextItem(-1, LVNI_SELECTED));
1091                                CLogDataList& LogDataList = pGraphData->m_LogDataList;
1092                                for(POSITION Position = LogDataList.GetHeadPosition(); Position; LogDataList.GetNext(Position))
1093                                {
1094                                        CLogData* pLogData = &LogDataList.GetAt(Position);
1095                                        const INT nItem = m_LogListView.InsertItem(m_LogListView.GetItemCount(), pLogData);
1096                                        _A(nItem >= 0);
1097                                }
1098                        }
1099                        return 0;
1100                }
1101                LRESULT OnLogListViewGetDispInfo(NMLVDISPINFO* pHeader)
1102                {
1103                        const CLogData* pLogData = m_LogListView.DataFromParameter(pHeader->item.lParam);
1104                        if(pHeader->item.mask & LVIF_TEXT)
1105                        {
1106                                CString& sTextBuffer = m_LogListView.GetTextBufferString(TRUE);
1107                                switch(pHeader->item.iSubItem)
1108                                {
1109                                case 1: // Event
1110                                        sTextBuffer = pLogData->GetFriendlyEventName();
1111                                        break;
1112                                case 2: // Moniker Name
1113                                        sTextBuffer = pLogData->GetFriendlyMonikerName();
1114                                        break;
1115                                case 3: // Filter Name
1116                                        sTextBuffer = CA2CT(pLogData->m_sFilterName);
1117                                        break;
1118                                case 4: // Application Result
1119                                        sTextBuffer = pLogData->GetFriendlyApplicationResult();
1120                                        break;
1121                                default: // Time
1122                                        sTextBuffer = _StringHelper::FormatDateTime(pLogData->m_nTime);
1123                                }
1124                                pHeader->item.pszText = m_LogListView.GetTextBuffer();
1125                        }
1126                        if(pHeader->item.mask & LVIF_IMAGE)
1127                                switch(pLogData->m_Type)
1128                                {
1129                                case CLogData::TYPE_SELECTEDFILTER:
1130                                        pHeader->item.iImage = (!pLogData->m_bSiteResultValid || SUCCEEDED(pLogData->m_nSiteResult)) ? 4 : 1;
1131                                        break;
1132                                case CLogData::TYPE_CREATEDFILTER:
1133                                        pHeader->item.iImage = (!pLogData->m_bSiteResultValid || SUCCEEDED(pLogData->m_nSiteResult)) ? 5 : 1;
1134                                        break;
1135                                case CLogData::TYPE_ADDFILTER:
1136                                        pHeader->item.iImage = 2;
1137                                        break;
1138                                case CLogData::TYPE_REMOVEFILTER:
1139                                        pHeader->item.iImage = 3;
1140                                        break;
1141                                default:
1142                                        pHeader->item.iImage = -1;
1143                                }
1144                        return 0;
1145                }
1146                LRESULT OnLogListViewGetInfoTip(NMLVGETINFOTIP* pHeader)
1147                {
1148                        const CLogData* pLogData = m_LogListView.GetItemData(pHeader->iItem);
1149                        CString& sTextBuffer = m_LogListView.GetTextBufferString(TRUE);
1150                        //sTextBuffer.AppendFormat(_T("Time: %s\r\n"), _StringHelper::FormatDateTime(pLogData->m_nTime));
1151                        sTextBuffer.AppendFormat(_T("Event: %s\r\n"), pLogData->GetFriendlyEventName());
1152                        CLSID ClassIdentifier = CLSID_NULL;
1153                        if(!pLogData->m_sMonikerDisplayName.IsEmpty())
1154                        {
1155                                sTextBuffer.AppendFormat(_T("Moniker Display Name: %hs\r\n"), pLogData->m_sMonikerDisplayName);
1156                                const CComPtr<IPropertyBag> pPropertyBag = pLogData->GetMonikerPropertyBag();
1157                                if(pPropertyBag)
1158                                        _ATLTRY
1159                                        {
1160                                                sTextBuffer.AppendFormat(_T("Moniker Name: %ls\r\n"), _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, L"FriendlyName"));
1161                                                _PersistHelper::ClassIdentifierFromString(_FilterGraphHelper::ReadPropertyBagString(pPropertyBag, L"CLSID"), ClassIdentifier);
1162                                        }
1163                                        _ATLCATCHALL()
1164                                        {
1165                                                _Z_EXCEPTION();
1166                                        }
1167                        }
1168                        if(pLogData->m_FilterClassIdentifier != CLSID_NULL)
1169                                ClassIdentifier = pLogData->m_FilterClassIdentifier;
1170                        if(ClassIdentifier != CLSID_NULL)
1171                        {
1172                                sTextBuffer.AppendFormat(_T("Class Identifier: %ls\r\n"), _PersistHelper::StringFromIdentifier(ClassIdentifier));
1173                                _ATLTRY
1174                                {
1175                                        CClassData ClassData(ClassIdentifier);
1176                                        if(!ClassData.m_sDescription.IsEmpty())
1177                                                sTextBuffer.AppendFormat(_T("Class Description: %s\r\n"), ClassData.m_sDescription);
1178                                        if(_tcslen(ClassData.m_sFilePath))
1179                                        {
1180                                                sTextBuffer.AppendFormat(_T("File Name: %s\r\n"), ClassData.m_pszFileName);
1181                                                sTextBuffer.AppendFormat(_T("File Directory: %s\r\n"), ClassData.m_sFileDirectory);
1182                                                // SUGG: File times
1183                                                if(_tcslen(ClassData.m_pszFileVersion))
1184                                                        sTextBuffer.AppendFormat(_T("File Version: %s\r\n"), ClassData.m_pszFileVersion);
1185                                                if(_tcslen(ClassData.m_pszFileProductVersion))
1186                                                        sTextBuffer.AppendFormat(_T("File Product Version: %s\r\n"), ClassData.m_pszFileProductVersion);
1187                                                if(ClassData.m_nFileSize)
1188                                                        sTextBuffer.AppendFormat(_T("File Size: %s\r\n"), _StringHelper::FormatNumber((LONGLONG) ClassData.m_nFileSize));
1189                                        }
1190                                }
1191                                _ATLCATCHALL()
1192                                {
1193                                        _Z_EXCEPTION();
1194                                        MessageBeep(MB_ICONERROR);
1195                                }
1196                        }
1197                        if(!pLogData->m_sFilterName.IsEmpty())
1198                                sTextBuffer.AppendFormat(_T("Filter Name: %hs\r\n"), pLogData->m_sFilterName);
1199                        if(pLogData->m_bSiteResultValid)
1200                                sTextBuffer.AppendFormat(_T("Application Result: 0x%08x\r\n"), pLogData->m_nSiteResult);
1201                        sTextBuffer.TrimRight(_T("\t\n\r ."));
1202                        #pragma region Clipboard Copy
1203                        if(GetKeyState(VK_CONTROL) < 0 && GetKeyState(VK_SHIFT) < 0)
1204                                _ATLTRY
1205                                {
1206                                        SetClipboardText(m_hWnd, sTextBuffer);
1207                                        MessageBeep(MB_OK);
1208                                }
1209                                _ATLCATCHALL()
1210                                {
1211                                        _Z_EXCEPTION();
1212                                        MessageBeep(MB_ICONERROR);
1213                                }
1214                        #pragma endregion
1215                        _tcsncpy_s(pHeader->pszText, pHeader->cchTextMax, m_LogListView.GetTextBuffer(), _TRUNCATE);
1216                        return 0;
1217                }
1218                LRESULT OnCopyToClipboardStaticAnchorClicked(NMHDR*)
1219                {
1220                        CString sText;
1221                        for(POSITION Position = m_GraphDataList.GetTailPosition(); Position; m_GraphDataList.GetPrev(Position))
1222                        {
1223                                CGraphData* pGraphData = &m_GraphDataList.GetAt(Position);
1224                                #pragma region Graph
1225                                #pragma region Header
1226                                LPCTSTR g_ppszGraphHeaderItems[] = 
1227                                {
1228                                        _T("Time"),
1229                                        _T("Process Identifier"),
1230                                        _T("Process Name"),
1231                                        _T("Process Directory"),
1232                                };
1233                                sText += _StringHelper::Join(g_ppszGraphHeaderItems, _T("\t")) + _T("\r\n");
1234                                #pragma endregion
1235                                sText += _StringHelper::Join<CString>(4, _T("\t"), 
1236                                        _StringHelper::FormatDateTime(pGraphData->m_nTime),
1237                                        AtlFormatString(_T("%d"), pGraphData->m_nProcessIdentifier),
1238                                        pGraphData->GetProcessName(),
1239                                        pGraphData->GetProcessDirectory(),
1240                                        0) + _T("\r\n");
1241                                sText += _T("\r\n");
1242                                #pragma endregion
1243                                #pragma region Log
1244                                if(pGraphData->m_LogDataList.IsEmpty())
1245                                        continue;
1246                                #pragma region Header
1247                                LPCTSTR g_ppszLogHeaderItems[] = 
1248                                {
1249                                        _T("Time"),
1250                                        _T("Event"),
1251                                        _T("Moniker Display Name"),
1252                                        _T("Moniker Friendly Name"),
1253                                        _T("Moniker Class Identifier"),
1254                                        _T("Filter Class Identifier"),
1255                                        _T("Filter Name"),
1256                                        _T("Class Description"),
1257                                        _T("File Name"),
1258                                        _T("File Directory"),
1259                                        _T("File Version"),
1260                                        _T("File Product Version"),
1261                                        _T("File Size"),
1262                                        _T("Application Result"),
1263                                };
1264                                sText += _StringHelper::Join(g_ppszLogHeaderItems, _T("\t")) + _T("\r\n");
1265                                #pragma endregion
1266                                CLogDataList& LogDataList = pGraphData->m_LogDataList;
1267                                for(POSITION Position = LogDataList.GetHeadPosition(); Position; LogDataList.GetNext(Position))
1268                                {
1269                                        CLogData* pLogData = &LogDataList.GetAt(Position);
1270                                        CStringW sMonikerFriendlyName, sMonikerClassIdentifier;
1271                                        if(!pLogData->m_sMonikerDisplayName.IsEmpty())
1272                                        {
1273                                                const CComPtr<IPropertyBag> pPropertyBag = pLogData->GetMonikerPropertyBag();
1274                                                if(pPropertyBag)
1275                                                        _ATLTRY
1276                                                        {
1277                                                                sMonikerFriendlyName = _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, L"FriendlyName");
1278                                                                sMonikerClassIdentifier = _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, L"CLSID");
1279                                                        }
1280                                                        _ATLCATCHALL()
1281                                                        {
1282                                                                _Z_EXCEPTION();
1283                                                        }
1284                                        }
1285                                        CStringW sFilterClassIdentifier;
1286                                        if(pLogData->m_FilterClassIdentifier != CLSID_NULL)
1287                                                sFilterClassIdentifier = _PersistHelper::StringFromIdentifier(pLogData->m_FilterClassIdentifier);
1288                                        CClassData ClassData;
1289                                        _ATLTRY
1290                                        {
1291                                                const CLSID ClassIdentifier = (pLogData->m_FilterClassIdentifier != CLSID_NULL) ? pLogData->m_FilterClassIdentifier : !sMonikerClassIdentifier.IsEmpty() ? _PersistHelper::ClassIdentifierFromString(sMonikerClassIdentifier) : CLSID_NULL;
1292                                                if(ClassIdentifier != CLSID_NULL)
1293                                                        ClassData.Initialize(ClassIdentifier);
1294                                        }
1295                                        _ATLCATCHALL()
1296                                        {
1297                                                _Z_EXCEPTION();
1298                                        }
1299                                        CString sSiteResult;
1300                                        if(pLogData->m_bSiteResultValid)
1301                                                sSiteResult = AtlFormatString(_T("0x%08x"), pLogData->m_nSiteResult);
1302                                        sText += _StringHelper::Join<CString>(14, _T("\t"), 
1303                                                _StringHelper::FormatDateTime(pLogData->m_nTime),
1304                                                pLogData->GetFriendlyEventName(),
1305                                                (LPCTSTR) CA2CT(pLogData->m_sMonikerDisplayName),
1306                                                (LPCTSTR) CW2CT(sMonikerFriendlyName),
1307                                                (LPCTSTR) CW2CT(sMonikerClassIdentifier),
1308                                                (LPCTSTR) CW2CT(sFilterClassIdentifier),
1309                                                (LPCTSTR) CA2CT(pLogData->m_sFilterName),
1310                                                ClassData.m_sDescription,
1311                                                ClassData.m_pszFileName,
1312                                                ClassData.m_sFileDirectory,
1313                                                ClassData.m_pszFileVersion,
1314                                                ClassData.m_pszFileProductVersion,
1315                                                ClassData.m_nFileSize ? (LPCTSTR) _StringHelper::FormatNumber((LONGLONG) ClassData.m_nFileSize) : NULL,
1316                                                sSiteResult,
1317                                                0) + _T("\r\n");
1318                                }
1319                                #pragma endregion
1320                                sText += _T("\r\n");
1321                        }
1322                        SetClipboardText(m_hWnd, sText);
1323                        MessageBeep(MB_OK);
1324                        return 0;
1325                }
1326        };
1327
1328private:
1329        CPath m_sPath;
1330        CGraphPropertyPage m_GraphPropertyPage;
1331
1332public:
1333// CGraphBuilderCallbackPropertySheet
1334        CGraphBuilderCallbackPropertySheet() :
1335                CSizablePropertySheetT<CGraphBuilderCallbackPropertySheet>(IDS_GRAPHBUILDERCALLBACK_GRAPH_PROPERTYSHEETCAPTION),
1336                m_GraphPropertyPage(this)
1337        {
1338                if(!_tcslen(m_sPath))
1339                {
1340                        const CPath sDirectory = CDebugTraceBase::GetLocalMachineDirectory();
1341                        CDebugTraceData Data;
1342                        Data.Configure(sDirectory, _T(""), _T(""));
1343                        Data.CreateLogFilePath(sDirectory);
1344                        m_sPath = Data.m_pszFilePath;
1345                }
1346                #if _DEVELOPMENT && FALSE
1347                        static LPCTSTR g_pszPath = _T("D:\\Projects\\A&H\\LuxRiot\\_Issues\\45 Sanyo XP Issues\\DirectShowSpy.log");
1348                        m_sPath = g_pszPath;
1349                #endif // _DEVELOPMENT
1350                AddPage(m_GraphPropertyPage);
1351        }
1352        BOOL SetInitialPosition()
1353        {
1354                if(!__super::SetInitialPosition())
1355                        return FALSE;
1356                SetIcon(AtlLoadIconImage(IDI_MODULE, LR_DEFAULTCOLOR, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)), TRUE);
1357                SetIcon(AtlLoadIconImage(IDI_MODULE, LR_DEFAULTCOLOR, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)), FALSE);
1358                CAboutDialog::UpdateCaption(*this);
1359                #pragma region System Menu
1360                CMenuHandle Menu = GetSystemMenu(FALSE);
1361                _W(Menu.AppendMenu(MF_SEPARATOR));
1362                _W(Menu.AppendMenu(MF_STRING, ID_APP_ABOUT, _T("&About...")));
1363                #pragma endregion
1364                return TRUE;
1365        }
1366
1367// Window message handelrs
1368        LRESULT OnSysCommand(UINT nCommand, CPoint)
1369        {
1370                switch(nCommand)
1371                {
1372                case ID_APP_ABOUT:
1373                        {
1374                                CAboutDialog Dialog;
1375                                Dialog.DoModal(m_hWnd);
1376                        }
1377                        break;
1378                default:
1379                        SetMsgHandled(FALSE);
1380                }
1381                return 0;
1382        }
1383};
Note: See TracBrowser for help on using the repository browser.