source: trunk/DirectShowSpy/GraphBuilderCallbackPropertySheet.h @ 267

Last change on this file since 267 was 267, checked in by roman, 10 years ago

Updated source code/copyright notice

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