OSDN Git Service

[ 879536 ] Add MakePatchDirs source to repository
authorPerry Rapp <elsapo@users.sourceforge.net>
Sat, 31 Jan 2004 01:22:35 +0000 (01:22 +0000)
committerPerry Rapp <elsapo@users.sourceforge.net>
Sat, 31 Jan 2004 01:22:35 +0000 (01:22 +0000)
29 files changed:
Src/readme.txt
Tools/MakePatchDirs/AppVersion.cpp [new file with mode: 0755]
Tools/MakePatchDirs/AppVersion.h [new file with mode: 0755]
Tools/MakePatchDirs/CDirDialog.cpp [new file with mode: 0755]
Tools/MakePatchDirs/CDirDialog.h [new file with mode: 0755]
Tools/MakePatchDirs/CMoveConstraint.cpp [new file with mode: 0755]
Tools/MakePatchDirs/CMoveConstraint.h [new file with mode: 0755]
Tools/MakePatchDirs/CSubclass.cpp [new file with mode: 0755]
Tools/MakePatchDirs/CSubclass.h [new file with mode: 0755]
Tools/MakePatchDirs/ChangeLog.txt [new file with mode: 0755]
Tools/MakePatchDirs/DropEdit.cpp [new file with mode: 0755]
Tools/MakePatchDirs/DropEdit.h [new file with mode: 0755]
Tools/MakePatchDirs/MakeDirs.cpp [new file with mode: 0755]
Tools/MakePatchDirs/MakeDirs.h [new file with mode: 0755]
Tools/MakePatchDirs/MakePatchDirs.dsp [new file with mode: 0755]
Tools/MakePatchDirs/MakePatchDirs.ico [new file with mode: 0755]
Tools/MakePatchDirs/MakePatchDirs.rc [new file with mode: 0755]
Tools/MakePatchDirs/MakePatchDirs.rc2 [new file with mode: 0755]
Tools/MakePatchDirs/MakePatchDirsApp.cpp [new file with mode: 0755]
Tools/MakePatchDirs/MakePatchDirsApp.h [new file with mode: 0755]
Tools/MakePatchDirs/MakePatchDirsDlg.cpp [new file with mode: 0755]
Tools/MakePatchDirs/MakePatchDirsDlg.h [new file with mode: 0755]
Tools/MakePatchDirs/ReadMe.txt [new file with mode: 0755]
Tools/MakePatchDirs/StdAfx.cpp [new file with mode: 0755]
Tools/MakePatchDirs/StdAfx.h [new file with mode: 0755]
Tools/MakePatchDirs/dist.txt [new file with mode: 0755]
Tools/MakePatchDirs/exc.cpp [new file with mode: 0755]
Tools/MakePatchDirs/exc.h [new file with mode: 0755]
Tools/MakePatchDirs/resource.h [new file with mode: 0755]

index 77cea90..86a831b 100644 (file)
@@ -3,6 +3,14 @@
   ShellExtension: ShellExtension.dsp
  PATCH: [ 882650 ] Move temp build files out of Build into BuildTmp (more)
   ShellExtension: ShellExtension.dsp
+ [ 879536 ] Add MakePatchDirs source to repository
+  MakePatchDirs: AppVersion.cpp AppVersion.h CDirDialog.cpp CDirDialog.h
+   CMoveConstraint.cpp CMoveConstraint.h CSubclass.cpp CSubclass.h
+   ChangeLog.txt DropEdit.cpp DropEdit.h MakeDirs.cpp MakeDirs.h
+   MakePatchDirs.dsp MakePatchDirs.ico MakePatchDirs.rc MakePatchDirs.rc2
+   MakePatchDirsApp.cpp MakePatchDirsApp.h MakePatchDirsDlg.cpp 
+   MakePatchDirsDlg.h ReadMe.txt StdAfx.cpp StdAfx.h dist.txt exc.cpp
+   exc.h resource.h
 
 2004-01-30 WinMerge experimental release 2.1.5.8 (cvs)
 
diff --git a/Tools/MakePatchDirs/AppVersion.cpp b/Tools/MakePatchDirs/AppVersion.cpp
new file mode 100755 (executable)
index 0000000..793ab2a
--- /dev/null
@@ -0,0 +1,146 @@
+/*!
+  \file    AppVersion.cpp
+  \author  Perry Rapp, Smartronix, 2001
+  \date    Created: 2001/09/15 (Perry Rapp)
+  \date    Edited:  2001/12/12 PR
+
+  \brief   Implementation of simple version functions for an MS-Win app.
+
+  This was built by combining cfilever.*, JulianVersion.*, and VersionReport.*
+  on 2001/09/15 by Perry Rapp.
+
+  It requires a CString an a COleDateTime class.
+*/
+/* The MIT License
+Copyright (c) 2001 Perry Rapp
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "StdAfx.h"
+#include "AppVersion.h"
+#include <afxole.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+namespace appv {
+
+// -- from cfilever.cpp
+
+/*!
+  Extracts the fixed-info version information from the version resource in
+  the RC file for the current module. The four integers that make up the
+  fixed-info version information are formatted into a string and returned
+  to the caller.
+*/
+CString FixedModuleVersion(HMODULE hmod)
+{
+       if (!hmod)
+               hmod = ::GetModuleHandle(NULL);
+       TCHAR filepath[MAX_PATH];
+       GetModuleFileName(hmod, filepath, sizeof(filepath));
+       DWORD dwDummyHandle;
+       DWORD len = GetFileVersionInfoSize(filepath, &dwDummyHandle);
+       BYTE * buf = new BYTE[len];
+       ::GetFileVersionInfo(filepath, 0, len, buf);
+       unsigned int verlen;
+       LPVOID lpvi;
+       ::VerQueryValue(buf, _T("\\"), &lpvi, &verlen);
+       VS_FIXEDFILEINFO fileInfo;
+       fileInfo = *(VS_FIXEDFILEINFO*)lpvi;
+       CString sVer;
+       sVer.Format(_T("%d.%d.%d.%d")
+               , HIWORD(fileInfo.dwFileVersionMS)
+               , LOWORD(fileInfo.dwFileVersionMS)
+               , HIWORD(fileInfo.dwFileVersionLS)
+               , LOWORD(fileInfo.dwFileVersionLS));
+       delete buf;
+       return sVer;
+}
+
+/*!
+  This routine will extract the version string from the string version
+  resource in the RC file for the current module. You must add version.lib
+  to your project to link to the Win32 versioning API calls. The actual call
+  VerQueryValue() uses a value of 040904B0 for the language and character set.
+  This value is equivalent to English language text encoded using Unicode.
+ */ 
+CString StringModuleVersion()
+{
+       TCHAR filepath[MAX_PATH];
+       GetModuleFileName(::GetModuleHandle(NULL), filepath, MAX_PATH);
+       DWORD dwDummyHandle;
+       DWORD len = GetFileVersionInfoSize(filepath, &dwDummyHandle);
+       BYTE * buf = new BYTE[len];
+       ::GetFileVersionInfo(filepath, 0, len, buf);
+       char *version;
+       unsigned int verlen;
+       ::VerQueryValue(buf, _T("\\StringFileInfo\\040904B0\\FileVersion"),(void **)&version, &verlen);
+       CString sval = buf;
+       delete buf;
+       return sval;
+}
+
+// -- from JulianVersion.cpp
+
+bool ConvertDateToWord(const COleDateTime& date, int & word)
+{
+       int year = date.GetYear();
+       int day = date.GetDayOfYear(); // 1-based
+       word = (year-1990)*1000 + day;
+       return true;
+}
+
+bool ConvertDateStringToWord(const CString& sDate, int & word)
+{
+       COleDateTime date;
+       if (!date.ParseDateTime(sDate))
+               return false;
+       return ConvertDateToWord(date, word);
+}
+
+bool ConvertWordToDate(int word, COleDateTime & date)
+{
+       int year = word/1000;
+       int day = word - year*1000;
+       year += 1990;
+       if (year < 2000)
+               return false;
+       // stored using 1 based
+       if (day < 1 || day > 366)
+               return false;
+       date.SetDate(year, 1, 1);
+       date += COleDateTimeSpan(day-1, 0, 0, 0);
+       return true;
+}
+
+bool ConvertVersionStringToDate(const CString& sVersion, COleDateTime & date)
+{
+       int n1,n2,n3,n4;
+       int cvt = _stscanf(sVersion, _T("%d.%d.%d.%d"), &n1, &n2, &n3, &n4);
+       if (cvt != 4)
+               return false;
+       return ConvertWordToDate(n3, date);
+}
+
+// -- from VersionReport.cpp
+
+CString
+GetVersionReport()
+{
+       CString sVersion = FixedModuleVersion();
+       COleDateTime date;
+       if (ConvertVersionStringToDate(sVersion, date))
+               sVersion = sVersion + _T(" (") + date.Format() + _T(")");
+       else
+               sVersion = sVersion + _T(" (?)");
+       return sVersion;
+}
+
+} // namespace
diff --git a/Tools/MakePatchDirs/AppVersion.h b/Tools/MakePatchDirs/AppVersion.h
new file mode 100755 (executable)
index 0000000..e9babf1
--- /dev/null
@@ -0,0 +1,44 @@
+/*!
+  \file    AppVersion.h
+  \author  Perry Rapp, Smartronix, 2001
+  \date    Created: 2001/09/15 (Perry Rapp)
+  \date    Edited:  2001/12/12 PR
+
+  \brief   Declaration of simple version functions for an MS-Win app.
+
+  This was built by combining cfilever.*, JulianVersion.*, and VersionReport.*
+  on 2001/09/15 by Perry Rapp.
+
+  It requires a CString an a COleDateTime class.
+*/
+/* The MIT License
+Copyright (c) 2001 Perry Rapp
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef AppVersion_h
+#define AppVersion_h
+
+namespace appv {
+
+// -- from cfilever.h
+/// Get the version number from the fixed (language independent) portion of the version resource for the current module
+CString FixedModuleVersion(HMODULE hmod=NULL);
+/// Get the version string from the English portion of the version resource for the current module
+CString StringModuleVersion();
+
+// -- from JulianVersion.h
+bool ConvertDateToWord(const COleDateTime& date, int & word);
+bool ConvertDateStringToWord(const CString& sDate, int & word);
+bool ConvertWordToDate(int word, COleDateTime & date);
+bool ConvertVersionStringToDate(const CString& sVersion, COleDateTime & date);
+
+// -- from VersionReport.h
+CString GetVersionReport();
+
+} // namespace
+
+#endif // AppVersion_h
diff --git a/Tools/MakePatchDirs/CDirDialog.cpp b/Tools/MakePatchDirs/CDirDialog.cpp
new file mode 100755 (executable)
index 0000000..775204b
--- /dev/null
@@ -0,0 +1,180 @@
+/*!
+  \file    CDirDialog.cpp
+  \author  Perry Rapp, Smartronix, Creator, 1999-2001
+  \date    Created: 1999
+  \date    Edited:  2001/12/12 PR
+
+  \brief   Implementation of CDirDialog
+*/
+/* The MIT License
+Copyright (c) 2001 Perry Rapp
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "stdafx.h"
+#include "CDirDialog.h"
+#include "shlobj.h"
+
+#ifndef __ATLCONV_H__
+// for T2OLE
+#include <atlconv.h>
+#endif
+
+namespace prdlg {
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[]=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+// Callback function called by SHBrowseForFolder's browse control
+// after initialization and when selection changes
+int __stdcall CDirDialog::BrowseCtrlCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+       CDirDialog* pDirDialogObj = (CDirDialog*)lpData;
+       if (uMsg == BFFM_INITIALIZED )
+       {
+               if( ! pDirDialogObj->m_strSelDir.IsEmpty() )
+                       ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)(pDirDialogObj->m_strSelDir));
+               if( ! pDirDialogObj->m_strWindowTitle.IsEmpty() )
+                       ::SetWindowText(hwnd, (LPCTSTR) pDirDialogObj->m_strWindowTitle);
+       }
+       else if( uMsg == BFFM_SELCHANGED )
+       {
+               LPITEMIDLIST pidl = (LPITEMIDLIST) lParam;
+               TCHAR selection[MAX_PATH];
+               if( ! ::SHGetPathFromIDList(pidl, selection) )
+                       selection[0] = '\0';
+
+               CString csStatusText;
+               BOOL bOk = pDirDialogObj->SelChanged(selection, csStatusText);
+
+               if( pDirDialogObj->m_ulFlags & BIF_STATUSTEXT)
+                       ::SendMessage(hwnd, BFFM_SETSTATUSTEXT , 0, (LPARAM)(LPCTSTR)csStatusText);
+
+               ::SendMessage(hwnd, BFFM_ENABLEOK, 0, bOk);
+       }
+       return 0;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CDirDialog::CDirDialog()
+{
+       m_ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
+}
+
+CDirDialog::~CDirDialog()
+{
+}
+
+BOOL CDirDialog::DoBrowse(CWnd *pwndParent)
+{
+       HWND hwndParent = pwndParent == NULL ? NULL : pwndParent->GetSafeHwnd();
+       return DoBrowse(hwndParent);
+}
+
+BOOL CDirDialog::DoBrowse(HWND hwndParent)
+{
+
+       if( ! m_strSelDir.IsEmpty() )
+       {
+               m_strSelDir.TrimRight();
+               if( m_strSelDir.Right(1) == "\\" || m_strSelDir.Right(1) == "//" )
+                       m_strSelDir = m_strSelDir.Left(m_strSelDir.GetLength() - 1);
+       }
+
+       LPMALLOC pMalloc;
+       if (SHGetMalloc (&pMalloc)!= NOERROR)
+               return FALSE;
+
+       BROWSEINFO bInfo;
+       LPITEMIDLIST pidl;
+       ZeroMemory ( (PVOID) &bInfo,sizeof (BROWSEINFO));
+
+       if (!m_strInitDir.IsEmpty ())
+       {
+               OLECHAR       olePath[MAX_PATH];
+               ULONG         chEaten;
+               ULONG         dwAttributes;
+               HRESULT       hr;
+               LPSHELLFOLDER pDesktopFolder;
+               //
+               // Get a pointer to the Desktop's IShellFolder interface.
+               //
+               if (SUCCEEDED(SHGetDesktopFolder(&pDesktopFolder)))
+               {
+                       USES_CONVERSION;
+
+                       LPCWSTR wpath = T2COLE(m_strInitDir);
+                       wcsncpy(olePath, wpath, sizeof(olePath)/sizeof(olePath[0]));
+                       olePath[sizeof(olePath)/sizeof(olePath[0])-1]=0;
+                       //
+                       // IShellFolder::ParseDisplayName requires the file name be in Unicode.
+                       //
+//                     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, m_strInitDir.GetBuffer(MAX_PATH), -1,
+//                                         olePath, MAX_PATH);
+
+                       m_strInitDir.ReleaseBuffer (-1);
+                       //
+                       // Convert the path to an ITEMIDLIST.
+                       //
+                       hr = pDesktopFolder->ParseDisplayName(
+                               NULL
+                               ,NULL
+                               ,olePath
+                               ,&chEaten
+                               ,&pidl
+                               ,&dwAttributes
+                       );
+                       if (FAILED(hr))
+                       {
+                               pMalloc ->Free (pidl);
+                               pMalloc ->Release ();
+                               return FALSE;
+                       }
+                       bInfo.pidlRoot = pidl;
+
+               }
+       }
+       bInfo.hwndOwner = hwndParent;
+       bInfo.pszDisplayName = m_strPath.GetBuffer (MAX_PATH);
+       if (m_strTitle.IsEmpty())
+               bInfo.lpszTitle = _T("Open");
+       else
+               bInfo.lpszTitle = m_strTitle;
+       bInfo.ulFlags = m_ulFlags;
+
+
+       bInfo.lpfn = BrowseCtrlCallback;  // address of callback function
+       bInfo.lParam = (LPARAM)this;      // pass address of object to callback function
+
+       if ((pidl = ::SHBrowseForFolder(&bInfo)) == NULL)
+       {
+               return FALSE;
+       }
+       m_strPath.ReleaseBuffer();
+       m_iImageIndex = bInfo.iImage;
+
+       if (::SHGetPathFromIDList(pidl, m_strPath.GetBuffer(MAX_PATH)) == FALSE)
+       {
+               pMalloc ->Free(pidl);
+               pMalloc ->Release();
+               return FALSE;
+       }
+
+       m_strPath.ReleaseBuffer();
+
+       pMalloc ->Free(pidl);
+       pMalloc ->Release();
+
+       return TRUE;
+}
+
+} // namespace
diff --git a/Tools/MakePatchDirs/CDirDialog.h b/Tools/MakePatchDirs/CDirDialog.h
new file mode 100755 (executable)
index 0000000..5f21fbd
--- /dev/null
@@ -0,0 +1,56 @@
+/*!
+  \file    CDirDialog.h
+  \author  Perry Rapp, Smartronix, Creator, 1999-2001
+  \date    Created: 1999
+  \date    Edited:  2001/12/12 PR
+
+  \brief   Declaration of CDirDialog
+*/
+/* The MIT License
+Copyright (c) 2001 Perry Rapp
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#if !defined(AFX_DIRDIALOG_H__62FFAC92_1DEE_11D1_B87A_0060979CDF6D__INCLUDED_)
+#define AFX_DIRDIALOG_H__62FFAC92_1DEE_11D1_B87A_0060979CDF6D__INCLUDED_
+#pragma once
+
+namespace prdlg {
+
+//! directory browse dialog
+class CDirDialog
+{
+public:
+
+       CDirDialog();
+       virtual ~CDirDialog();
+
+       BOOL DoBrowse(HWND hwndParent = NULL);
+       BOOL DoBrowse(CWnd *pwndParent);
+
+       CString m_strWindowTitle;
+       CString m_strPath;
+       CString m_strInitDir;
+       CString m_strSelDir;
+       CString m_strTitle;
+       int  m_iImageIndex;
+       UINT m_ulFlags;
+
+private:
+
+       virtual BOOL SelChanged(LPCTSTR /*lpcsSelection*/, CString& /*csStatusText*/) { return TRUE; };
+       static int __stdcall CDirDialog::BrowseCtrlCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
+};
+
+// not in VC6 supplied headers, but in Aug2001 platform sdk headers
+#ifndef BIF_USENEWUI
+#define BIF_USENEWUI           (BIF_NEWDIALOGSTYLE | BIF_EDITBOX)
+#endif
+
+} // namespace
+
+#endif // !defined(AFX_DIRDIALOG_H__62FFAC92_1DEE_11D1_B87A_0060979CDF6D__INCLUDED_)
+
diff --git a/Tools/MakePatchDirs/CMoveConstraint.cpp b/Tools/MakePatchDirs/CMoveConstraint.cpp
new file mode 100755 (executable)
index 0000000..fb8df17
--- /dev/null
@@ -0,0 +1,755 @@
+/*!
+  \file    CMoveConstraint.cpp
+  \author  Perry Rapp, Smartronix, Creator, 1998-2001
+  \date    Created: 1998
+  \date    Edited:  2002/04/27 PR
+
+  \brief   Implementation of CMoveConstraint
+
+*/
+/* The MIT License
+Copyright (c) 2001 Perry Rapp
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "StdAfx.h"
+#include <afxtempl.h>       // MFC template collection classes
+#include <afxext.h> // needed for CFormView
+#include "CMoveConstraint.h"
+#ifndef NOSUBCLASS
+#include "CSubclass.h"
+#endif // NOSUBCLASS
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+
+
+namespace prdlg {
+
+// from windowsx.h
+#define GetWindowStyle(hwnd) ((DWORD)GetWindowLong(hwnd, GWL_STYLE))
+#define MapWindowRect(hwndFrom, hwndTo, lprc) \
+                    MapWindowPoints((hwndFrom), (hwndTo), (POINT *)(lprc), 2)
+
+// from wdj
+static RECT getGripRect(HWND hwnd)
+{
+       RECT rc;
+       GetClientRect(hwnd, &rc);
+       rc.left = rc.right - GetSystemMetrics(SM_CXVSCROLL);
+       rc.top = rc.bottom - GetSystemMetrics(SM_CYHSCROLL);
+       return rc;
+}
+
+
+CMoveConstraint::Constraint::Constraint()
+{
+       Init();
+}
+CMoveConstraint::Constraint::Constraint(double fLeftX, double fExpandX, double fAboveY, double fExpandY, HWND hwndChild, CWnd * pWnd)
+{
+       Init();
+       m_fLeftX = fLeftX;
+       m_fExpandX = fExpandX;
+       m_fAboveY = fAboveY;
+       m_fExpandY = fExpandY;
+       m_hwndChild = hwndChild;
+       m_pWnd = pWnd;
+}
+void 
+CMoveConstraint::Constraint::Init()
+{
+       m_fLeftX = 0;
+       m_fExpandX = 0;
+       m_fAboveY = 0;
+       m_fExpandY = 0;
+       m_hwndChild = 0;
+       m_pWnd = 0;
+       // m_rectChildOriginal
+       m_hwndParent = 0;
+}
+
+CMoveConstraint::CMoveConstraint()
+{
+       m_bSubclassed = false;
+       m_sKey = _T("UnnamedWindow");
+       ClearMostData();
+}
+
+
+bool
+CMoveConstraint::InitializeCurrentSize(HWND hwndDlg)
+{
+ASSERT(!m_hwndDlg);
+       if (!IsWindow(hwndDlg))
+               return false;
+       m_hwndDlg = hwndDlg;
+
+       GrabCurrentDimensionsAsOriginal(hwndDlg);
+       return true;
+}
+
+void
+CMoveConstraint::GrabCurrentDimensionsAsOriginal(HWND hwndDlg)
+{
+       // figure original size for resizing code
+       GetClientRect(hwndDlg, m_rectDlgOriginal);
+       CRect rect;
+       GetWindowRect(hwndDlg, &rect);
+
+       // (min/max code)
+       // remember original width & heighth in case a disallow function called
+       // by default, set minimum size to original size
+       m_nOrigX = m_nMinX = rect.Width();
+       m_nOrigY = m_nMinY = rect.Height();
+
+       m_bOriginalFetched = true;
+}
+
+void
+CMoveConstraint::InitializeSpecificSize(HWND /*hwndDlg*/, int nWidth, int nHeight)
+{
+       // figure original size for resizing code
+       m_rectDlgOriginal.left = 0;
+       m_rectDlgOriginal.right = nWidth;
+       m_rectDlgOriginal.top = 0;
+       m_rectDlgOriginal.bottom = nHeight;
+
+       // (min/max code)
+       // remember original width & heighth in case a disallow function called
+       // by default, set minimum size to original size
+       m_nOrigX = m_nMinX = nWidth;
+       m_nOrigY = m_nMinY = nHeight;
+}
+
+bool
+CMoveConstraint::InitializeOriginalSize(HWND hwndDlg)
+{
+       ASSERT(hwndDlg && !m_hwndDlg);
+       m_hwndDlg = hwndDlg;
+
+       return m_nOrigX != 0; // if 0, we didn't get WM_SIZE so we don't know the original size
+}
+
+bool
+CMoveConstraint::InitializeOriginalSize(CWnd * pParent)
+{
+       ASSERT(pParent);
+       return InitializeOriginalSize(pParent->m_hWnd);
+}
+
+
+void
+CMoveConstraint::InitializeSpecificSize(CWnd * pDlg, int nWidth, int nHeight)
+{
+       ASSERT(pDlg);
+       InitializeSpecificSize(pDlg->m_hWnd, nWidth, nHeight);
+}
+
+bool
+CMoveConstraint::InitializeCurrentSize(CWnd * pDlg)
+{
+       ASSERT(pDlg);
+       return InitializeCurrentSize(pDlg->m_hWnd);
+}
+
+void
+CMoveConstraint::UpdateSizes()
+{
+       Resize(m_hwndDlg, SIZE_RESTORED);
+}
+
+void
+CMoveConstraint::AllowHeightShrink()
+{
+       m_nMinY = 0;
+}
+void
+CMoveConstraint::AllowWidthShrink()
+{
+       m_nMinX = 0;
+}
+void
+CMoveConstraint::DisallowHeightGrowth()
+{
+       m_nMaxY = m_nOrigY;
+}
+void
+CMoveConstraint::DisallowWidthGrowth()
+{
+       m_nMaxX = m_nOrigX;
+}
+
+void
+CMoveConstraint::SetMaxSizePixels(int nWidth, int nHeight)
+{
+       if (nWidth != -1)
+               m_nMaxX = nWidth;
+       if (nHeight != -1)
+               m_nMaxY = nHeight;
+}
+
+void
+CMoveConstraint::SetMinSizePixels(int nWidth, int nHeight)
+{
+       if (nWidth != -1)
+               m_nMinX = nWidth;
+       if (nHeight != -1)
+               m_nMinY = nHeight;
+}
+
+void
+CMoveConstraint::SetMinSizePercent(double fWidth, double fHeight)
+{
+       if (fWidth >= 0)
+               m_nMinX = (int)(fWidth * m_nOrigX);
+       if (fHeight >= 0)
+               m_nMinY = (int)(fHeight * m_nOrigY);
+}
+
+void
+CMoveConstraint::SetScrollScale(CFormView * pFormView, double fShrinkWidth, double fShrinkHeight)
+{
+       m_fShrinkHeight = fShrinkHeight;
+       m_fShrinkWidth = fShrinkWidth;
+       m_pFormView = pFormView;
+       CSize size = pFormView->GetTotalSize();
+       m_nOrigScrollX = size.cx;
+       m_nOrigScrollY = size.cy;
+}
+
+CMoveConstraint::~CMoveConstraint()
+{
+       ClearMostData();
+}
+
+
+void
+CMoveConstraint::ClearMostData()
+{
+       // clears everything but m_bSubclassed
+       // this is called from constructor, OnDestroy, and destructor
+       // so it can't assume any numerical variables have sane values
+       m_hwndDlg=NULL;
+       // m_rectDlgOriginal
+       m_nOrigX=0;
+       m_nOrigY=0;
+       m_nGrip=SG_NORMAL;
+       m_bOriginalFetched=false;
+       m_nMinX=0;
+       m_nMinY=0;
+       m_nMaxX=0;
+       m_nMaxY=0;
+       m_nDelayed=0;
+       // this specifically does NOT touch m_bSubclassed, as a subclass may still be in use
+       m_pFormView=0;
+       m_nOrigScrollX=0;
+       m_nOrigScrollY=0;
+       m_fShrinkWidth=0;
+       m_fShrinkHeight=0;
+       m_bPropertyPage=false;
+       m_bPropertySheet=false;
+       m_ConstraintList.RemoveAll();
+       m_bPersistent=false;
+       m_bConstrainNonChildren = false;
+}
+
+void
+CMoveConstraint::
+InitializeChildConstraintData(HWND hwndDlg, Constraint & constraint)
+{
+       HWND hwndChild = constraint.m_hwndChild;
+       ASSERT(IsWindow(hwndChild));
+       constraint.m_hwndParent = GetParent(hwndChild);
+       if (!m_bConstrainNonChildren && constraint.m_hwndParent != hwndDlg)
+       {
+               // this is all predicated on the children being real Windows children
+               // because of the use of client coordinates in ::SetWindowPos down in Resize() below
+               // altho the truth is, the scaling is linear, so it will work with any windows
+               // but if you want to do that, you have to call 
+               //  m_constraint.ConstrainNonWindows();
+               // to suppress this debug ASSERT
+               ASSERT(0); // this is not a child of the dialog
+       }
+       GetWindowRect(hwndChild, constraint.m_rectChildOriginal);
+       CWnd * wndParent = CWnd::FromHandle(constraint.m_hwndParent);
+       wndParent->ScreenToClient(constraint.m_rectChildOriginal);
+}
+
+bool
+CMoveConstraint::
+Constrain(HWND hwndChild, double fLeftX, double fExpandX, double fAboveY, double fExpandY)
+{
+       return DoConstrain(0, hwndChild, fLeftX, fExpandX, fAboveY, fExpandY);
+}
+
+bool
+CMoveConstraint::
+DoConstrain(CWnd * pWnd, HWND hwndChild, double fLeftX, double fExpandX, double fAboveY, double fExpandY)
+{
+       Constraint constraint(fLeftX, fExpandX, fAboveY, fExpandY, hwndChild, pWnd);
+
+       if (m_hwndDlg && IsWindow(m_hwndDlg) && hwndChild && IsWindow(hwndChild))
+       {
+               InitializeChildConstraintData(m_hwndDlg, constraint);
+       }
+       else
+       {
+               if (!pWnd) // only CWnds can be deferred
+                       return false;
+               m_nDelayed++;
+       }
+
+       ConstraintList & constraintList = m_ConstraintList;
+       constraintList.AddTail(constraint);
+       return true;
+}
+
+
+void
+CMoveConstraint::
+Constrain(CWnd * pWnd, double fLeftX, double fExpandX, double fAboveY, double fExpandY)
+{
+       ASSERT(pWnd);
+       DoConstrain(pWnd, pWnd->m_hWnd, fLeftX, fExpandX, fAboveY, fExpandY);
+}
+
+bool
+CMoveConstraint::
+ConstrainItem(int nId, double fLeftX, double fExpandX, double fAboveY, double fExpandY)
+{
+       if (!m_hwndDlg || !IsWindow(m_hwndDlg))
+               return false;
+       HWND hwnd = GetDlgItem(m_hwndDlg, nId);
+       return DoConstrain(0, hwnd, fLeftX, fExpandX, fAboveY, fExpandY);
+}
+
+/**
+ * Chain to further CSubclass processing if appropriate
+ */
+UINT
+CMoveConstraint::CallOriginalProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+#ifndef NOSUBCLASS
+       if (m_bSubclassed)
+               return CallOldProc(ConstraintWndProc, hwnd, msg, wParam, lParam);
+#else
+       if (0)
+               ;
+#endif // NOSUBCLASS
+       else
+               return 0;
+}
+
+#ifndef NOSUBCLASS
+/**
+ * This is the window proc callback that works with the CSubclass module.
+ */
+LRESULT CALLBACK
+CMoveConstraint::ConstraintWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+       void * data = GetData(ConstraintWndProc, hwnd);
+       CMoveConstraint * constraint = reinterpret_cast<CMoveConstraint *>(data);
+
+       LRESULT lresult;
+       if (constraint->WindowProc(hwnd, msg, wParam, lParam, &lresult))
+               return lresult;
+
+       return constraint->CallOriginalProc(hwnd, msg, wParam, lParam);
+}
+bool
+CMoveConstraint::SubclassWnd()
+{
+       void * data = reinterpret_cast<void *>(this);
+       // this will return false if this window/wndproc combination has already
+       // been established (subclassed)
+       m_bSubclassed = Subclass(ConstraintWndProc, m_hwndDlg, data);
+       return m_bSubclassed;
+}
+bool
+CMoveConstraint::UnSubclassWnd()
+{
+       return UnSubclass(ConstraintWndProc, m_hwndDlg);
+}
+#endif
+
+/**
+ * Check if we have any pending constraints not yet added to constraint list
+ * because they were set before the dialog was created (so initial sizes 
+ * could not yet be captured).
+ */
+void
+CMoveConstraint::CheckDeferredChildren()
+{
+       if (!m_nDelayed)
+               return;
+       ConstraintList & constraintList = m_ConstraintList;
+       for (POSITION pos=constraintList.GetHeadPosition(); pos; constraintList.GetNext(pos))
+       {
+               Constraint & constraint = constraintList.GetAt(pos);
+               if (constraint.m_hwndChild)
+                       continue;
+               ASSERT(constraint.m_pWnd);
+               if (constraint.m_pWnd->m_hWnd)
+               {
+                       constraint.m_hwndChild = constraint.m_pWnd->m_hWnd;
+                       InitializeChildConstraintData(m_hwndDlg, constraint);
+                       m_nDelayed--;
+               }
+       }
+}
+
+/**
+ * Custom handling for WM_SIZE
+ * Apply all resize constraints from the constraint list.
+ */
+void
+CMoveConstraint::Resize(HWND hWnd, UINT nType)
+{
+// optional - could use BeginDeferWindowPos, DeferWindowPos, EndDeferWindowPos
+// 2000/10/07 - haven't tried them
+// but I don't think they'd matter because I use SWP_NOREDRAW in the loop
+
+       if (nType == SIZE_MINIMIZED) return;
+
+       if (!m_hwndDlg && hWnd && !m_bOriginalFetched)
+       {
+               // if early subclass or wndproc
+               // grab early dimensions, in case we want them later (eg, property sheet)
+               GrabCurrentDimensionsAsOriginal(hWnd);
+               return;
+       }
+
+       if (!m_hwndDlg || !IsWindow(m_hwndDlg))
+               return;
+
+       CRect rectParentCurrent;
+       GetClientRect(m_hwndDlg, rectParentCurrent);
+
+       // compute delta from original size (all fractions based on this)
+       int nDeltaWidth = (rectParentCurrent.right - m_rectDlgOriginal.right);
+       int nDeltaHeight = (rectParentCurrent.bottom - m_rectDlgOriginal.bottom);
+
+       ConstraintList & constraintList = m_ConstraintList;
+       for (POSITION pos=constraintList.GetHeadPosition(); pos; constraintList.GetNext(pos))
+       {
+               Constraint & constraint = constraintList.GetAt(pos);
+               if (!constraint.m_hwndChild)
+                       continue;
+
+               CRect rectChildCurrent;
+               // get the screen & client coordinates of the child
+               ::GetWindowRect(constraint.m_hwndChild, &rectChildCurrent);
+               CWnd * wndParent = CWnd::FromHandle(constraint.m_hwndParent);
+               wndParent->ScreenToClient(&rectChildCurrent);
+
+               int nDelta;
+
+               nDelta = nDeltaWidth;
+               rectChildCurrent.left = (int)(nDelta * constraint.m_fLeftX) + constraint.m_rectChildOriginal.left;
+               rectChildCurrent.right = (int)(nDelta * (constraint.m_fLeftX + constraint.m_fExpandX)) + constraint.m_rectChildOriginal.right;
+
+               nDelta = nDeltaHeight;
+               rectChildCurrent.top = (int)(nDelta * constraint.m_fAboveY) + constraint.m_rectChildOriginal.top;
+               rectChildCurrent.bottom = (int)(nDelta * (constraint.m_fAboveY + constraint.m_fExpandY)) + constraint.m_rectChildOriginal.bottom;
+
+               SetWindowPos(constraint.m_hwndChild, NULL, rectChildCurrent.left, rectChildCurrent.top
+                       , rectChildCurrent.Width(), rectChildCurrent.Height(), SWP_NOZORDER+SWP_NOREDRAW);
+       }
+
+       if (m_pFormView)
+       {
+               // ignore growth
+               if (nDeltaWidth > 0)
+                       nDeltaWidth = 0;
+               if (nDeltaHeight > 0)
+                       nDeltaHeight = 0;
+               CSize size;
+               size.cx = (int)(m_nOrigScrollX + nDeltaWidth * m_fShrinkWidth);
+               size.cy = (int)(m_nOrigScrollY + nDeltaHeight * m_fShrinkHeight);
+               m_pFormView->SetScrollSizes(MM_TEXT, size);
+       }
+
+       InvalidateRect(m_hwndDlg, NULL, TRUE);
+       UpdateWindow(m_hwndDlg);
+}
+
+/**
+ * Custom handling for WM_GETMINMAXINFO.
+ * Enforce any resizing limitations.
+ */
+void
+CMoveConstraint::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
+{
+       // views don't get WM_GETMINMAXINFO, but dialogs & frames do
+       if (!m_hwndDlg)
+               return;
+       if (m_nMinX)
+               lpMMI->ptMinTrackSize.x = m_nMinX;
+       if (m_nMinY)
+               lpMMI->ptMinTrackSize.y = m_nMinY;
+       if (m_nMaxX)
+               lpMMI->ptMaxTrackSize.x = m_nMaxX;
+       if (m_nMaxY)
+               lpMMI->ptMaxTrackSize.y = m_nMaxY;
+}
+
+/**
+ * Client is asking for window proc handling for a property page.
+ */
+bool
+CMoveConstraint::WindowProcPropertyPage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT * plresult)
+{
+       m_bPropertyPage = true;
+       return WindowProc(hWnd, message, wParam, lParam, plresult);
+}
+
+/**
+ * Client is asking for window proc handling for a property sheet.
+ */
+bool
+CMoveConstraint::WindowProcPropertySheet(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT * plresult)
+{
+       m_bPropertySheet = true;
+       return WindowProc(hWnd, message, wParam, lParam, plresult);
+}
+
+bool
+CMoveConstraint::PaintGrip()
+{
+       if (m_nGrip == SG_NONE) return false;
+       if (!m_hwndDlg) return false;
+       HWND hw = (m_nGrip == SG_PARENTSTATE) ? GetParent(m_hwndDlg) : m_hwndDlg;
+       return !IsZoomed(hw) && !IsIconic(hw);
+}
+
+/**
+ * Custom handling for WM_NCHITTEST
+ * We paint the sizing grip if the mouse is in the lower right hand corner.
+ */
+bool
+CMoveConstraint::OnNcHitTest(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT * plresult)
+{
+       // views don't get WM_NCHITTEST, but dialogs & frames do
+       if (!m_hwndDlg)
+               return false;
+       if (m_nMinY == m_nMaxY)
+       {
+               int nRet = CallOriginalProc(m_hwndDlg, msg, wParam, lParam);
+               switch(nRet)
+               {
+               case HTBOTTOMLEFT:
+               case HTTOPLEFT:
+                       *plresult = HTLEFT;
+                       return true;
+               case HTBOTTOMRIGHT:
+               case HTTOPRIGHT:
+                       *plresult = HTRIGHT;
+                       return true;
+               case HTBOTTOM:
+               case HTTOP:
+                       *plresult = HTBORDER;
+                       return true;
+               }
+               return false;
+       }
+       if (m_nMinX == m_nMaxX)
+       {
+               int nRet = CallOriginalProc(m_hwndDlg, msg, wParam, lParam);
+               switch(nRet)
+               {
+               case HTBOTTOMLEFT:
+               case HTBOTTOMRIGHT:
+                       *plresult = HTBOTTOM;
+                       return true;
+               case HTTOPLEFT:
+               case HTTOPRIGHT:
+                       *plresult = HTTOP;
+                       return true;
+               case HTLEFT:
+               case HTRIGHT:
+                       *plresult = HTBORDER;
+                       return true;
+               }
+               return false;
+       }
+       if (!PaintGrip())
+               return false;
+
+       // check for size grip
+       int x = (int)(short)LOWORD(lParam);
+       int y = (int)(short)HIWORD(lParam);
+       int cx,cy;
+       RECT rc = getGripRect(m_hwndDlg);
+       MapWindowRect(m_hwndDlg, HWND_DESKTOP, &rc);
+       RECT rc2;
+       GetWindowRect(m_hwndDlg, &rc2);
+       cx = x-rc.left;
+       cy = y-rc.top;
+       if (0 < cx && 0 < cy && (rc.right - rc.left < cy+cy))
+       {
+               *plresult = HTBOTTOMRIGHT;
+               return true;
+       }
+       return false;
+}
+
+void
+CMoveConstraint::OnDestroy()
+{
+       if (m_bPersistent)
+               Persist(true, true);
+       // the one variable that CANNOT safely be cleared now is m_bSubclassed
+       // because the subclass is almost certainly not yet removed
+       // (the subclass calls us to let us do destroy processing, before 
+       //  removing itself)
+       ClearMostData();
+}
+
+/**
+ * Custom handling of the TTN_NEEDTEXT notification message
+ */
+bool
+CMoveConstraint::OnTtnNeedText(TOOLTIPTEXT * pTTT, LRESULT * plresult)
+{
+       int id = pTTT->hdr.idFrom;
+       UINT uflags = pTTT->uFlags;
+       if (uflags & TTF_IDISHWND)
+               id = GetDlgCtrlID((HWND)id);
+       tip ti;
+       if (m_tips.Lookup(id, ti))
+       {
+               if (ti.m_nResourceId)
+               {
+                       pTTT->lpszText = MAKEINTRESOURCE(ti.m_nResourceId);
+                       pTTT->hinst = AfxGetResourceHandle();
+               }
+               else
+               {
+                       pTTT->lpszText = (LPTSTR)(LPCTSTR)ti.m_sText;
+               }
+               *plresult = TRUE; // return TRUE from original window proc
+               return true; // stop processing this message
+       }
+       return false;
+}
+
+/**
+ * Main window proc of this subclassing library
+ * Set plresult to set the return value of the real window proc which called us.
+ * Return true to prevent any further handling of this message.
+ */
+bool
+CMoveConstraint::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT * plresult)
+{
+       if (m_bPropertyPage)
+       {
+               // pass PSN_SETACTIVE to parent (property sheet)
+               if (m_hwndDlg && (WM_NOTIFY == msg) && (PSN_SETACTIVE == (((NMHDR *)lParam)->code)))
+               {
+                       HWND hwndParent = GetParent(m_hwndDlg);
+                       NMHDR nmhdr = { hwndParent, 0, PSN_SETACTIVE };
+                       SendMessage(hwndParent, WM_NOTIFY, 0, (LPARAM)&nmhdr);
+               }
+       }
+       if (m_bPropertySheet)
+       {
+               if ((WM_NOTIFY == msg) && (PSN_SETACTIVE == (((NMHDR *)lParam)->code)))
+               {
+                       CheckDeferredChildren();
+               }
+       }
+       if (WM_GETMINMAXINFO == msg) {
+               OnGetMinMaxInfo(reinterpret_cast<LPMINMAXINFO>(lParam));
+       } else if (WM_SIZE == msg) { // 2000/03/10 - tried WM_EXITSIZEMOVE - no help for property page problem
+               Resize(hWnd, (UINT)wParam /* x & y in lParam */);
+       } else if (WM_PAINT == msg && PaintGrip()) {
+               CPaintDC dc(CWnd::FromHandle(hWnd));
+               RECT rc = getGripRect(hWnd);
+               dc.DrawFrameControl(&rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
+       } else if (WM_NCHITTEST == msg && !IsIconic(hWnd) && !IsZoomed(hWnd)) {
+               if (OnNcHitTest(msg, wParam, lParam, plresult))
+                       return true;
+       } else if (WM_DESTROY == msg) {
+               OnDestroy();
+       } else if (msg==WM_NOTIFY && TTN_NEEDTEXT==((NMHDR*)lParam)->code) {
+               if (OnTtnNeedText((TOOLTIPTEXT*)lParam, plresult))
+                       return true;
+       }
+
+       return false;
+}
+
+
+void
+CMoveConstraint::LoadPosition(LPCTSTR szName, bool position)
+{
+       m_sKey = szName;
+       m_bPersistent=true;
+       Persist(false, position);
+}
+
+void
+CMoveConstraint::Persist(bool saving, bool position)
+{
+       LPCTSTR szSection = _T("LastWindowPos");
+       WINDOWPLACEMENT wp;
+       wp.length=sizeof(wp);
+       if (saving)
+       {
+               CString str;
+               GetWindowPlacement(m_hwndDlg, &wp);
+               RECT & rc = wp.rcNormalPosition;
+               str.Format(_T("%d,%d,%d,%d"), rc.left, rc.top, rc.right, rc.bottom);
+               AfxGetApp()->WriteProfileString(szSection, m_sKey, str);
+       }
+       else
+       {
+               CString str = AfxGetApp()->GetProfileString(szSection, m_sKey);
+               GetWindowPlacement(m_hwndDlg, &wp);
+               CRect rc;
+               int ct=_stscanf(str, _T("%d,%d,%d,%d"), &rc.left, &rc.top, &rc.right, &rc.bottom);
+               if (ct==4)
+               {
+                       RECT & wprc = wp.rcNormalPosition;
+                       if (position)
+                       {
+                               wprc.left = rc.left;
+                               wprc.top = rc.top;
+                       }
+                       wprc.right = wprc.left + rc.Width();
+                       wprc.bottom = wprc.top + rc.Height();
+                       SetWindowPlacement(m_hwndDlg, &wp);
+               }
+       }
+}
+
+
+void
+CMoveConstraint::SetTip(int id, LPCTSTR szTip)
+{
+       tip ti;
+       ti.m_sText = szTip;
+       m_tips[id] = ti;
+}
+
+void
+CMoveConstraint::SetTip(int id, int nResourceId)
+{
+       tip ti;
+       ti.m_nResourceId = nResourceId;
+       m_tips[id] = ti;
+}
+
+
+} // namespace
+
diff --git a/Tools/MakePatchDirs/CMoveConstraint.h b/Tools/MakePatchDirs/CMoveConstraint.h
new file mode 100755 (executable)
index 0000000..a9a8327
--- /dev/null
@@ -0,0 +1,254 @@
+/*!
+  \file    CMoveConstraint.h
+  \author  Perry Rapp, Smartronix
+  \date    Created: 1998
+  \date    Edited:  2001/12/12 PR
+
+  \brief   Declaration of CMoveConstraint
+
+*/
+/* The MIT License
+Copyright (c) 2001 Perry Rapp
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef CMoveConstraint_h
+#define CMoveConstraint_h
+
+#ifndef __AFXTEMPL_H__
+#include <afxtempl.h>
+#endif
+
+class CFormView;
+
+namespace prdlg {
+
+class ConstraintData;
+
+/*!
+  \class CMoveConstraint
+  \brief Code to resize controls on a dialog (formview, propertypage)
+
+  HOW TO USE
+
+  (a) add a member variable
+
+       prdlg::CMoveConstraint m_constraint; 
+
+  (b) add (1) Initialize & (2,3,4...) Constrain calls
+      (to OnInitDialog for dialogs)
+      (to InitialUpdate for views)
+      (to OnCreate or OnCreateClient for frames)
+
+  (c) optionally call any Allow or Disallow functions to adjust sizing potential (as in b)
+
+  (d) call SetIsPropertyPage or Sheet if appropriate
+       call SetScrollScale (for formview)
+
+  Choose to (e1) Subclass or (e2) call WindowProc
+
+  (e1) call Subclass - can call after Initialize calls
+       unless original size is needed, eg FormViews,
+                in which case call Initialize from OnNcCreate
+
+  (e2) override dialog's WindowProc and forward to constraint
+    add code to WindowProc (copy following block) before the call to the parent WindowProc
+          use ClassWizard, or add to AFX_VIRTUAL block:
+          virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
+
+       LRESULT lresult;
+       if (m_constraint.WindowProc(m_hWnd, message, wParam, lParam, &lresult))
+               return lresult;
+
+
+   For frames & views, the GetMinMaxInfo is sent to the frame
+   so the frame must have a constraint to control min & max
+
+  EXAMPLE USE (in InitDialog)
+
+  m_constraint.InitializeCurrentSize(this);
+  m_constraint.ConstrainItem(IDC_EDIT, 0, 1, 0, 1); // fills up all x & y delta
+  m_constraint.ConstrainItem(IDC_LABEL, 0, 0, 1, 0); // no expansion, but below 100% of height growth
+  m_constraint.SubclassWnd(); // install subclassing
+
+ */
+
+class CMoveConstraint
+{
+public:
+
+       // add a MoveConstraint member to dialog or view
+       CMoveConstraint();
+       ~CMoveConstraint();
+
+       bool IsInitalized() { return m_hwndDlg!=0; }
+
+       // THIS IS THE USUAL ONE
+       // call from InitDialog (dialogs) or InitialUpdate (views) or OnCreate (frames)
+       // if you want the current size of the dialog
+       // to be used for scaling the controls
+       // fails if IsWindow fails
+       bool InitializeCurrentSize(HWND hwndParent);
+       bool InitializeCurrentSize(CWnd * pParent);
+
+       // if you want to set, a priori, the size of the dialog to be assumed
+       // the controls are scaled for in the template
+       // for use when parent is maximized, and we need to know the design size (in pixels)
+       // this size is what the initial controls are sized to fit
+       void InitializeSpecificSize(HWND hwndParent, int nWidth, int nHeight);
+       void InitializeSpecificSize(CWnd * pParent, int nWidth, int nHeight);
+
+       // for FORMVIEWS, who lose their dialog size early
+       // fails if no WM_SIZE came thru
+       bool InitializeOriginalSize(CWnd * pParent);
+       bool InitializeOriginalSize(HWND hwndParent);
+
+       // force an update of controls (laying them out to current size)
+       void UpdateSizes();
+
+       // default is no height shrink, no width shrink
+       // but allowed height growth & allowed width growth
+       void AllowHeightShrink();
+       void AllowWidthShrink();
+       void DisallowHeightGrowth();
+       void DisallowWidthGrowth();
+       // if you know exactly how big you want to allow it (in pixels)
+       // use -1 to not set an argument
+       void SetMaxSizePixels(int nWidth, int nHeight);
+       void SetMinSizePixels(int nWidth, int nHeight);
+       void SetMinSizePercent(double fWidth, double fHeight);
+
+       // for FORMVIEW, how much to reduce scrollbars when form shrinks
+       void SetScrollScale(CFormView * pFormView, double fShrinkWidth, double fShrinkHeight);
+
+       // call for each constrained child window (three equivalent versions for convenience)
+       // fails if IsWindow fails (except with CWnd it is just deferred)
+       bool Constrain(HWND hwndChild, double fLeftX, double fExpandX, double fAboveY, double fExpandY);
+       void Constrain(CWnd * pWnd, double fLeftX, double fExpandX, double fAboveY, double fExpandY);
+       bool ConstrainItem(int nId, double fLeftX, double fExpandX, double fAboveY, double fExpandY);
+
+       void SetIsPropertyPage() { m_bPropertyPage = true; SetSizeGrip(SG_NONE); }
+       void SetIsPropertySheet() { m_bPropertySheet = true; }
+       void SetIsView() { SetSizeGrip(SG_PARENTSTATE); }
+
+       // If you plan to constrain windows that are not your children
+       // (eg, grandchildren), call this
+       void ConstrainNonChildren() { m_bConstrainNonChildren = true; }
+
+       // embedded windows, such as property pages or formviews, should set the size grip to none
+       enum EGRIP { SG_NONE, SG_NORMAL, SG_PARENTSTATE };
+       void SetSizeGrip(EGRIP nGrip) { m_nGrip = nGrip; }
+       // either Subclass or call a WindowProc
+       bool SubclassWnd();
+       bool UnSubclassWnd();
+
+       // call after all constraints established
+       void LoadPosition(LPCTSTR szName, bool position); // always loads size, may also set position
+
+       // for use when children hadn't been created yet at initialization time
+       // so their constraints had to be buffered to be initialized later
+       // (this is used by property pages & property sheets automatically, at PSN_SETACTIVE)
+       void CheckDeferredChildren();
+       int GetDeferredCount() { return m_nDelayed; }
+
+       // see usage section above
+       bool WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT * plresult);
+       // obsolete now 2000/10/06
+       // (use SetIsPropertyPage etc, and WindowProc above, or just Subclass)
+       bool WindowProcPropertyPage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT * plresult);
+       bool WindowProcPropertySheet(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT * plresult);
+
+// ToolTips
+       void SetTip(int id, LPCTSTR szTip);
+       void SetTip(int id, int nResourceId);
+
+// Implementation methods
+protected:
+       struct Constraint;
+       void GrabCurrentDimensionsAsOriginal(HWND hwndParent);
+       bool DoConstrain(CWnd * pWnd, HWND hwndChild, double fLeftX, double fExpandX, double fAboveY, double fExpandY);
+       void InitializeChildConstraintData(HWND hwndParent, Constraint & constraint);
+       void Persist(bool saving, bool position);
+       BOOL CheckConstraint(HWND hwndChild);
+       // handle WM_SIZE
+       void Resize(HWND hWnd, UINT nType);
+       // handle WM_GETMINMAXINFO
+       void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI );
+       // handle WM_NCHITTEST
+       bool OnNcHitTest(UINT message, WPARAM wParam, LPARAM lParam, LRESULT * plresult);
+       // handle WM_NOTIFY/TTN_NEEDTEXT combination
+       bool OnTtnNeedText(TOOLTIPTEXT * pTTT, LRESULT * plresult);
+       // forwarder
+       UINT CallOriginalProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+       bool PaintGrip();
+       void ClearMostData();
+       void DeleteAllConstraints();
+       // handle WM_DESTROY
+       void OnDestroy();
+
+
+       static LRESULT CALLBACK ConstraintWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+       
+
+// Implementation types
+protected:
+       struct tip { CString m_sText; int m_nResourceId; tip() : m_nResourceId(0) { } };
+
+       struct Constraint
+       {
+               double m_fLeftX;
+               double m_fExpandX;
+               double m_fAboveY;
+               double m_fExpandY;
+               HWND m_hwndChild;
+               CWnd * m_pWnd;
+               CRect m_rectChildOriginal;
+               HWND m_hwndParent; // normally is the dialog
+               Constraint();
+               Constraint(double fLeftX, double fExpandX, double fAboveY, double fExpandY, HWND hwndChild, CWnd * pWnd);
+               void Init();
+       };
+
+       typedef CList<Constraint, Constraint &> ConstraintList;
+
+
+// Implementation data
+private:
+       HWND m_hwndDlg; // parent of controls - could be FormView or PropertyPage or whatever as well
+       CRect m_rectDlgOriginal;
+       int m_nOrigX;
+       int m_nOrigY;
+       EGRIP m_nGrip;
+       bool m_bOriginalFetched;
+       int m_nMinX;
+       int m_nMinY;
+       int m_nMaxX;
+       int m_nMaxY;
+       int m_nDelayed; // CWnds without HWND
+       bool m_bSubclassed;
+// formview stuff
+       CFormView * m_pFormView;
+       // formview original scrollbars
+       int m_nOrigScrollX;
+       int m_nOrigScrollY;
+       // formview - how much scrollbars shrink
+       double m_fShrinkWidth;
+       double m_fShrinkHeight;
+       // special handling for PSN_SETACTIVE
+       bool m_bPropertyPage;
+       bool m_bPropertySheet;
+// constraints
+       ConstraintList m_ConstraintList;
+       bool m_bConstrainNonChildren;
+       bool m_bPersistent; // whether to save position to registry
+       CString m_sKey;
+// tooltips
+       CMap<UINT, UINT, tip, tip&> m_tips;
+};
+
+} // namespace
+
+#endif // CMoveConstraint_h
+
diff --git a/Tools/MakePatchDirs/CSubclass.cpp b/Tools/MakePatchDirs/CSubclass.cpp
new file mode 100755 (executable)
index 0000000..5d9b993
--- /dev/null
@@ -0,0 +1,227 @@
+/*!
+  \file    CSubclass.cpp
+  \author  Perry Rapp, Smartronix, Creator, 1998-2001
+  \date    Created: 1998
+  \date    Edited:  2001/12/12 PR
+
+  \brief   Implementation of CSubclass
+
+*/
+/* The MIT License
+Copyright (c) 2001 Perry Rapp
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "StdAfx.h"
+#include "CSubclass.h"
+
+#ifndef __AFXTEMPL_H__
+#include <afxtempl.h>
+#endif
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+namespace prdlg {
+
+struct SubclassRec
+{
+       WNDPROC m_newproc;
+       WNDPROC m_oldproc;
+       void * m_data;
+       bool m_suppressing; // set during the failed message
+       Msg m_succeededMsg;
+       Msg m_failedMsg;
+};
+
+// all the subclasses for a given hwnd
+// newest is head
+typedef CList<SubclassRec, SubclassRec &> SubclassList;
+
+// map of hwnds to subclasses
+typedef CTypedPtrMap<CMapPtrToPtr, HWND, SubclassList*> SubclassMap;
+
+#ifdef _MT
+#define THREAD _declspec(thread)
+#else
+#define THREAD
+#endif
+// map of hwnds to subclasses for current thread
+static THREAD SubclassMap * f_Subclasses=0;
+
+
+
+bool Subclass(WNDPROC wndproc, HWND hwnd, void * data
+       , Msg * unsubclassSucceeded, Msg * unsubclassFailed)
+{
+               ASSERT(IsWindow(hwnd));
+               // cross-thread window usage is not kosher ?
+               ASSERT(GetCurrentThreadId() == GetWindowThreadProcessId(hwnd, 0));
+       if (!f_Subclasses)
+               f_Subclasses = new SubclassMap;
+       SubclassList *pList = 0;
+       if (f_Subclasses->Lookup(hwnd, pList))
+       { // we've already subclassed this window
+               for (POSITION pos = pList->GetHeadPosition(); pos; pList->GetNext(pos))
+               {
+                       SubclassRec & srec = pList->GetAt(pos);
+                       if (srec.m_newproc == wndproc)
+                               return false; // cannot resubclass with same WNDPROC
+               }
+       }
+       else
+       {
+               pList = new SubclassList;
+               f_Subclasses->SetAt(hwnd, pList);
+       }
+       SubclassRec sdata;
+       sdata.m_data = data;
+       sdata.m_newproc = wndproc;
+       sdata.m_oldproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+       sdata.m_suppressing = false;
+       if (unsubclassSucceeded)
+               sdata.m_succeededMsg = *unsubclassSucceeded;
+       else
+               sdata.m_succeededMsg.msg = 0;
+       if (unsubclassFailed)
+               sdata.m_failedMsg = *unsubclassFailed;
+       else
+               sdata.m_failedMsg.msg = 0;
+       SetWindowLong(hwnd, GWL_WNDPROC, (LPARAM)(WNDPROC)wndproc);
+       pList->AddHead(sdata);
+       return true;
+}
+
+bool UnSubclass(WNDPROC id, HWND hwnd)
+{
+               ASSERT(IsWindow(hwnd));
+               // cross-thread window usage is not kosher ?
+               ASSERT(GetCurrentThreadId() == GetWindowThreadProcessId(hwnd, 0));
+       SubclassList *pList = 0;
+               if (!f_Subclasses || !f_Subclasses->Lookup(hwnd, pList))
+                       // We've not subclassed this hwnd!
+                       return false;
+               if (!pList->GetCount())
+                       // internal error
+                       return false;
+       POSITION pos = pList->GetHeadPosition();
+       SubclassRec srec = pList->GetNext(pos);
+       if (srec.m_newproc == id)
+       { // we're the latest subclass
+                       WNDPROC curproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+                       if (id != curproc)
+                               // We're not the current wndproc, so we can't safely unhook
+                               return false;
+                       ASSERT(srec.m_oldproc); // internal error
+               SetWindowLong(hwnd, GWL_WNDPROC, (LPARAM)(WNDPROC)srec.m_oldproc);
+               pList->RemoveHead();
+               // fall thru to garbage collect list
+       }
+       else
+       { // we're not the latest, but try to unhook anyway (may be ok)
+               bool found=false;
+               SubclassRec sprevrec = srec;
+               for ( ; pos; pList->GetNext(pos), sprevrec=srec)
+               {
+                       srec = pList->GetAt(pos);
+                       if (srec.m_newproc == id)
+                       {
+                               found=true;
+                               break;
+                       }
+               }
+                       if (!found)
+                               // We've not subclassed with this wndproc (id) (or its been unsubclassed already)
+                               return false;
+                       if (sprevrec.m_oldproc != id)
+                               // Foreign subclass has intervened - we can't unhook
+                               return false;
+               sprevrec.m_oldproc = srec.m_oldproc;
+               pList->RemoveAt(pos);
+               // fall thru to garbage collect list
+       }
+       // garbage collect
+       if (!pList->GetCount())
+       {
+               f_Subclasses->RemoveKey(hwnd);
+               delete pList;
+               if (!f_Subclasses->GetCount())
+               {
+                       delete f_Subclasses;
+                       f_Subclasses = 0;
+               }
+       }
+       return true;
+}
+
+static SubclassRec * FindSubclass(WNDPROC id, HWND hwnd)
+{
+       SubclassList *pList = 0;
+               if (!f_Subclasses || !f_Subclasses->Lookup(hwnd, pList))
+                       // We've not subclassed this hwnd!
+                       return 0;
+       for (POSITION pos = pList->GetHeadPosition(); pos; pList->GetNext(pos))
+       {
+               SubclassRec & srec = pList->GetAt(pos);
+               if (srec.m_newproc == id)
+                       return &srec;
+       }
+       // We couldn't find our subclass of this hwnd
+       return 0;
+}
+
+LRESULT CallOldProc(WNDPROC id, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+       SubclassRec * psrec = FindSubclass(id, hwnd);
+               if (!psrec) return 0;
+       WNDPROC oldproc = psrec->m_oldproc; // psrec may get destroyed by the UnSubclass
+       if (msg == WM_DESTROY || msg == WM_NCDESTROY)
+       {
+               Msg smsg = psrec->m_succeededMsg;
+               bool succeeded = UnSubclass(id, hwnd);
+               // if UnSubclass succeeds, psrec will be deleted
+               if (succeeded)
+                       psrec = 0;
+               if (!psrec && smsg.msg)
+               {
+                       // succeeded, inform client
+                       CallWindowProc(id, hwnd, smsg.msg, smsg.wparam, smsg.lparam);
+               }
+               if (psrec && (msg == WM_NCDESTROY) && psrec->m_failedMsg.msg)
+               {
+                       // failed our last chance, inform client
+                       Msg & fmsg = psrec->m_failedMsg;
+                       psrec->m_suppressing = true;
+                       CallWindowProc(id, hwnd, fmsg.msg, fmsg.wparam, fmsg.lparam);
+                       psrec->m_suppressing = false;
+               }
+       }
+       // we don't forward the failed message
+       // (the succeeded message will never get here, as it was sent after unsubclassed)
+       if (psrec && psrec->m_suppressing)
+       {
+               const Msg & tmsg = psrec->m_failedMsg;
+               if (tmsg.msg == msg && tmsg.wparam == wParam && tmsg.lparam == lParam)
+                       return 0;
+       }
+
+       return CallWindowProc(oldproc, hwnd, msg, wParam, lParam);
+}
+
+void * GetData(WNDPROC id, HWND hwnd)
+{
+       SubclassRec * psrec = FindSubclass(id, hwnd);
+               if (!psrec) return 0;
+       return psrec->m_data;
+}
+
+
+
+
+} // namespace
diff --git a/Tools/MakePatchDirs/CSubclass.h b/Tools/MakePatchDirs/CSubclass.h
new file mode 100755 (executable)
index 0000000..adc98c4
--- /dev/null
@@ -0,0 +1,57 @@
+/*!
+  \file    CSubclass.h
+  \author  Perry Rapp, Smartronix
+  \date    Created: 1998
+  \date    Edited: 2001/12/12 PR
+
+  \brief   Subclass library - functions to subclass any window proc
+
+
+ Multiple subclasses of a given window proc are allowed, as long as each is a different
+ subclass window proc. A second subclass attempt with same window proc will fail --
+ Subclass(..) will return false.
+
+ Client may optionally specify unsubclass messages, if client wants to be notified
+ after the subclass has succeeded or failed.
+*/
+/* The MIT License
+Copyright (c) 2001 Perry Rapp
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef CSubclass_h
+#define CSubclass_h
+
+namespace prdlg {
+
+//! post-subclass message (CallOldProc does not forward these)
+// note that if another subclass removes ours violently, these will not get sent
+struct Msg
+{
+       UINT msg; // must be non-zero to be used
+       WPARAM wparam;
+       LPARAM lparam;
+};
+
+       //! Client calls Subclass(..) to install new window proc
+bool Subclass(WNDPROC wndproc, HWND hwnd, void * data
+       , Msg * unsubclassSucceeded = NULL, Msg * unsubclassFailed = NULL);
+
+       //! Client calls UnSubclass(..) to remove existing window proc subclass
+       // this does NOT trigger post-subclass messages
+bool UnSubclass(WNDPROC id, HWND hwnd);
+
+       //! Client must call CallOldProc(..) at end of subclassing proc
+LRESULT CallOldProc(WNDPROC id, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+       //! Client calls GetData(..) to retrieve data pointer passed in its Subclass(..) call
+void * GetData(WNDPROC id, HWND hwnd);
+
+
+} // namespace
+
+#endif CSubclass_h
+
diff --git a/Tools/MakePatchDirs/ChangeLog.txt b/Tools/MakePatchDirs/ChangeLog.txt
new file mode 100755 (executable)
index 0000000..c2c482b
--- /dev/null
@@ -0,0 +1,26 @@
+MakePatchDirs/ChangeLog.txt
+Add new items to bottom
+
+2003-08-21, Perry Rapp
+ Program works.
+
+2003-09-03, Perry Rapp
+ Added checkboxes to front to suppress VC6 stuff and RCS stuff.
+ (Implemented filter to implement suppressing this stuff.)
+ Bumped version to 1.1.13246.0.
+
+2003-12-10, Perry Rapp
+ Replaced App-Wizard boilerplate readme.txt with small writeup.
+
+2004-01-18, Perry Rapp
+ Remove code that skipped everything at top level except subdirectories (common, Languages, WinMerge)"
+ (So it works with WinMerge after the recent CVS reorganization.)
+ Fix browse dialog prompt, and move to string table.
+ Move errors from MakeDirs.cpp to string table.
+ Moved obj & binaries to Build and bin peer directories.
+ Display summary messagebox (with #files changed & new).
+ Bumped version to 1.2.0.0.
+
+2004-01-30, Perry Rapp
+ Moved output to ..\Build\Merge*, and temps to ..\BuildTmp\MakeMatchDirs__*.
+ Added to WinMerge sourceforge cvs repository.
\ No newline at end of file
diff --git a/Tools/MakePatchDirs/DropEdit.cpp b/Tools/MakePatchDirs/DropEdit.cpp
new file mode 100755 (executable)
index 0000000..57d3c8a
--- /dev/null
@@ -0,0 +1,218 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+//     CDropEdit
+//     Copyright 1997 Chris Losinger
+//
+//     This code is freely distributable and modifiable, as long as credit
+//     is given to where it's due. Watch, I'll demonstrate :
+//
+//     shortcut expansion code modified from :
+//     CShortcut, 1996 Rob Warner
+//
+////
+//
+//     To use this in an app, you'll need to :
+//
+//     1) Place a normal edit control on your dialog. 
+//     2) Check the "Accept Files" property.
+//
+//     4) In your dialog class, declare a member variable of type CDropEdit
+//        (be sure to #include "CDropEdit.h")
+//             ex. CDropEdit m_dropEdit;
+//
+//     5) In your dialog's OnInitDialog, call
+//             m_dropEdit.SubclassDlgItem(IDC_YOUR_EDIT_ID, this);
+//
+//     that's it!
+//
+//     This will behave exactly like a normal edit-control but with the 
+//     ability to accept drag-n-dropped files (or directories).
+//
+//  Modified Mid 1998 by Chris Maunder:
+//       - DropEdit can now accept files and directories at the 
+//         same time
+
+
+#include "stdafx.h"
+#include "DropEdit.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <afxdisp.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CDropEdit
+
+CDropEdit::CDropEdit()
+{
+       m_bAllowFiles = m_bAllowDirs = TRUE;
+
+    // Initialize OLE libraries
+       m_bMustUninitOLE = FALSE;
+    _AFX_THREAD_STATE* pState = AfxGetThreadState();
+    if (!pState->m_bNeedTerm)
+       {
+               SCODE sc = ::OleInitialize(NULL);
+               if (FAILED(sc))
+            AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
+               else
+                       m_bMustUninitOLE = TRUE;
+       }
+}
+
+CDropEdit::~CDropEdit()
+{
+       // Uninitialize OLE support
+       if (m_bMustUninitOLE)
+               ::OleUninitialize();
+}
+
+
+BEGIN_MESSAGE_MAP(CDropEdit, CEdit)
+       //{{AFX_MSG_MAP(CDropEdit)
+       ON_WM_CREATE()
+       ON_WM_DROPFILES()
+       //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CDropEdit message handlers
+
+int CDropEdit::OnCreate(LPCREATESTRUCT lpCreateStruct) 
+{
+       if (CEdit::OnCreate(lpCreateStruct) == -1)
+               return -1;
+       
+       DragAcceptFiles(TRUE);
+       
+       return 0;
+}
+
+//
+//     handle WM_DROPFILES
+//
+
+void CDropEdit::OnDropFiles(HDROP dropInfo)
+{
+       // Get the number of pathnames that have been dropped
+       WORD wNumFilesDropped = DragQueryFile(dropInfo, -1, NULL, 0);
+
+       CString firstFile="";
+
+       // get all file names. but we'll only need the first one.
+       for (WORD x = 0 ; x < wNumFilesDropped; x++) {
+
+               // Get the number of bytes required by the file's full pathname
+               WORD wPathnameSize = DragQueryFile(dropInfo, x, NULL, 0);
+
+               // Allocate memory to contain full pathname & zero byte
+               char * npszFile = (char *) LocalAlloc(LPTR, wPathnameSize += 1);
+
+               // If not enough memory, skip this one
+               if (npszFile == NULL) continue;
+
+               // Copy the pathname into the buffer
+               DragQueryFile(dropInfo, x, npszFile, wPathnameSize);
+
+               // we only care about the first
+               if (firstFile=="")
+                       firstFile=npszFile;
+
+               // clean up
+               LocalFree(npszFile);
+       }
+
+       // Free the memory block containing the dropped-file information
+       DragFinish(dropInfo);
+
+       // if this was a shortcut, we need to expand it to the target path
+       CString expandedFile = ExpandShortcut(firstFile);
+
+       // if that worked, we should have a real file name
+       if (expandedFile!="") 
+               firstFile=expandedFile;
+
+       
+       struct _stat buf;
+       // get some info about that file
+       int result = _stat( firstFile, &buf );
+       if( result == 0 ) {
+
+               // verify that we have a dir (if we want dirs)
+               if ((buf.st_mode & _S_IFDIR) == _S_IFDIR) 
+        {
+                       if (m_bAllowDirs)
+                               SetWindowText(firstFile);
+            SetSel(firstFile.GetLength(), firstFile.GetLength());
+               } 
+               // verify that we have a file (if we want files)
+        else if ((buf.st_mode & _S_IFREG) == _S_IFREG) 
+        {
+                       if (m_bAllowFiles)
+                               SetWindowText(firstFile);
+            SetSel(firstFile.GetLength(), firstFile.GetLength());
+               }
+       }
+}
+
+//////////////////////////////////////////////////////////////////
+//     use IShellLink to expand the shortcut
+//     returns the expanded file, or "" on error
+//
+//     original code was part of CShortcut 
+//     1996 by Rob Warner
+//     rhwarner@southeast.net
+//     http://users.southeast.net/~rhwarner
+
+CString CDropEdit::ExpandShortcut(CString &inFile)
+{
+       CString outFile = "";
+
+    // Make sure we have a path
+    ASSERT(inFile != _T(""));
+
+    IShellLink* psl;
+    HRESULT hres;
+    LPTSTR lpsz = inFile.GetBuffer(MAX_PATH);
+
+    // Create instance for shell link
+    hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+        IID_IShellLink, (LPVOID*) &psl);
+    if (SUCCEEDED(hres))
+    {
+        // Get a pointer to the persist file interface
+        IPersistFile* ppf;
+        hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*) &ppf);
+        if (SUCCEEDED(hres))
+        {
+            // Make sure it's ANSI
+            WORD wsz[MAX_PATH];
+            ::MultiByteToWideChar(CP_ACP, 0, lpsz, -1, wsz, MAX_PATH);
+
+            // Load shortcut
+            hres = ppf->Load(wsz, STGM_READ);
+            if (SUCCEEDED(hres)) {
+                               WIN32_FIND_DATA wfd;
+                               // find the path from that
+                               HRESULT hres = psl->GetPath(outFile.GetBuffer(MAX_PATH), 
+                                                               MAX_PATH,
+                                                               &wfd, 
+                                                               SLGP_UNCPRIORITY);
+
+                               outFile.ReleaseBuffer();
+            }
+            ppf->Release();
+        }
+        psl->Release();
+    }
+
+       inFile.ReleaseBuffer();
+
+       // if this fails, outFile == ""
+    return outFile;
+}
diff --git a/Tools/MakePatchDirs/DropEdit.h b/Tools/MakePatchDirs/DropEdit.h
new file mode 100755 (executable)
index 0000000..a3c69c1
--- /dev/null
@@ -0,0 +1,74 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+//     CDropEdit
+//     Copyright 1997 Chris Losinger
+//
+//     This code is freely distributable and modifiable, as long as credit
+//     is given to where it's due. Watch, I'll demonstrate :
+//
+//     shortcut expansion code modified from :
+//     CShortcut, 1996 Rob Warner
+//
+
+#if !defined(AFX_DROPEDIT_H__1D8BBDC1_784C_11D1_8159_444553540000__INCLUDED_)
+#define AFX_DROPEDIT_H__1D8BBDC1_784C_11D1_8159_444553540000__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+// DropEdit.h : header file
+//
+
+#include <shlobj.h>
+
+/////////////////////////////////////////////////////////////////////////////
+// CDropEdit window
+
+class CDropEdit : public CEdit
+{
+// Construction
+public:
+       CDropEdit();
+
+// Attributes
+public:
+
+// Operations
+public:
+    void AllowFileDrop(BOOL bAllow = TRUE)      { m_bAllowFiles = bAllow; }
+    BOOL AllowingFileDrop()                     { return m_bAllowFiles;   }
+    void AllowDirDrop(BOOL bAllow = TRUE)       { m_bAllowDirs = bAllow;  }
+    BOOL AllowingDirDrop()                      { return m_bAllowDirs;    }
+
+// Overrides
+       // ClassWizard generated virtual function overrides
+       //{{AFX_VIRTUAL(CDropEdit)
+       //}}AFX_VIRTUAL
+
+// Implementation
+public:
+       virtual ~CDropEdit();
+
+protected:
+       CString ExpandShortcut(CString &inFile);
+
+       // Generated message map functions
+protected:
+       //{{AFX_MSG(CDropEdit)
+       afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+       afx_msg void OnDropFiles(HDROP dropInfo);
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+
+       BOOL m_bAllowFiles, m_bAllowDirs;
+       BOOL m_bMustUninitOLE;
+
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_DROPEDIT_H__1D8BBDC1_784C_11D1_8159_444553540000__INCLUDED_)
diff --git a/Tools/MakePatchDirs/MakeDirs.cpp b/Tools/MakePatchDirs/MakeDirs.cpp
new file mode 100755 (executable)
index 0000000..cc8df6d
--- /dev/null
@@ -0,0 +1,307 @@
+/** @file MakeDirs.cpp 
+ *
+ *  @brief Implementation of MakeDirs class
+ */ 
+
+#include "stdafx.h"
+#include "MakeDirs.h"
+#include "resource.h"
+#include "exc.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+/** @brief Entry point */
+CString
+MakeDirs::DoIt(const CString & rootDir, MakeDirFilter * pifilter)
+{
+       MakeDirs md(rootDir, pifilter);
+       return md.Worker();
+}
+
+/** @brief Main code outline */
+CString
+MakeDirs::Worker()
+{
+       // normalize root dir
+       m_rootDir.Replace('/', '\\');
+       if (m_rootDir[m_rootDir.GetLength()-1] == '\\')
+               m_rootDir = m_rootDir.Left(m_rootDir.GetLength()-1);
+
+       LoadFiles(m_rootDir + _T("\\original_all"), &m_originalFiles);
+       LoadFiles(m_rootDir + _T("\\applied"), &m_appliedFiles);
+
+       RemoveDirIfExists(m_rootDir + _T("\\original"));
+       RemoveDirIfExists(m_rootDir + _T("\\altered"));
+
+       DiffArray diffs;
+       SplitFiles(m_originalFiles, m_appliedFiles, & diffs);
+
+       for (int i=0; i<diffs.Right.GetSize(); ++i)
+       {
+               CString src = m_rootDir + _T("\\applied\\") + diffs.Right[i];
+               CString dest = m_rootDir + _T("\\altered\\") + diffs.Right[i];
+               MyCopyFile(src, dest);
+       }
+
+       int newfiles = diffs.Right.GetSize();
+       int changedfiles = 0;
+       for (i=0; i<diffs.Shared.GetSize(); ++i)
+       {
+               CString oldf = m_rootDir + _T("\\original_all\\") + diffs.Shared[i];
+               CString newf = m_rootDir + _T("\\applied\\") + diffs.Shared[i];
+               if (FilesDiffer(oldf, newf))
+               {
+                       CString src = newf;
+                       CString dest = m_rootDir + _T("\\altered\\") + diffs.Shared[i];
+                       MyCopyFile(src, dest);
+                       src = oldf;
+                       dest = m_rootDir + _T("\\original\\") + diffs.Shared[i];
+                       MyCopyFile(src, dest);
+                       ++changedfiles;
+               }
+       }
+       CString summary = MakeStr(LoadResString(IDS_SUMMARY2), changedfiles, newfiles);
+       return summary;
+}
+
+
+/** @brief Split files into diff groups */
+void
+MakeDirs::SplitFiles(const CStringArray & left, const CStringArray & right, DiffArray * diffs)
+{
+       // caller must have sorted left & right !
+       int l=0, r=0;
+       while (1)
+       {
+               if (l<left.GetSize())
+               {
+                       if (r<right.GetSize())
+                       {
+                               int n = left[l].CollateNoCase(right[r]);
+                               if (n < 0)
+                               {
+                                       diffs->Left.Add(left[l]);
+                                       ++l;
+                               }
+                               else if (n > 0)
+                               {
+                                       diffs->Right.Add(right[r]);
+                                       ++r;
+                               }
+                               else
+                               {
+                                       diffs->Shared.Add(left[l]);
+                                       ++l;
+                                       ++r;
+                               }
+                       }
+                       else
+                       {
+                               diffs->Left.Add(left[l]);
+                               ++l;
+                       }
+               }
+               else
+               {
+                       if (r<right.GetSize())
+                       {
+                               diffs->Right.Add(right[r]);
+                               ++r;
+                       }
+                       else
+                       {
+                               return;
+                       }
+               }
+       }
+}
+
+/** @brief Load files recursively into array & sort */
+void
+MakeDirs::LoadFiles(const CString & path, CStringArray * array)
+{
+       CheckDirectory(path);
+       CString subdir;
+       LoadFilesWorker(path, subdir, array);
+       SortArray(array);
+}
+
+/** @brief Send array contents to debug window */
+void
+MakeDirs::TraceArray(const CStringArray & array)
+{
+#ifdef _DEBUG
+       for (int i=0; i<array.GetSize(); ++i)
+               TRACE(_T("%d: %s\n"), i, array[i]);
+#endif
+}
+
+/** @brief Throw exception if directory not found */
+void
+MakeDirs::CheckDirectory(const CString & path)
+{
+       if (!DoesDirExist(path))
+               Fail(MakeStr(LoadResString(IDS_DIR_NOT_FOUND1), path));
+}
+
+/** @brief Return true if directory exists */
+bool
+MakeDirs::DoesDirExist(const CString & path)
+{
+       CFileFind finder;
+       return !!finder.FindFile(path + _T("\\*.*"));
+}
+
+/** @brief Throw an exception */
+void
+MakeDirs::Fail(LPCTSTR sz)
+{
+       perry::exc e;
+       e.reportAndThrowError(sz);
+}
+
+/** @brief Load files recursively into array */
+void
+MakeDirs::LoadFilesWorker(const CString & path, const CString & subdir, CStringArray * array)
+{
+       CFileFind finder;
+       CString findpath = path + _T("\\");
+       if (subdir.IsEmpty())
+               findpath += _T("*.*");
+       else
+               findpath += subdir + _T("\\*.*");
+       BOOL bWorking = finder.FindFile(findpath);
+       while (bWorking)
+       {
+               bWorking = finder.FindNextFile();
+               if (finder.IsDots())
+                       continue;
+               CString subfilepath = finder.GetFilePath().Mid(path.GetLength()+1);
+               CString filename = finder.GetFileName();
+               CString filebase = filename;
+               CString ext;
+               int ind = filename.ReverseFind('.');
+               if (ind >= 0)
+               {
+                       ext = filename.Mid(ind+1);
+                       filebase = filename.Left(ind);
+               }
+               bool dir = !!finder.IsDirectory();
+               subfilepath = subfilepath.Left(subfilepath.GetLength() - filename.GetLength());
+               if (!m_pifilter->handle(dir, subfilepath, filebase, ext))
+                       continue;
+               if (finder.IsDirectory())
+               {
+                       CString newsubdir;
+                       if (!subfilepath.IsEmpty())
+                               newsubdir = subfilepath + (CString)_T("\\");
+                       newsubdir += finder.GetFileName();
+                       LoadFilesWorker(path, newsubdir, array);
+               }
+               else
+               {
+                       if (subdir.IsEmpty())
+                               continue;
+                       array->Add(subfilepath+filename);
+               }
+       }
+}
+
+static int __cdecl cmpstrarrents(const void * el1, const void * el2)
+{
+       const CString * str1 = reinterpret_cast<const CString *>(el1);
+       const CString * str2 = reinterpret_cast<const CString *>(el2);
+       return str1->CollateNoCase(*str2);
+}
+
+/** @brief Sort contents of array */
+void
+MakeDirs::SortArray(CStringArray * array)
+{
+       qsort(array->GetData(), array->GetSize(), sizeof(array->GetAt(0)), &cmpstrarrents);
+}
+
+/** @brief copy file, creating directories as needed */
+void
+MakeDirs::MyCopyFile(CString src, CString dest)
+{
+       int i = m_rootDir.GetLength()+1;
+       while (1)
+       {
+               int n = dest.Find('\\', i+1);
+               if (n<0)
+                       break;
+               CString subdir = dest.Left(n);
+               if (!DoesDirExist(subdir))
+               {
+                       if (!CreateDirectory(subdir, 0))
+                               Fail(MakeStr(LoadResString(IDS_CREATE_DIR_FAILED1), subdir));
+               }
+               i = n+1;
+       }
+       if (!CopyFile(src, dest, TRUE))
+               Fail(MakeStr(LoadResString(IDS_COPY_FILE_FAILED2), src, dest));
+}
+
+/** @brief Has file been changed (just use modification time) ? */
+bool
+MakeDirs::FilesDiffer(CString oldf, CString newf)
+{
+       CFileStatus olds, news;
+       if (!CFile::GetStatus(oldf, olds))
+               Fail(MakeStr(LoadResString(IDS_FILE_STATUS_ERROR1), oldf));
+       if (!CFile::GetStatus(newf, news))
+               Fail(MakeStr(LoadResString(IDS_FILE_STATUS_ERROR1), newf));
+       return (olds.m_size != news.m_size || olds.m_mtime != news.m_mtime);
+}
+
+/** @brief Recursively delete directory (throw exception if error) */
+void
+MakeDirs::MyDeleteDir(LPCTSTR szDir)
+{
+       CFileFind finder;
+       CString sSpec = szDir;
+       sSpec += _T("\\*.*");
+       if (finder.FindFile(sSpec))
+       {
+               BOOL done=FALSE;
+               while (!done)
+               {
+                       done = !finder.FindNextFile();
+                       if (finder.IsDots()) continue;
+                       if (finder.IsDirectory())
+                       {
+                               MyDeleteDir(finder.GetFilePath());
+                       }
+                       else
+                       {
+                               MyDeleteFile(finder.GetFilePath());
+                       }
+               }
+       }
+       finder.Close(); // must close the handle or RemoveDirectory will fail
+       if (!RemoveDirectory(szDir))
+               Fail(MakeStr(LoadResString(IDS_REMOVEDIRECTORY_FAILED1), szDir));
+}
+
+/** @brief Delete file (throw exception if error) */
+void
+MakeDirs::MyDeleteFile(LPCTSTR szFile)
+{
+       if (!DeleteFile(szFile))
+               Fail(MakeStr(LoadResString(IDS_DELETEFILE_FAILED1), szFile));
+}
+
+/** @brief Remove directory if it exists */
+void
+MakeDirs::RemoveDirIfExists(CString path)
+{
+       if (DoesDirExist(path))
+               MyDeleteDir(path);
+}
diff --git a/Tools/MakePatchDirs/MakeDirs.h b/Tools/MakePatchDirs/MakeDirs.h
new file mode 100755 (executable)
index 0000000..1ce909c
--- /dev/null
@@ -0,0 +1,57 @@
+/** @file MakeDirs.h 
+ *
+ *  @brief Declaration of MakeDirs class
+ */ 
+
+#ifndef MakeDirs_h
+#define MakeDirs_h
+
+class MakeDirFilter
+{
+public:
+       virtual bool handle(bool dir, const CString & subdir, const CString & filebase, const CString & ext) = 0;
+};
+
+class MakeDirs
+{
+public:
+       static CString DoIt(const CString & rootDir, MakeDirFilter * pifilter);
+
+
+// Implementation types
+private:
+       struct DiffArray
+       {
+               CStringArray Left;
+               CStringArray Right;
+               CStringArray Shared;
+       };
+
+// Implementation methods
+private:
+       MakeDirs(const CString & rootDir, MakeDirFilter * pifilter) : m_rootDir(rootDir), m_pifilter(pifilter) { }
+       CString Worker();
+       void LoadFiles(const CString & path, CStringArray * array);
+       void LoadFilesWorker(const CString & path, const CString & subdir, CStringArray * array);
+       void SortArray(CStringArray * array);
+       void CheckDirectory(const CString & path);
+       void SplitFiles(const CStringArray & left, const CStringArray & right, DiffArray * diffs);
+       void TraceArray(const CStringArray & array);
+       void MyCopyFile(CString src, CString dest);
+       void Fail(LPCTSTR sz);
+       bool DoesDirExist(const CString & path);
+       bool FilesDiffer(CString oldf, CString newf);
+       void MyDeleteDir(LPCTSTR szDir);
+       void MyDeleteFile(LPCTSTR szFile);
+       void RemoveDirIfExists(CString path);
+
+// Implementation data
+private:
+       CString m_rootDir;
+       MakeDirFilter * m_pifilter;
+       CStringArray m_originalFiles;
+       CStringArray m_appliedFiles;
+};
+
+
+#endif // MakeDirs_h
diff --git a/Tools/MakePatchDirs/MakePatchDirs.dsp b/Tools/MakePatchDirs/MakePatchDirs.dsp
new file mode 100755 (executable)
index 0000000..405b7ba
--- /dev/null
@@ -0,0 +1,212 @@
+# Microsoft Developer Studio Project File - Name="MakePatchDirs" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=MakePatchDirs - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "MakePatchDirs.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "MakePatchDirs.mak" CFG="MakePatchDirs - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "MakePatchDirs - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "MakePatchDirs - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "MakePatchDirs - Win32 Release"
+
+# PROP BASE Use_MFC 6
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 6
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\BuildTmp\MakePatchDirs__ReleaseA"
+# PROP Intermediate_Dir "..\BuildTmp\MakePatchDirs__ReleaseA"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
+# ADD LINK32 version.lib /nologo /subsystem:windows /machine:I386 /out:"..\Build\MergeRelease\MakePatchDirs.exe"
+
+!ELSEIF  "$(CFG)" == "MakePatchDirs - Win32 Debug"
+
+# PROP BASE Use_MFC 6
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 6
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\BuildTmp\MakePatchDirs__DebugA"
+# PROP Intermediate_Dir "..\BuildTmp\MakePatchDirs__DebugA"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 version.lib /nologo /subsystem:windows /debug /machine:I386 /out:"..\Build\MergeDebug\MakePatchDirs.exe" /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "MakePatchDirs - Win32 Release"
+# Name "MakePatchDirs - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\AppVersion.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CDirDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMoveConstraint.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CSubclass.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\DropEdit.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\exc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MakeDirs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MakePatchDirs.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\MakePatchDirsApp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MakePatchDirsDlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\AppVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CDirDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CMoveConstraint.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CSubclass.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DropEdit.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\exc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MakeDirs.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MakePatchDirsApp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MakePatchDirsDlg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\MakePatchDirs.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\MakePatchDirs.rc2
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\ChangeLog.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\dist.txt
+# End Source File
+# Begin Source File
+
+SOURCE=.\ReadMe.txt
+# End Source File
+# End Target
+# End Project
diff --git a/Tools/MakePatchDirs/MakePatchDirs.ico b/Tools/MakePatchDirs/MakePatchDirs.ico
new file mode 100755 (executable)
index 0000000..dfeca88
Binary files /dev/null and b/Tools/MakePatchDirs/MakePatchDirs.ico differ
diff --git a/Tools/MakePatchDirs/MakePatchDirs.rc b/Tools/MakePatchDirs/MakePatchDirs.rc
new file mode 100755 (executable)
index 0000000..538d4ee
--- /dev/null
@@ -0,0 +1,226 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+    "#define _AFX_NO_OLE_RESOURCES\r\n"
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+    "\r\n"
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+    "#ifdef _WIN32\r\n"
+    "LANGUAGE 9, 1\r\n"
+    "#pragma code_page(1252)\r\n"
+    "#endif //_WIN32\r\n"
+    "#include ""MakePatchDirs.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
+    "#include ""afxres.rc""         // Standard components\r\n"
+    "#endif\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME           ICON    DISCARDABLE     "MakePatchDirs.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG DISCARDABLE  0, 0, 235, 55
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About MakePatchDirs"
+FONT 8, "MS Sans Serif"
+BEGIN
+    ICON            IDR_MAINFRAME,IDC_STATIC,11,17,20,20
+    LTEXT           "MakePatchDirs Version 1.0",IDC_STATIC,40,10,119,8,
+                    SS_NOPREFIX
+    LTEXT           "Copyright (C) 2003",IDC_STATIC,40,22,119,8
+    DEFPUSHBUTTON   "OK",IDOK,178,7,50,14,WS_GROUP
+    LTEXT           "FIXED VERSION INFO",IDC_VERSION,40,34,119,8
+END
+
+IDD_MAKEPATCHDIRS_DIALOG DIALOGEX 0, 0, 298, 111
+STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | 
+    WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "MakePatchDirs"
+FONT 8, "MS Sans Serif"
+BEGIN
+    PUSHBUTTON      "...",IDC_DIR_BROWSE,242,23,26,14
+    DEFPUSHBUTTON   "Go",IDOK,203,62,50,14
+    EDITTEXT        IDC_DIR,29,26,199,12,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES
+    GROUPBOX        "Patch root directory: (drop directory here, or use browse button)",
+                    IDC_DIR_GROUP,19,14,256,29
+    GROUPBOX        "Options",IDC_STATIC,19,48,177,56
+    CONTROL         "Exclude VC stuff",IDC_EXCLUDE_VC_STUFF,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,25,61,156,10
+    CONTROL         "Exclude RCS stuff",IDC_EXCLUDE_RCS_STUFF,"Button",
+                    BS_AUTOCHECKBOX | WS_TABSTOP,25,77,156,10
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,2,0,0
+ PRODUCTVERSION 1,2,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "Comments", "\0"
+            VALUE "CompanyName", "Perry Rapp\0"
+            VALUE "FileDescription", "MakePatchDirs MFC Application\0"
+            VALUE "FileVersion", "1, 2, 0, 0\0"
+            VALUE "InternalName", "MakePatchDirs\0"
+            VALUE "LegalCopyright", "Copyright (C) 2003\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "MakePatchDirs.EXE\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "MakePatchDirs Application\0"
+            VALUE "ProductVersion", "1, 2, 0, 0\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_ABOUTBOX, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 228
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 48
+    END
+
+    IDD_MAKEPATCHDIRS_DIALOG, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 291
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 104
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDS_ABOUTBOX            "&About MakePatchDirs..."
+    IDS_CHOOSE_PATCH_PROMPT "Choose patch root (parent of original_all and applied"
+    IDS_CREATE_DIR_FAILED1  "CreateDirectory(%s) failed"
+    IDS_DIR_NOT_FOUND1      "Directory not found: %s"
+    IDS_COPY_FILE_FAILED2   "CopyFile(%s, %s) failed"
+    IDS_FILE_STATUS_ERROR1  "FileStatus error: %s"
+    IDS_REMOVEDIRECTORY_FAILED1 "RemoveDirectory(%s) failed"
+    IDS_DELETEFILE_FAILED1  "DeleteFile(%s) failed"
+    IDS_SUMMARY2            "Changed files: %d\r\nNew files: %d"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif //_WIN32
+#include "MakePatchDirs.rc2"  // non-Microsoft Visual C++ edited resources
+#include "afxres.rc"         // Standard components
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/Tools/MakePatchDirs/MakePatchDirs.rc2 b/Tools/MakePatchDirs/MakePatchDirs.rc2
new file mode 100755 (executable)
index 0000000..60a6888
--- /dev/null
@@ -0,0 +1,13 @@
+//
+// MAKEPATCHDIRS.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+       #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/Tools/MakePatchDirs/MakePatchDirsApp.cpp b/Tools/MakePatchDirs/MakePatchDirsApp.cpp
new file mode 100755 (executable)
index 0000000..3f5ce32
--- /dev/null
@@ -0,0 +1,72 @@
+// MakePatchDirs.cpp : Defines the class behaviors for the application.
+//
+
+#include "stdafx.h"
+#include "MakePatchDirsApp.h"
+#include "MakePatchDirsDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CMakePatchDirsApp
+
+BEGIN_MESSAGE_MAP(CMakePatchDirsApp, CWinApp)
+       //{{AFX_MSG_MAP(CMakePatchDirsApp)
+               // NOTE - the ClassWizard will add and remove mapping macros here.
+               //    DO NOT EDIT what you see in these blocks of generated code!
+       //}}AFX_MSG
+       ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMakePatchDirsApp construction
+
+CMakePatchDirsApp::CMakePatchDirsApp()
+{
+       // TODO: add construction code here,
+       // Place all significant initialization in InitInstance
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CMakePatchDirsApp object
+
+CMakePatchDirsApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CMakePatchDirsApp initialization
+
+BOOL CMakePatchDirsApp::InitInstance()
+{
+       // Standard initialization
+       // If you are not using these features and wish to reduce the size
+       //  of your final executable, you should remove from the following
+       //  the specific initialization routines you do not need.
+
+#ifdef _AFXDLL
+       Enable3dControls();                     // Call this when using MFC in a shared DLL
+#else
+       Enable3dControlsStatic();       // Call this when linking to MFC statically
+#endif
+
+       CMakePatchDirsDlg dlg;
+       m_pMainWnd = &dlg;
+       int nResponse = dlg.DoModal();
+       if (nResponse == IDOK)
+       {
+               // TODO: Place code here to handle when the dialog is
+               //  dismissed with OK
+       }
+       else if (nResponse == IDCANCEL)
+       {
+               // TODO: Place code here to handle when the dialog is
+               //  dismissed with Cancel
+       }
+
+       // Since the dialog has been closed, return FALSE so that we exit the
+       //  application, rather than start the application's message pump.
+       return FALSE;
+}
diff --git a/Tools/MakePatchDirs/MakePatchDirsApp.h b/Tools/MakePatchDirs/MakePatchDirsApp.h
new file mode 100755 (executable)
index 0000000..312bc44
--- /dev/null
@@ -0,0 +1,49 @@
+// MakePatchDirs.h : main header file for the MAKEPATCHDIRS application
+//
+
+#if !defined(AFX_MAKEPATCHDIRS_H__52906114_7009_41C2_AC82_A92A68F0EE58__INCLUDED_)
+#define AFX_MAKEPATCHDIRS_H__52906114_7009_41C2_AC82_A92A68F0EE58__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifndef __AFXWIN_H__
+       #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h"          // main symbols
+
+/////////////////////////////////////////////////////////////////////////////
+// CMakePatchDirsApp:
+// See MakePatchDirs.cpp for the implementation of this class
+//
+
+class CMakePatchDirsApp : public CWinApp
+{
+public:
+       CMakePatchDirsApp();
+
+// Overrides
+       // ClassWizard generated virtual function overrides
+       //{{AFX_VIRTUAL(CMakePatchDirsApp)
+       public:
+       virtual BOOL InitInstance();
+       //}}AFX_VIRTUAL
+
+// Implementation
+
+       //{{AFX_MSG(CMakePatchDirsApp)
+               // NOTE - the ClassWizard will add and remove member functions here.
+               //    DO NOT EDIT what you see in these blocks of generated code !
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_MAKEPATCHDIRS_H__52906114_7009_41C2_AC82_A92A68F0EE58__INCLUDED_)
diff --git a/Tools/MakePatchDirs/MakePatchDirsDlg.cpp b/Tools/MakePatchDirs/MakePatchDirsDlg.cpp
new file mode 100755 (executable)
index 0000000..b12438c
--- /dev/null
@@ -0,0 +1,281 @@
+/** 
+ * @file  MakePatchDirsDlg.cpp
+ *
+ * @date  Edited:  2004-01-18 (Perry)
+ * @date  Created: 2003 (Perry)
+ * @brief Code for CMakePatchDirsDlg (main dialog) & CAboutDlg classes
+ */
+// RCS ID line follows -- this is updated by CVS
+// $Id$
+
+
+#include "stdafx.h"
+#include "MakePatchDirsApp.h"
+#include "MakePatchDirsDlg.h"
+#include "MakeDirs.h"
+#include "CDirDialog.h"
+#include "AppVersion.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CAboutDlg dialog used for App About
+
+class CAboutDlg : public CDialog
+{
+public:
+       CAboutDlg();
+
+// Dialog Data
+       //{{AFX_DATA(CAboutDlg)
+       enum { IDD = IDD_ABOUTBOX };
+       CString m_sVersion;
+       //}}AFX_DATA
+
+       // ClassWizard generated virtual function overrides
+       //{{AFX_VIRTUAL(CAboutDlg)
+       protected:
+       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+       //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+       //{{AFX_MSG(CAboutDlg)
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+};
+
+CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
+{
+       //{{AFX_DATA_INIT(CAboutDlg)
+       m_sVersion = _T("");
+       //}}AFX_DATA_INIT
+}
+
+void CAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+       CDialog::DoDataExchange(pDX);
+       //{{AFX_DATA_MAP(CAboutDlg)
+       DDX_Text(pDX, IDC_VERSION, m_sVersion);
+       //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
+       //{{AFX_MSG_MAP(CAboutDlg)
+               // No message handlers
+       //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMakePatchDirsDlg dialog
+
+CMakePatchDirsDlg::CMakePatchDirsDlg(CWnd* pParent /*=NULL*/)
+       : CDialog(CMakePatchDirsDlg::IDD, pParent)
+{
+       //{{AFX_DATA_INIT(CMakePatchDirsDlg)
+       //}}AFX_DATA_INIT
+       // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
+       m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+}
+
+void CMakePatchDirsDlg::DoDataExchange(CDataExchange* pDX)
+{
+       CDialog::DoDataExchange(pDX);
+       //{{AFX_DATA_MAP(CMakePatchDirsDlg)
+       DDX_Control(pDX, IDC_DIR, m_dir);
+       //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CMakePatchDirsDlg, CDialog)
+       //{{AFX_MSG_MAP(CMakePatchDirsDlg)
+       ON_WM_SYSCOMMAND()
+       ON_WM_PAINT()
+       ON_WM_QUERYDRAGICON()
+       ON_BN_CLICKED(IDC_DIR_BROWSE, OnDirBrowse)
+       //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMakePatchDirsDlg message handlers
+
+BOOL CMakePatchDirsDlg::OnInitDialog()
+{
+       CDialog::OnInitDialog();
+
+       // Add "About..." menu item to system menu.
+
+       // IDM_ABOUTBOX must be in the system command range.
+       ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
+       ASSERT(IDM_ABOUTBOX < 0xF000);
+
+       CMenu* pSysMenu = GetSystemMenu(FALSE);
+       if (pSysMenu != NULL)
+       {
+               CString strAboutMenu;
+               strAboutMenu.LoadString(IDS_ABOUTBOX);
+               if (!strAboutMenu.IsEmpty())
+               {
+                       pSysMenu->AppendMenu(MF_SEPARATOR);
+                       pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
+               }
+       }
+
+       // Set the icon for this dialog.  The framework does this automatically
+       //  when the application's main window is not a dialog
+       SetIcon(m_hIcon, TRUE);                 // Set big icon
+       SetIcon(m_hIcon, FALSE);                // Set small icon
+
+       m_dir.AllowDirDrop();
+       m_dir.AllowFileDrop(FALSE);
+       m_constraint.InitializeCurrentSize(this);
+       m_constraint.ConstrainItem(IDC_DIR_GROUP, 0, 1, 0, 1);
+       m_constraint.ConstrainItem(IDC_DIR, 0, 1, 0, 1);
+       m_constraint.ConstrainItem(IDC_DIR_BROWSE, 1, 0, 1, 0);
+       m_constraint.ConstrainItem(IDOK, .5, 0, 1, 0);
+       m_constraint.DisallowHeightGrowth();
+       m_constraint.SubclassWnd();
+
+       GetDlgItem(IDC_EXCLUDE_VC_STUFF)->SendMessage(BM_SETCHECK, BST_CHECKED, 0);
+       
+       return TRUE;  // return TRUE  unless you set the focus to a control
+}
+
+void CMakePatchDirsDlg::OnSysCommand(UINT nID, LPARAM lParam)
+{
+       if ((nID & 0xFFF0) == IDM_ABOUTBOX)
+       {
+               CAboutDlg dlgAbout;
+               dlgAbout.m_sVersion = appv::GetVersionReport();
+               dlgAbout.DoModal();
+       }
+       else
+       {
+               CDialog::OnSysCommand(nID, lParam);
+       }
+}
+
+// If you add a minimize button to your dialog, you will need the code below
+//  to draw the icon.  For MFC applications using the document/view model,
+//  this is automatically done for you by the framework.
+
+void CMakePatchDirsDlg::OnPaint() 
+{
+       if (IsIconic())
+       {
+               CPaintDC dc(this); // device context for painting
+
+               SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
+
+               // Center icon in client rectangle
+               int cxIcon = GetSystemMetrics(SM_CXICON);
+               int cyIcon = GetSystemMetrics(SM_CYICON);
+               CRect rect;
+               GetClientRect(&rect);
+               int x = (rect.Width() - cxIcon + 1) / 2;
+               int y = (rect.Height() - cyIcon + 1) / 2;
+
+               // Draw the icon
+               dc.DrawIcon(x, y, m_hIcon);
+       }
+       else
+       {
+               CDialog::OnPaint();
+       }
+}
+
+// The system calls this to obtain the cursor to display while the user drags
+//  the minimized window.
+HCURSOR CMakePatchDirsDlg::OnQueryDragIcon()
+{
+       return (HCURSOR) m_hIcon;
+}
+
+void CMakePatchDirsDlg::OnDirBrowse() 
+{
+       UpdateData(TRUE);
+       prdlg::CDirDialog dlg; 
+
+       CString dir;
+       m_dir.GetWindowText(dir);
+
+       dlg.m_strTitle = LoadResString(IDS_CHOOSE_PATCH_PROMPT);
+       dlg.m_strSelDir = dir;
+
+       if (dlg.DoBrowse()) 
+       {
+               m_dir.SetWindowText(dlg.m_strPath);
+       }
+}
+
+
+/** @brief file/directory filter to pass to MakeDirs module */
+class PatchDlgFilter : public MakeDirFilter
+{
+public:
+       PatchDlgFilter() : m_excludeVc6(false), m_excludeCvs(false) { }
+       virtual bool handle(bool dir, const CString & subdir, const CString & filebase, const CString & ext);
+
+public:
+       bool m_excludeVc6;
+       bool m_excludeCvs;
+};
+
+bool PatchDlgFilter::handle(bool dir, const CString & subdir, const CString & filebase, const CString & ext)
+{
+       if (m_excludeVc6)
+       {
+               if (ext.CompareNoCase(_T("ncb"))==0
+                       || ext.CompareNoCase(_T("opt"))==0
+                       || ext.CompareNoCase(_T("aps"))==0
+                       || ext.CompareNoCase(_T("plg"))==0
+                       )
+               {
+                       return false;
+               }
+               if (filebase.CompareNoCase(_T("Build")) == 0)
+               {
+                       return false;
+               }
+
+       }
+       if (m_excludeCvs)
+       {
+               if (dir && filebase.CompareNoCase(_T("CVS")) == 0 && ext.IsEmpty())
+               {
+                       return false;
+               }
+       }
+       return true;
+}
+
+static bool IsButtonChecked(CWnd * pwnd, int id)
+{
+       return (pwnd->SendDlgItemMessage(id, BM_GETCHECK, 0, 0) == BST_CHECKED);
+}
+
+/** @brief User clicked Go */
+void CMakePatchDirsDlg::OnOK() 
+{
+       CString dir;
+       m_dir.GetWindowText(dir);
+       if (dir.IsEmpty()) return;
+
+
+       try {
+               CWaitCursor wait;
+
+               PatchDlgFilter filter;
+               filter.m_excludeVc6 = IsButtonChecked(this, IDC_EXCLUDE_VC_STUFF);;
+               filter.m_excludeCvs = IsButtonChecked(this, IDC_EXCLUDE_RCS_STUFF);;
+               CString summary = MakeDirs::DoIt(dir, &filter);
+               MessageBox(summary);
+
+       } catch(CException * pExc) {
+               pExc->ReportError();
+               pExc->Delete();
+       }
+}
diff --git a/Tools/MakePatchDirs/MakePatchDirsDlg.h b/Tools/MakePatchDirs/MakePatchDirsDlg.h
new file mode 100755 (executable)
index 0000000..93206f2
--- /dev/null
@@ -0,0 +1,57 @@
+// MakePatchDirsDlg.h : header file
+//
+
+#if !defined(AFX_MAKEPATCHDIRSDLG_H__E35CCFFC_0CBB_424C_85F2_3CF36C2672F6__INCLUDED_)
+#define AFX_MAKEPATCHDIRSDLG_H__E35CCFFC_0CBB_424C_85F2_3CF36C2672F6__INCLUDED_
+#pragma once
+
+/////////////////////////////////////////////////////////////////////////////
+// CMakePatchDirsDlg dialog
+
+#if !defined(AFX_DROPEDIT_H__1D8BBDC1_784C_11D1_8159_444553540000__INCLUDED_)
+#include "DropEdit.h"
+#endif
+#ifndef CMoveConstraint_h
+#include "CMoveConstraint.h"
+#endif
+
+
+class CMakePatchDirsDlg : public CDialog
+{
+// Construction
+public:
+       CMakePatchDirsDlg(CWnd* pParent = NULL);        // standard constructor
+
+// Dialog Data
+       //{{AFX_DATA(CMakePatchDirsDlg)
+       enum { IDD = IDD_MAKEPATCHDIRS_DIALOG };
+       CDropEdit       m_dir;
+       //}}AFX_DATA
+
+       // ClassWizard generated virtual function overrides
+       //{{AFX_VIRTUAL(CMakePatchDirsDlg)
+       protected:
+       virtual void DoDataExchange(CDataExchange* pDX);        // DDX/DDV support
+       //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+       HICON m_hIcon;
+       prdlg::CMoveConstraint m_constraint;
+
+       // Generated message map functions
+       //{{AFX_MSG(CMakePatchDirsDlg)
+       virtual BOOL OnInitDialog();
+       afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
+       afx_msg void OnPaint();
+       afx_msg HCURSOR OnQueryDragIcon();
+       afx_msg void OnDirBrowse();
+       virtual void OnOK();
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_MAKEPATCHDIRSDLG_H__E35CCFFC_0CBB_424C_85F2_3CF36C2672F6__INCLUDED_)
diff --git a/Tools/MakePatchDirs/ReadMe.txt b/Tools/MakePatchDirs/ReadMe.txt
new file mode 100755 (executable)
index 0000000..ea0c15b
--- /dev/null
@@ -0,0 +1,10 @@
+MakePatchDirs is a simple MFC AppWizard generated dialog-based utility which,
+when given a directory with subdirectories "Applied" and "Original_all", will
+diff them (naively using only modified date) and populate the two subdirectories
+"Altered" and "Original". It first deletes any existing subdirectories by those
+names ("Altered" and "Original").
+
+It was created by Perry Rapp in the late summer of 2003 for the purpose of 
+creating patches for winmerge (http://sourceforge.net/projects/winmerge).
+
+
diff --git a/Tools/MakePatchDirs/StdAfx.cpp b/Tools/MakePatchDirs/StdAfx.cpp
new file mode 100755 (executable)
index 0000000..1571dec
--- /dev/null
@@ -0,0 +1,24 @@
+// stdafx.cpp : source file that includes just the standard includes
+//     MakePatchDirs.pch will be the pre-compiled header
+//     stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+
+CString
+MakeStr(LPCTSTR fmt, ...)
+{
+       va_list args;
+       va_start(args, fmt);
+       CString str;
+       str.FormatV(fmt, args);
+       va_end(args);
+       return str;
+}
+
+CString LoadResString(int id)
+{
+       CString s;
+       VERIFY(s.LoadString(id));
+       return s;
+}
diff --git a/Tools/MakePatchDirs/StdAfx.h b/Tools/MakePatchDirs/StdAfx.h
new file mode 100755 (executable)
index 0000000..1b9bf78
--- /dev/null
@@ -0,0 +1,26 @@
+// stdafx.h : include file for standard system include files,
+//  or project specific include files that are used frequently, but
+//      are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__90247E26_68CE_4BA4_A7E2_B13CE471C2A0__INCLUDED_)
+#define AFX_STDAFX_H__90247E26_68CE_4BA4_A7E2_B13CE471C2A0__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define VC_EXTRALEAN           // Exclude rarely-used stuff from Windows headers
+
+#include <afxwin.h>         // MFC core and standard components
+#include <afxext.h>         // MFC extensions
+
+CString MakeStr(LPCTSTR fmt, ...);
+
+CString LoadResString(int id);
+
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__90247E26_68CE_4BA4_A7E2_B13CE471C2A0__INCLUDED_)
diff --git a/Tools/MakePatchDirs/dist.txt b/Tools/MakePatchDirs/dist.txt
new file mode 100755 (executable)
index 0000000..0a69ac9
--- /dev/null
@@ -0,0 +1,8 @@
+MakePatchDirs/dist.txt
+Add new items to bottom
+
+2003-08-25, Perry Rapp
+ Sent release exe (1.0.13233.0) to Laurent Ganier.
+
+2003-12-10, Perry Rapp
+ Sent source (1.1.13246.0) to Christian List.
diff --git a/Tools/MakePatchDirs/exc.cpp b/Tools/MakePatchDirs/exc.cpp
new file mode 100755 (executable)
index 0000000..f01a537
--- /dev/null
@@ -0,0 +1,524 @@
+/**
+ *  @file    exc.cpp
+ *  @author  Perry Rapp, Creator, 2001
+ *  @date    Created: 2001/10/10
+ *  @date    Edited:  2002/02/16 PR
+ *  @brief   Implements exception/reporting functions
+ *
+ * Copyright: 2001, Perry Rapp
+ */
+
+#include "stdafx.h"
+
+#ifndef exc_h
+#include "exc.h"
+#endif
+
+#ifndef __AFXDISP_H__
+#include <afxdisp.h>
+#endif
+
+#ifndef _INC_TIME
+#include <time.h>
+#endif
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+namespace perry {
+
+exc::~exc()
+{
+       CStdioFile & file = m_logfile;
+       if (file.m_hFile!=CFile::hFileNull)
+               file.Close();
+}
+
+void
+exc::setLog(LPCTSTR szLogFilepath)
+{
+       m_sLogFilepath = szLogFilepath;
+}
+
+static void
+DoThrow(CException * pExc)
+{
+       // this function exists as a convenient location for breakpointing
+       throw pExc;
+}
+
+excException *
+exc::Extract(CException * pExc)
+{
+       // get pointer to our type, if it is ours (else return NULL)
+       excException * myExc = 0;
+       if (pExc->IsKindOf(RUNTIME_CLASS(excException)))
+               myExc = (excException *)pExc;
+       return myExc;
+}
+
+excException *
+exc::Wrap(CException * pExc)
+{
+       // return pointer to ours (wrap it if not ours)
+       excException * myExc = Extract(pExc);
+       if (!myExc)
+               myExc = excException::Chained(pExc);
+       return myExc;
+}
+
+void
+exc::logError(LPCTSTR szText)
+{
+       CString str = szText;
+       dolog(str, true);
+}
+
+void
+exc::log(LPCTSTR szText)
+{
+       CString str = szText;
+       dolog(str, false);
+}
+
+bool
+exc::dolog(CString & str, bool error)
+{
+       if (str.IsEmpty()) // drop all blank messages
+               return false;
+       COleDateTime now = COleDateTime::GetCurrentTime();
+       CString sNow = now.Format();
+       for (POSITION pos = m_callbacks.GetHeadPosition(); pos; )
+       {
+               callback cb = m_callbacks.GetNext(pos);
+               (*cb.fnc)(cb.param, sNow, str, error);
+               if (str.IsEmpty()) // drop any messages cleared by a callback
+                       return false;
+       }
+       if (error)
+               m_nErrors++;
+       // we skip logging if no log file or not text
+       if (m_sLogFilepath.IsEmpty())
+               return true;
+       CSingleLock lock(&m_sem);
+       // we use semaphore if client has enabled multithreaded flag
+       if (m_bMultithreaded || lock.Lock())
+       {
+               CStdioFile & file = m_logfile;
+               if (file.m_hFile==CFile::hFileNull)
+               {
+                       int mode = CFile::shareDenyWrite+CFile::modeCreate+CFile::modeWrite;
+                       if (m_nMessageCount || !m_bWipePrevious)
+                               mode+=CFile::modeNoTruncate;
+                       if (!file.Open(m_sLogFilepath, mode))
+                               return true;
+               }
+               file.SeekToEnd();
+               CString sLeader = _T(" ");
+               if (error)
+                       sLeader = _T("*");
+
+               if (!m_nMessageCount)
+               {
+                       CString sIntro = GetIntro();
+                       file.WriteString((CString)_T(" ") + sNow + _T(": ") + sIntro + _T("\n"));
+               }
+               ++m_nMessageCount;
+               file.WriteString(sLeader + sNow+_T(": "));
+               file.WriteString(str);
+               file.WriteString(_T("\n"));
+               if (isTimeToFlush())
+               {
+                       m_nLastFlushTime=time(0);
+                       file.Close();
+               }
+       }
+       return true;
+}
+
+CString
+exc::GetIntro()
+{
+       CString sMessage = _T("Initial Log Message, Module: ");
+       TCHAR filename[_MAX_PATH];
+       GetModuleFileName(NULL, filename, sizeof(filename)/sizeof(filename[0]));
+       sMessage += filename;
+       CString sDebug;
+#ifdef _DEBUG
+       sDebug = " (Debug)";
+#endif
+       return sMessage;
+}
+
+bool
+exc::dolog(CException * pExc, LPCTSTR szText, bool error)
+{
+       // is it one of ours ?
+       excException * myExc = Extract(pExc);
+       if (myExc && myExc->IsLogged())
+       {
+               // exception has already been logged, so only log additional text
+               // (dolog will ignore it if text is blank)
+               CString str = szText;
+               dolog(str, false);
+               return true;
+       }
+       // forward to string logging function
+       CString str, sex(getString(pExc));
+       if (szText && szText[0])
+               str = szText;
+       if (!str.IsEmpty())
+               str += _T(": ");
+       str += sex;
+       CString sExceptionType = getTypeName(pExc);
+       if (!sExceptionType.IsEmpty())
+               str += _T(" (") + sExceptionType + _T(")");
+       // could add call here to report exception type & details
+       bool process = dolog(str, error);
+       // mark it as logged if it is one of ours
+       if (myExc)
+               myExc->SetLogged();
+       return process;
+}
+
+void
+exc::logError(CException * pExc, LPCTSTR szText)
+{
+       dolog(pExc, szText, true);
+}
+
+void
+exc::log(CException * pExc, LPCTSTR szText)
+{
+       dolog(pExc, szText, false);
+}
+
+void
+exc::logAndThrowError(CException * pExc, LPCTSTR szText)
+{
+       // wrap it with ours, if it isn't already one of ours
+       excException * myExc = Wrap(pExc);
+       // log it, and that will update it, as it is one of ours now
+       logError(myExc, szText);
+       DoThrow(myExc);
+}
+
+void
+exc::logAndThrowError(LPCTSTR szText)
+{
+       // create an exception for it
+       excException * myExc = excException::New(szText);
+       // log it, and that will update it, as it is one of ours now
+       logError(myExc, szText);
+       DoThrow(myExc);
+}
+
+bool
+exc::isTimeToFlush()
+{
+       if (m_bFlushEveryMessage)
+               return true;
+       if (m_nFlushMessageInterval 
+               && (m_nMessageCount%m_nFlushMessageInterval==0))
+       {
+               return true;
+       }
+       if (m_nFlushTimeInterval
+               && (time(0)-m_nLastFlushTime >= m_nFlushTimeInterval))
+       {
+               return true;
+       }
+       return false;
+}
+
+CString
+exc::getString(CException * pExc)
+{
+       TCHAR buffer[1024]=_T("");
+       if (!pExc->GetErrorMessage(buffer, sizeof(buffer)/sizeof(buffer[0])))
+               _tcscpy(buffer, _T("Exception with unobtainable content"));
+       return buffer;
+}
+
+CString
+exc::getTypeName(const CException * pExc)
+{
+       CString sNull;
+       if (pExc->IsKindOf(RUNTIME_CLASS(excException)))
+       {
+               excException * myExc = (excException *)pExc;
+               if (myExc->getChained())
+                       return getTypeName(myExc->getChained());
+               return sNull;
+       }
+       if (pExc->IsKindOf(RUNTIME_CLASS(CFileException)))
+               return _T("FileException");
+       if (pExc->IsKindOf(RUNTIME_CLASS(CMemoryException)))
+               return _T("MemoryException");
+       if (pExc->IsKindOf(RUNTIME_CLASS(CResourceException)))
+               return _T("ResourceException");
+#ifdef __AFXDAO_H
+       if (pExc->IsKindOf(RUNTIME_CLASS(CDaoException)))
+               return _T("DaoException");
+#endif
+       if (pExc->IsKindOf(RUNTIME_CLASS(CNotSupportedException)))
+               return _T("NotSupportedException");
+#ifndef __AFXOLE_H__
+       if (pExc->IsKindOf(RUNTIME_CLASS(COleException)))
+               return _T("OleException");
+#endif
+#ifndef __AFXDISP_H__
+       if (pExc->IsKindOf(RUNTIME_CLASS(COleDispatchException)))
+               return _T("OleDispatchException");
+#endif
+       return sNull;
+}
+
+void
+exc::reportError(LPCTSTR szText)
+{
+       doreport(szText, true);
+}
+
+bool
+exc::doreport(LPCTSTR szText, bool error)
+{
+       CString str = szText;
+       if (!dolog(str, error))
+               return false;
+       domsgbox(str);
+       return true;
+}
+
+void
+exc::domsgbox(CString str)
+{
+       if (!m_sErrorDisplayOverride.IsEmpty())
+               str = m_sErrorDisplayOverride;
+       if (m_timeMsgBox.GetStatus() != COleDateTime::valid)
+               m_timeMsgBox = COleDateTime::GetCurrentTime();
+       if (m_msgboxfnc)
+               (*m_msgboxfnc)(m_msgparam, str);
+       else
+               AfxMessageBox(str);
+}
+
+void
+exc::reportError(CException * pExc, LPCTSTR szText)
+{
+       doreport(pExc, szText, true);
+}
+
+bool
+exc::doreport(CException * pExc, LPCTSTR szText, bool error)
+{
+       excException * myExc = Extract(pExc);
+       if (myExc && myExc->IsReported())
+       {
+               // if already reported, just log it (dolog will skip it if already logged as well)
+               return dolog(myExc, szText, true);
+       }
+       // assemble msg string
+       CString str, sex(getString(pExc));
+       if (szText && szText[0])
+               str=szText;
+       if (!str.IsEmpty())
+               str += _T(": ");
+       str += sex;
+       // log it first
+       bool result = dolog(pExc, str, error);
+       // if not cancelled by callback, display it
+       if (result)
+               domsgbox(str);
+       // mark it as logged & displayed, if one of ours
+       if (myExc)
+       {
+               myExc->SetLogged();
+               myExc->SetReported();
+       }
+       return result;
+}
+
+void
+exc::reportAndThrowError(CException * pExc, LPCTSTR szText)
+{
+       // wrap it with ours, if it isn't already one of ours
+       excException * myExc = Wrap(pExc);
+       // report it or just log it
+       if (m_bDelayReport)
+       {
+               if (!dolog(myExc, szText, true))
+                       return;
+       }
+       else
+       {
+               if (!doreport(myExc, szText, true))
+                       return;
+       }
+       DoThrow(myExc);
+}
+
+void
+exc::reportAndThrowError(LPCTSTR szText)
+{
+       // create an exception for it
+       excException * myExc = excException::New(szText);
+       reportAndThrowError(myExc, NULL);
+}
+
+void
+exc::throwErrorString(LPCTSTR szText)
+{
+       if (!szText)
+               szText = _T("");
+       excException * pExc = excException::New(szText);
+       if (!dolog(pExc, NULL, true))
+       {
+               pExc->Delete();
+               return;
+       }
+       DoThrow(pExc);
+}
+
+void
+exc::throwError(CException * pExc)
+{
+       throwErrorString(getString(pExc));
+}
+
+static CString
+GetSystemError(int n)
+{
+       LPVOID lpMsgBuf;
+       FormatMessage( 
+                FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+                FORMAT_MESSAGE_FROM_SYSTEM | 
+                FORMAT_MESSAGE_IGNORE_INSERTS,
+                NULL,
+                n,
+                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                (LPTSTR) &lpMsgBuf,
+                0,
+                NULL 
+       );
+       // Process any inserts in lpMsgBuf.
+       // ...
+       // Display the string.
+       CString str = (LPCTSTR)lpMsgBuf;
+       // Free the buffer.
+       LocalFree( lpMsgBuf );
+       return str;
+}
+
+void
+exc::logLastSystemError()
+{
+       int err = GetLastError();
+       if (err)
+       {
+               CString sTemp;
+               sTemp.Format(_T("Last System Error (%d): "), err);
+               sTemp += GetSystemError(err);
+               dolog(sTemp, false);
+       }
+}
+
+void
+exc::addCallback(CALLBACKPTR ptr, void * param)
+{
+       m_callbacks.AddTail(callback(ptr, param));
+}
+
+void
+exc::removeCallback(CALLBACKPTR ptr, void * param)
+{
+       for (POSITION pos = m_callbacks.GetHeadPosition(); pos; )
+       {
+               POSITION prev = pos;
+               callback cb = m_callbacks.GetNext(pos);
+               if (cb.fnc == ptr && cb.param == param)
+               {
+                       m_callbacks.RemoveAt(prev);
+                       return;
+               }
+       }
+}
+
+IMPLEMENT_DYNAMIC(excException, CException)
+
+struct StartupInfo : STARTUPINFO
+{
+       StartupInfo()
+       {
+               memset(this, 0, sizeof(*this));
+               cb = sizeof(this);
+       }
+};
+bool
+RunNotepad(LPCTSTR szFilepath)
+{
+       CString sCommand;
+       sCommand.Format(_T("Notepad %s"), szFilepath);
+       StartupInfo sinfo;
+       sinfo.lpTitle=_T("test");
+       PROCESS_INFORMATION pinfo;
+       LPTSTR cmdline = sCommand.GetBuffer(sCommand.GetLength()+2);
+       int rtn = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo);
+       sCommand.ReleaseBuffer();
+       return rtn!=0;
+}
+
+bool
+IsPathSep(TCHAR ch)
+{
+       return ch=='\\' || ch=='/';
+}
+
+
+CString
+PathConcat(CString sPath, CString sFile)
+{
+       if (!sPath.IsEmpty() && IsPathSep(sPath[sPath.GetLength()-1]))
+       {
+               if (!sFile.IsEmpty() && IsPathSep(sFile[0]))
+                       return sPath + ((LPCTSTR)sFile+1);
+               else
+                       return sPath + sFile;
+       }
+       else
+       {
+               if (!sFile.IsEmpty() && IsPathSep(sFile[0]))
+                       return sPath + sFile;
+               else
+                       return sPath + '\\' + sFile;
+       }
+}
+
+CString
+GetModuleFilepath(HINSTANCE hinst)
+{
+       TCHAR filepath[MAX_PATH];
+       if (!hinst)
+               hinst=::GetModuleHandle(NULL);
+       GetModuleFileName(hinst, filepath, MAX_PATH);
+       return filepath;
+}
+
+CString
+GetPathFromFilepath(CString sFile)
+{
+       if (sFile.IsEmpty())
+               return _T("");
+       int count=0;
+       for (LPCTSTR ptr = (LPCTSTR)sFile+sFile.GetLength()-1; *ptr && *ptr!=':' && !IsPathSep(*ptr); --ptr)
+       {
+               ++count;
+       }
+       return sFile.Left(sFile.GetLength()-count);
+}
+
+
+} // namespace
diff --git a/Tools/MakePatchDirs/exc.h b/Tools/MakePatchDirs/exc.h
new file mode 100755 (executable)
index 0000000..07a99b2
--- /dev/null
@@ -0,0 +1,305 @@
+/**
+ *  @file    exc.h
+ *  @author  Perry Rapp, Creator, 2001
+ *  @date    Created: 2001/10/09
+ *  @date    Edited:  2001/11/28
+ *  @brief   Declares exception/reporting functions
+ *
+ * Copyright: 2001, Perry Rapp
+ */
+
+#ifndef exc_h
+#define exc_h
+
+#ifndef __AFXMT_H__
+#include <afxmt.h> // MFC multithreading classes
+#endif
+
+#ifndef __AFXTEMPL_H__
+#include <afxtempl.h> // MFC C++ template collection classes
+#endif
+
+#ifndef __AFXDISP_H__
+#include <afxdisp.h> // MFC Dispatch support classes (incl. COleDateTime)
+#endif
+
+namespace perry {
+class excException;
+
+// documentation below
+class exc
+{
+public:
+       // logging
+               // log() & logLastSystemError() do not increment #errors)
+               // others increment it unless exception is marked as having been logged already)
+       void log(LPCTSTR szText);
+       void log(CException * pExc, LPCTSTR szText=NULL);
+       void logError(LPCTSTR szText);
+       void logError(CException * pExc, LPCTSTR szText=NULL);
+       void logLastSystemError();
+       void logAndThrowError(CException * pExc, LPCTSTR szText=NULL);
+       void logAndThrowError(LPCTSTR szText);
+
+       // NB: callbacks can cancel messages, which also cancels throws
+
+       // message box (also logs contents)
+       void reportError(LPCTSTR szText);
+       void reportError(CException * pExc, LPCTSTR szText=NULL);
+       void reportAndThrowError(CException * pExc, LPCTSTR szText=NULL);
+       void reportAndThrowError(LPCTSTR szText);
+       // throwing exception (also logs contents, but does not do message box)
+       void throwErrorString(LPCTSTR szText);
+       void throwError(CException * pExc);
+
+// settings
+       void setLog(LPCTSTR szLogFilepath);
+
+       // protect logging with semaphore
+       bool isMultithreaded() const { return m_bMultithreaded; }
+       void setMultithreaded(bool multithreaded=true) { m_bMultithreaded=multithreaded; }
+       
+       // close file after every log message
+       bool isFlushEveryMessage() const { return m_bFlushEveryMessage; }
+       void setFlushEveryMessage(bool bFlushEveryMessage=true) { m_bFlushEveryMessage=bFlushEveryMessage; }
+       
+       // close file if it has been a while since last message
+       int getFlushTimeInterval() const { return m_nFlushTimeInterval; }
+       void setFlushTimeInterval(int nSeconds=60) { m_nFlushTimeInterval=nSeconds; }
+       
+       // close file if it has been a number of messages since last message
+       int getFlushMessageInterval() const { return m_nFlushMessageInterval; }
+       void setFlushMessageInterval(int nMessages=10) { m_nFlushMessageInterval=nMessages; }
+       
+       // replace previous log file (when writing first entry)
+       bool isWipePrevious() const { return m_bWipePrevious; }
+       void setWipePrevious(bool bWipe=true) { m_bWipePrevious=bWipe; }
+       
+       // log filepath
+       CString getLog() const { return m_sLogFilepath; }
+       
+       // error pre-callback (clear sText to suppress error)
+       typedef void (*CALLBACKPTR)(void * param, LPCTSTR szTime, CString & sText, bool error);
+       void addCallback(CALLBACKPTR ptr, void * param);
+       void removeCallback(CALLBACKPTR ptr, void * param);
+
+       // msgbox custom implementation
+       typedef void (*MSGBOXPTR)(void * param, LPCTSTR szText);
+       void setMsgbox(MSGBOXPTR fnc, void * param) { m_msgboxfnc = fnc; m_msgparam = param; }
+       
+       // error count
+       long getErrorCount() const { return m_nErrors; }
+       long getLogCount() const { return m_nMessageCount; }
+       void resetCounts() { m_nErrors=m_nMessageCount=0; }
+       
+       // override all visible msgbox strings
+       void setErrorDisplayString(LPCTSTR str) { m_sErrorDisplayOverride = str; }
+       CString getErrorDisplayString() const { return m_sErrorDisplayOverride; }
+
+       // for reportAndThrow, should msgboxes be delayed ?
+       void setDelayReports(bool bDelay=true) { m_bDelayReport=bDelay; }
+       bool getDelayReports() const { return m_bDelayReport; }
+
+       // what time was the first msg box displayed ?
+       COleDateTime GetMsgBoxTime() const { return m_timeMsgBox; }
+
+// Implementation methods (publicly available)
+public:
+       bool isTimeToFlush();
+       static CString getString(CException * pExc);
+       static CString getTypeName(const CException * pExc);
+
+// Implementation methods (not public)
+protected:
+               // all these return false if cancelled via callback
+       bool dolog(CString & str, bool error);
+       bool dolog(CException * pExc, LPCTSTR szText, bool error);
+       bool doreport(LPCTSTR szText, bool error);
+       bool doreport(CException * pExc, LPCTSTR szText, bool error);
+       excException * Extract(CException * pExc);
+       excException * Wrap(CException * pExc);
+       void domsgbox(CString str);
+
+       CString GetIntro();
+
+
+// Construction
+public:
+       exc()
+               // CString m_sLogFilepath
+               : m_bMultithreaded(false)
+               // CStdioFile m_logfile;
+               , m_bFlushEveryMessage(true)
+               , m_nFlushTimeInterval(10)
+               , m_nLastFlushTime(0)
+               , m_nLastFlushMessage(0)
+               , m_nMessageCount(0)
+               , m_nFlushMessageInterval(10)
+               , m_bWipePrevious(false)
+               // CSemaphore m_sem
+               // CallbackList m_callbacks
+               , m_nErrors(0)
+               // CString m_sErrorDisplayOverride
+               , m_bDelayReport(false)
+               , m_msgboxfnc(0)
+               , m_msgparam(0)
+               {
+               }
+       ~exc();
+
+       struct callback { CALLBACKPTR fnc; void * param; callback(CALLBACKPTR f=0, void * p=0) : fnc(f), param(p) { } };
+       typedef CList<callback, callback> CallbackList;
+// Implementation data
+private:
+       CString m_sLogFilepath;
+       bool m_bMultithreaded;
+       CStdioFile m_logfile;
+       bool m_bFlushEveryMessage; // write every message out separately
+       int m_nFlushTimeInterval; // flush if over this much time since last flush
+       int m_nLastFlushTime;
+       int m_nLastFlushMessage;
+       long m_nMessageCount;
+       int m_nFlushMessageInterval; // flush after this many messages
+       bool m_bWipePrevious;
+       CSemaphore m_sem; // for multithreaded use
+       CallbackList m_callbacks;
+       long m_nErrors;
+       CString m_sErrorDisplayOverride;
+       bool m_bDelayReport;
+       MSGBOXPTR m_msgboxfnc;
+       void * m_msgparam;
+       COleDateTime m_timeMsgBox;
+};
+
+// utility functions
+bool RunNotepad(LPCTSTR szFilepath);
+bool IsPathSep(TCHAR ch);
+CString PathConcat(CString sPath, CString sFile);
+CString GetModuleFilepath(HINSTANCE hinst);
+CString GetPathFromFilepath(CString sFile);
+
+// exception type used by exc
+// exposed here in header in case client wants to catch or use them
+class excException : public CException
+{
+public:
+       DECLARE_DYNAMIC(excException)
+       static excException * New(LPCTSTR sz) { return new excException(sz); }
+       static excException * Chained(CException * pExc) { return new excException(pExc); }
+       virtual BOOL GetErrorMessage( LPTSTR lpszError, UINT nMaxError, PUINT /*pnHelpContext*/ = NULL)
+       {
+               _tcsncpy(lpszError, m_str, nMaxError);
+               return TRUE;
+       }
+       virtual int ReportError(UINT nType = MB_OK, UINT nMessageID = 0)
+       {
+               int rtn=IDOK;
+               if (!IsReported())
+               {
+                       rtn=CException::ReportError(nType, nMessageID);
+                       SetReported(true);
+               }
+               return rtn;
+       }
+       bool IsLogged() const { return m_bLogged; }
+       bool IsReported() const { return m_bReported; }
+       void SetLogged(bool logged=true) { m_bLogged=logged; }
+       void SetReported(bool reported=true) { m_bReported=reported; }
+       virtual CString GetString() const { return m_str; }
+       const CException * getChained() const { return m_pExc; }
+protected:
+       excException(LPCTSTR sz) : m_str(sz),m_bLogged(false),m_bReported(false),m_pExc(0) { }
+       excException(CException * pExc) : m_str(exc::getString(pExc)), m_bLogged(false),m_bReported(false), m_pExc(pExc) { }
+       ~excException() { if (m_pExc) { m_pExc->Delete(); m_pExc=0; } }
+private:
+       CString m_str;
+       bool m_bLogged;
+       bool m_bReported;
+       CException * m_pExc; // throwing someone else's exception
+};
+
+/*!
+       @class   exc
+
+       Simplest way to use:
+
+       ** #1) Add these two lines to stdafx.h:
+
+#include "exc.h"
+extern perry::exc appexc;
+       ** #2) Add this line to stdafx.cpp:
+
+perry::exc appexc;
+
+       ** #3a) Add these lines to App::InitInstance:
+
+       appexc.setLog(_T("Wherever you want the log file.log")); 
+       ** #3b) or, to put it in the directory with the exe:
+
+       CString sPath = perry::GetPathFromFilepath(perry::GetModuleFilepath(0));
+       CString sAppName = m_pszAppName;
+       CString sLog = perry::PathConcat(sPath, sAppName+_T(".log"));
+       appexc.setLog(sLog);
+
+       ** #4) Write simple exception handlers like so (for message boxes):
+
+               } catch(CException * pExc) {
+                       appexc.report(pExc);
+                       pExc->Delete();
+               } catch(...) {
+                       appexc.logLastSystemError(); // Logs GetLastError if nonzero
+                       appexc.report(_T("Unknown exception in foo"));
+               }
+    
+       ** #5) Write simple exception handlers like so (for silent handling):
+
+               } catch(CException * pExc) {
+                       appexc.log(pExc);
+                       pExc->Delete();
+               } catch(...) {
+                       appexc.logLastSystemError(); // Logs GetLastError if nonzero
+                       appexc.log(_T("Unknown exception in foo"));
+               }
+
+       ** #6) Translate exceptions like so (silently, but rethrowing):
+
+               } catch(dbException & exc) {
+                       appexc.logLastSystemError();
+                       appexc.log(_T("fastdb exception"));
+                       appexc.throwString(exc.getMsg() ? exc.getMsg() : _T("Unspecified fastdb exception"));
+                       // this throws an excException, which is a type of CException
+               }
+
+       ** #7) Write a message to the log at any time like so:
+               appexc.log(_T("The user just put the mouse into the CD drive!"));
+
+       ** #8) Menu handlers for viewing log file from menu choice:
+
+void CMsiBrowserApp::OnViewlog() 
+{
+       perry::RunNotepad(appexc.getLog());     
+}
+void CMsiBrowserApp::OnUpdateViewlog(CCmdUI* pCmdUI) 
+{
+       bool empty=true;
+       CFileStatus fs;
+       if (CFile::GetStatus(appexc.getLog(), fs))
+       {
+               if (fs.m_size>0)
+                       empty=false;
+       }
+       pCmdUI->Enable(!empty);
+}
+
+
+  Notes:
+   An excException is logged when thrown, not when caught.
+       An excException does not present a message box again if report is called 
+        for it a second time.
+*/
+
+} // namespace
+
+#endif // exc_h
diff --git a/Tools/MakePatchDirs/resource.h b/Tools/MakePatchDirs/resource.h
new file mode 100755 (executable)
index 0000000..7437219
--- /dev/null
@@ -0,0 +1,35 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by MakePatchDirs.rc
+//
+#define IDM_ABOUTBOX                    0x0010
+#define IDD_ABOUTBOX                    100
+#define IDS_ABOUTBOX                    101
+#define IDD_MAKEPATCHDIRS_DIALOG        102
+#define IDS_CHOOSE_PATCH_PROMPT         102
+#define IDS_CREATE_DIR_FAILED1          103
+#define IDS_DIR_NOT_FOUND1              104
+#define IDS_COPY_FILE_FAILED2           105
+#define IDS_FILE_STATUS_ERROR1          106
+#define IDS_REMOVEDIRECTORY_FAILED1     107
+#define IDS_DELETEFILE_FAILED1          108
+#define IDS_SUMMARY2                    109
+#define IDR_MAINFRAME                   128
+#define IDC_DIR_BROWSE                  1001
+#define IDC_DIR                         1004
+#define IDC_DIR_GROUP                   1006
+#define IDC_VERSION                     1007
+#define IDC_EXCLUDE_VC_STUFF            1008
+#define IDC_EXCLUDE_RCS_STUFF2          1009
+#define IDC_EXCLUDE_RCS_STUFF           1009
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        129
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1009
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif