source: trunk/DirectShowSpy/GraphBuilderCallbackPropertySheet.h @ 193

Last change on this file since 193 was 193, checked in by roman, 9 years ago

Cosmetic, moved binaries, added graph list and clipboard copy property sheet

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