You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1591 lines
51 KiB
1591 lines
51 KiB
/******************************************************************************
|
|
|
|
Source File: Project Record.CPP
|
|
|
|
This implements the project record class, which tracks the details for
|
|
multiple mini-drivers.
|
|
|
|
Copyright (c) 1997 by Microsoft Corporation. All Rights Reserved.
|
|
|
|
A Pretty Penny Enterprises Production.
|
|
|
|
Change History:
|
|
02-03-1997 [email protected] Created it
|
|
|
|
******************************************************************************/
|
|
|
|
#include "StdAfx.H"
|
|
#include <gpdparse.h>
|
|
#include "MiniDev.H"
|
|
#include "Resource.H"
|
|
#include "comctrls.h"
|
|
#include "NewProj.H"
|
|
#include "projnode.h"
|
|
#include "StrEdit.h"
|
|
#include "codepage.h"
|
|
#include <io.h>
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CProjectRecord
|
|
|
|
IMPLEMENT_DYNCREATE(CProjectRecord, CDocument)
|
|
|
|
BEGIN_MESSAGE_MAP(CProjectRecord, CDocument)
|
|
//{{AFX_MSG_MAP(CProjectRecord)
|
|
// NOTE - the ClassWizard will add and remove mapping macros here.
|
|
// DO NOT EDIT what you see in these blocks of generated code!
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CProjectRecord construction/destruction
|
|
|
|
CProjectRecord::CProjectRecord() {
|
|
m_ufTargets = Win2000;
|
|
m_ufStatus = 0;
|
|
m_bRCModifiedFlag = FALSE ;
|
|
m_ctRCFileTimeStamp = (time_t) 0 ;
|
|
m_dwDefaultCodePage = 1252 ; // Not always correct but better than nothing
|
|
m_dwDefaultCodePageNum = 1252 ; // Not always correct but better than nothing
|
|
}
|
|
|
|
CProjectRecord::~CProjectRecord() {
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::OnOpenDocument
|
|
|
|
First, open the file directly and try to read version information from it.
|
|
Complain and fail the open if the file's version is greater than the MDT's
|
|
current version number. IE, fail if someone is trying to open a workspace
|
|
on a down level (older) version of the MDT.
|
|
|
|
Second, open a workspace in the normal way. Then check the workspace's
|
|
version to see if it is out of date. If it is and the user agrees, do what is
|
|
necessary to bring it up to date and then save the updated workspace file.
|
|
|
|
All version related upgrade work should be managed from this routine.
|
|
Depending on the age of the workspace file, there may be multiple upgrade
|
|
steps required. Be that as it may, the user should only be prompted once.
|
|
NEW UPGRADE CHECKS AND STEPS SHOULD FOLLOW THE FORMAT LAYED OUT BELOW.
|
|
|
|
There are various other workspace related checks that need to be done. For
|
|
example, the timestamp of the RC file needs to be checked to see if it has
|
|
been changed by something other than the the MDT. That work should be done
|
|
and/or managed by code in this routine, too. If possible (and I'm not sure
|
|
it is), prompt the user no more than once per file (eg, RC or INF) for these
|
|
things, too. AGAIN, FOLLOW THE FORMAT LAYED OUT BELOW.
|
|
|
|
The last thing done in this routine is to try to verify and - if necessary -
|
|
update the location of files in the workspace. If this fails and the user
|
|
doesn't want to continue anyway, the Open is failed. See VerUpdateFilePaths()
|
|
for more information.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CProjectRecord::OnOpenDocument(LPCTSTR lpszPathName)
|
|
{
|
|
// Complain and fail if the user is trying to open a bogus file.
|
|
|
|
CString cstmp(lpszPathName), cstmp2 ;
|
|
cstmp.MakeUpper() ;
|
|
cstmp2.LoadString(IDS_MDWExtension) ;
|
|
if (cstmp.Find(cstmp2) == -1) {
|
|
cstmp.LoadString(IDS_UnExpFilTypError) ;
|
|
AfxMessageBox(cstmp, MB_ICONEXCLAMATION) ;
|
|
return FALSE ;
|
|
} ;
|
|
|
|
// Start by reading the MDW file's version stamp.
|
|
|
|
try {
|
|
CFile cfmdw(lpszPathName, CFile::modeRead | CFile::shareDenyNone) ;
|
|
cfmdw.Read(&m_mvMDWVersion, MDWVERSIONSIZE) ;
|
|
cfmdw.Close() ;
|
|
}
|
|
catch (CException* pce) {
|
|
pce->ReportError() ;
|
|
pce->Delete() ;
|
|
return FALSE ;
|
|
} ;
|
|
|
|
// If the version tag is invalid, set the version number to the
|
|
// default version number; IE, 0.
|
|
|
|
if (strncmp(m_mvMDWVersion.acvertag, VERTAGSTR, MDWVERSIONSIZE) != 0)
|
|
m_mvMDWVersion.uvernum = MDW_DEFAULT_VERSION ;
|
|
|
|
// Now. make sure that the MDW's version isn't newer than the MDT's version.
|
|
|
|
if (m_mvMDWVersion.uvernum > MDW_CURRENT_VERSION) {
|
|
CString csmsg, cstmp ;
|
|
cstmp = lpszPathName ;
|
|
int nloc = cstmp.ReverseFind(_T('\\')) ;
|
|
if (nloc >= 0)
|
|
cstmp = cstmp.Right(cstmp.GetLength() - nloc - 1) ;
|
|
csmsg.Format(IDS_MDWTooNewError, cstmp, m_mvMDWVersion.uvernum,
|
|
MDW_CURRENT_VERSION) ;
|
|
AfxMessageBox(csmsg, MB_ICONEXCLAMATION) ;
|
|
return FALSE ;
|
|
} ;
|
|
|
|
if (!CDocument::OnOpenDocument(lpszPathName))
|
|
return FALSE ;
|
|
|
|
// Save the project file's filespec.
|
|
|
|
m_csProjFSpec = lpszPathName ;
|
|
|
|
// If the workspace version is too old to upgrade, just return TRUE to
|
|
// indicate that the file was successfully opened and that nothing else
|
|
// can be done.
|
|
|
|
if (m_mvMDWVersion.uvernum < MDW_FIRST_UPGRADABLE_VER)
|
|
return TRUE ;
|
|
|
|
// *** Beginning of workspace upgrade management code.
|
|
//
|
|
// o Declare flags for each of the required upgrade steps. These
|
|
// flags will be set in the following switch statement.
|
|
// o There is also a flag that is set when any workspace upgrading is
|
|
// required.
|
|
// o Make sure that all flags are initialized to false.
|
|
//
|
|
// NOTE: That the cases in the switch statement do not end with break
|
|
// statements. This is so that all of the upgrade flags for a workspace
|
|
// currently at a particular version will be set when needed. The
|
|
// switch statement is set up so that if the workspace is version X, then
|
|
// all of the upgrade flags for versions > X are set.
|
|
//
|
|
// Whenever a new workspace version is added:
|
|
// o Declare a new flag for it.
|
|
// o Add a new case statement to the switch statement for it. (See note
|
|
// above. You are actually adding a case statement for the previous
|
|
// version that will set the new version's flag.)
|
|
// o Bupgradeneeded should always be set by the last case statement.
|
|
// Move the bupgradeneeded setting statement to the last case statement
|
|
// whenever a new case statement is added.
|
|
|
|
bool bupgradeneeded, brctimestamp, bdefaultcodepage, bresdllnamechanged ;
|
|
bool bnodrpathsinmdw, bfilesinw2ktree ;
|
|
bupgradeneeded = brctimestamp = bdefaultcodepage = false ;
|
|
bresdllnamechanged = bnodrpathsinmdw = bfilesinw2ktree = false ;
|
|
switch (m_mvMDWVersion.uvernum) {
|
|
case MDW_VER_STRING_RCIDS:
|
|
bdefaultcodepage = true ;
|
|
case MDW_VER_DEFAULT_CPAGE:
|
|
brctimestamp = true ;
|
|
case MDW_VER_RC_TIMESTAMP:
|
|
bresdllnamechanged = true ;
|
|
case MDW_VER_NEW_DLLNAME:
|
|
bnodrpathsinmdw = true ;
|
|
case MDW_VER_NO_FILE_PATHS:
|
|
bfilesinw2ktree = true ;
|
|
bupgradeneeded = true ;
|
|
} ;
|
|
|
|
// If upgrade(s) are needed, declare a flag that indicates if any upgrading,
|
|
// checking, or updating error has occurred. If this flag is set, all
|
|
// processing should stop. Then...
|
|
|
|
bool bprocerror = false ;
|
|
bool buserwantstoupgrade = false ;
|
|
CString csprompt ;
|
|
if (bupgradeneeded) {
|
|
|
|
// ... Build a customized prompt for the user.
|
|
// o Statements about upgrade tasks relevant to the user should also
|
|
// be added to the prompt. For example, it should be noted when
|
|
// the RC file will be rewritten. In this case (and below when
|
|
// other RC related checks are made), it is only necessary to
|
|
// test the "newest" RC related flag. IE, the one associated with
|
|
// the latest MDW version. This works because if any of the older
|
|
// RC flags are set, the newest one must be set too.
|
|
// o Be concise so the message doesn't get too long.
|
|
|
|
csprompt.Format(IDS_MDWUpgradeMsg1, DriverName()) ;
|
|
if (bresdllnamechanged) {
|
|
cstmp.LoadString(IDS_RCFileChanging) ;
|
|
csprompt += cstmp ;
|
|
} ;
|
|
cstmp.LoadString(IDS_MDWUpgradeMsg2) ;
|
|
csprompt += cstmp ;
|
|
|
|
// ... Do the work if the user wants to upgrade.
|
|
// o Each upgrade step should be enclosed in an if statement that
|
|
// checks its individual flag and the processing error flag.
|
|
|
|
if (AfxMessageBox(csprompt, MB_ICONQUESTION + MB_YESNO) == IDYES) {
|
|
buserwantstoupgrade = true ;
|
|
|
|
// If required, prompt the user for a default code page for the
|
|
// driver and save it.
|
|
|
|
if (!bprocerror && bdefaultcodepage)
|
|
bprocerror = !UpdateDfltCodePage() ;
|
|
|
|
// Reparse the RC file, rewrite it, and update its timestamp when
|
|
// required.
|
|
|
|
if (!bprocerror && bresdllnamechanged)
|
|
bprocerror = !UpdateRCFile() ;
|
|
|
|
// If required, rename the driver's subtree root directory from
|
|
// "NT5" to "W2K".
|
|
|
|
if (!bprocerror && bfilesinw2ktree)
|
|
bprocerror = !UpdateDrvSubtreeRootName() ;
|
|
|
|
// If everything is ok, update the MDW's version number. (The MDW
|
|
// file is saved later so that this only has to be done once.)
|
|
|
|
if (!bprocerror)
|
|
m_mvMDWVersion.uvernum = MDW_CURRENT_VERSION ;
|
|
} ;
|
|
} ;
|
|
|
|
// *** End of workspace upgrade management code except for possible MDW
|
|
// *** file reload. (See below for details.)
|
|
|
|
// *** Begin workspace related checks and updates
|
|
//
|
|
// o All of the checks for a specific file should be grouped together in
|
|
// one if statement so that only one prompt is required when the file
|
|
// needs to be updated.
|
|
// o The if statement must contain the specific checks and, optionally,
|
|
// test if a related MDW upgrade step has already been performed or
|
|
// if a processing error has already occurred.
|
|
// o If all of the checks/tests are "passed", perform whatever processing
|
|
// is required.
|
|
// o If any updates are performed that require the MDW file to be
|
|
// rewritten, set bupgradeneeded.
|
|
// o Always set bprocerror if an error occurs and tell the user what
|
|
// happened.
|
|
|
|
// Reread the RC file if it has been changed and user oks it.
|
|
|
|
if (!bprocerror && !bresdllnamechanged && RCFileChanged()) {
|
|
cstmp = m_csRCName ;
|
|
cstmp.MakeUpper() ;
|
|
csprompt.Format(IDS_UpdateRCFile, cstmp) ;
|
|
if (AfxMessageBox(csprompt, MB_ICONQUESTION + MB_YESNO) == IDYES) {
|
|
if (!(bprocerror = !UpdateRCFile()))
|
|
bupgradeneeded = true ;
|
|
} ;
|
|
} ;
|
|
|
|
// *** End of workspace related checks and updates
|
|
|
|
// Save any MDW file changes that were made by any of the code above.
|
|
|
|
if (bupgradeneeded && !bprocerror)
|
|
bprocerror = (bool) !CDocument::OnSaveDocument(lpszPathName) ;
|
|
|
|
// Occassionally, one of the changes done above requires the reloading of
|
|
// the driver's MDW file. That is done here. The reasons are listed below.
|
|
// o When the driver's subtree root has been renamed from "NT5" to "W2K",
|
|
// there are still copies of "NT5" in paths and filespecs in class
|
|
// instances all over the place. The easiest way to correct those paths,
|
|
// etc is by reloading the MDW file.
|
|
|
|
if (buserwantstoupgrade && bfilesinw2ktree && !bprocerror)
|
|
if (!CDocument::OnOpenDocument(lpszPathName))
|
|
return FALSE ;
|
|
|
|
// Try to detect if driver files were moved and if they can be found.
|
|
// Continue processing if the files were found or the user wants to
|
|
// continue anyway. Otherwise, cancel the loading of the workspace.
|
|
|
|
if (!VerUpdateFilePaths())
|
|
return FALSE ;
|
|
|
|
// Workspace was loaded so return TRUE.
|
|
// DEAD_BUG: Should I return TRUE even if there was a processing error???
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::RCFileChanged
|
|
|
|
If the MDW version is NOT large enough for this info to be relevant, return
|
|
false. If the version is large enough but m_ctRCFileTimeStamp is
|
|
uninitialized, assert.
|
|
|
|
If the everything is ok, get the timestamp for the RC file and compare it
|
|
with m_ctRCFileTimeStamp. If the RC file has changed, return true.
|
|
Otherwise, return false.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CProjectRecord::RCFileChanged()
|
|
{
|
|
// Return no change if the MDW version is too low.
|
|
|
|
if (m_mvMDWVersion.uvernum < MDW_VER_RC_TIMESTAMP)
|
|
return false ;
|
|
|
|
// Blow if the saved time is uninitialized.
|
|
|
|
ASSERT(m_ctRCFileTimeStamp.GetTime() > 0) ;
|
|
|
|
// Get the timestamp for the RC file, compare it with the time the MDT last
|
|
// modified the file, and return the result.
|
|
|
|
CTime ct ;
|
|
if (!GetRCFileTimeStamp(ct))
|
|
return false ;
|
|
//TRACE("RC timestamp = %s Saved timestamp = %s\n", ct.Format("%c"), m_ctRCFileTimeStamp.Format("%c")) ;
|
|
if (ct > m_ctRCFileTimeStamp)
|
|
return true ;
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::GetRCFileTimeStamp
|
|
|
|
Get the last modified time stamp for this project's RC file and load it into
|
|
the specified parameter. Return true if this succeeds. Otherwise, return
|
|
false.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CProjectRecord::GetRCFileTimeStamp(CTime& ct)
|
|
{
|
|
try {
|
|
// Open the RC file
|
|
|
|
CString csrcfspec(TargetPath(Win2000) + '\\' + m_csRCName) ;
|
|
CFile cfrc(csrcfspec, CFile::modeRead + CFile::shareDenyNone) ;
|
|
|
|
// Get RC file status information
|
|
|
|
CFileStatus cfs ;
|
|
cfrc.GetStatus(cfs) ;
|
|
|
|
// Copy the last modified time stamp into the caller's variable
|
|
|
|
ct = cfs.m_mtime ;
|
|
|
|
// All went well so...
|
|
|
|
return true ;
|
|
}
|
|
catch (CException* pce) {
|
|
pce->ReportError() ;
|
|
pce->Delete() ;
|
|
return false ;
|
|
} ;
|
|
|
|
return false ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::UpdateRCFile
|
|
|
|
This routine is called when it has been determined that the RC file was
|
|
modified outside of the MDT. This routine will reparse the RC file to
|
|
update the internal data structures, merge the new data with the old data,
|
|
and write a new RC file based on the combined information. Then the
|
|
timestamp for the last time the MDT modified the RC file is updated.
|
|
|
|
Return true if all goes well. Otherwise, return false.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CProjectRecord::UpdateRCFile()
|
|
{
|
|
// Build a filespec for the RC file.
|
|
|
|
CString csrcfspec(TargetPath(Win2000) + '\\' + m_csRCName) ;
|
|
|
|
// Reparse the RC file and update internal data structures.
|
|
|
|
if (!m_cdr.ReparseRCFile(csrcfspec))
|
|
return false ;
|
|
|
|
// Write a new RC file base on the updated information.
|
|
|
|
if (!m_cdr.Generate(Win2000, csrcfspec)) {
|
|
AfxMessageBox(IDS_RCWriteError) ;
|
|
return false ; // TODO: Cleanup and backtracking
|
|
} ;
|
|
|
|
// Update the last time the RC file was written by the MDT timestamp.
|
|
|
|
GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
|
|
|
|
// All went well so...
|
|
|
|
return true ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::UpdateDfltCodePage
|
|
|
|
Prompt the user for a default code page and save it. Fail (return) false if
|
|
the user cancels. Return true if all goes well.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CProjectRecord::UpdateDfltCodePage()
|
|
{
|
|
// Display the dialog box to prompt for the code page.
|
|
|
|
CGetDefCodePage dlg ;
|
|
if (dlg.DoModal() == IDCANCEL)
|
|
return false ;
|
|
|
|
// A code page was selected, get it out of the dialog class and save it in
|
|
// this class. Both the cp/translated Far East resource ID and the real
|
|
// CP are saved.
|
|
|
|
SetDefaultCodePage(dlg.GetDefaultCodePage()) ;
|
|
SetDefaultCodePageNum(dlg.GetDefaultCodePageNum()) ;
|
|
|
|
|
|
// All went well so...
|
|
|
|
return true ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::UpdateDrvSubtreeRootName
|
|
|
|
This routine is called when the root of the driver's subtree needs to be
|
|
renamed. Older versions of the MDT would create a directory named "NT5" in
|
|
which to put the driver's files and subdirectories. Now that NT 5.0 has
|
|
been renamed to Windows 2000 the new driver root directory should be called
|
|
"W2K". This routine will rename the driver's "NT5" directory to "W2K".
|
|
Return true if the directory rename is successful. Otherwise, return false.
|
|
|
|
******************************************************************************/
|
|
|
|
bool CProjectRecord::UpdateDrvSubtreeRootName()
|
|
{
|
|
// Isolate the path for the MDW file.
|
|
|
|
int npos = m_csProjFSpec.ReverseFind(_T('\\')) ;
|
|
CString cspath = m_csProjFSpec.Left(npos + 1) ;
|
|
|
|
// Now use the MDW file's path to build the old and new root directory
|
|
// paths.
|
|
|
|
CString csoldpath, csnewpath ;
|
|
csoldpath.LoadString(IDS_OldDriverRootDir) ;
|
|
csoldpath = cspath + csoldpath ;
|
|
csnewpath.LoadString(IDS_NewDriverRootDir) ;
|
|
csnewpath = cspath + csnewpath ;
|
|
|
|
// Rename the directory. Complain and return false if this fails.
|
|
|
|
try {
|
|
if (rename(csoldpath, csnewpath) != 0)
|
|
return false ;
|
|
}
|
|
catch (CException *pce) {
|
|
pce->ReportError() ;
|
|
pce->Delete() ;
|
|
return FALSE ;
|
|
} ;
|
|
|
|
// Update this path so that the RC file checks will work later in the
|
|
// code.
|
|
|
|
m_csW2000Path = csnewpath ;
|
|
// All went well so...
|
|
|
|
return true ;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::OnSaveDocument
|
|
|
|
Before saving the document, rebuild the RC file when needed and check the
|
|
workspace for consistency.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CProjectRecord::OnSaveDocument(LPCTSTR lpszPathName)
|
|
{
|
|
// Check to see if the RC file needs to be rewritten first. If the RC file
|
|
// needs to be rewritten but this operation fails, return false (FAILURE).
|
|
|
|
if (m_bRCModifiedFlag) {
|
|
|
|
// If the workspace has no version information, rewriting the RC file
|
|
// will erase the string table from the file. The user probably
|
|
// won't want to do this. Only continue if he says so.
|
|
|
|
int nqr = IDYES ; // Query result
|
|
if (m_mvMDWVersion.uvernum == MDW_DEFAULT_VERSION) {
|
|
CString csmsg ;
|
|
csmsg.Format(IDS_RCRewriteQuestion, m_cdr.Name(), m_csRCName) ;
|
|
nqr = AfxMessageBox(csmsg, MB_YESNO+MB_ICONQUESTION+MB_DEFBUTTON2) ;
|
|
} ;
|
|
|
|
if (nqr == IDYES) {
|
|
if (!m_cdr.Generate(Win2000, TargetPath(Win2000) + '\\' + m_csRCName)) {
|
|
AfxMessageBox(IDS_RCWriteError) ;
|
|
return FALSE ; // TODO: Cleanup and backtracking
|
|
} ;
|
|
|
|
// Update the last time the RC file was written by the MDT timestamp.
|
|
|
|
GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
|
|
} ;
|
|
m_bRCModifiedFlag = FALSE ;
|
|
} ;
|
|
|
|
// Check the workspace for consistency before continuing. Save, set, and
|
|
// restore the directory around this call.
|
|
|
|
CString cscurdir ;
|
|
::GetCurrentDirectory(512, cscurdir.GetBuffer(512)) ;
|
|
cscurdir.ReleaseBuffer() ;
|
|
SetCurrentDirectory(m_csW2000Path) ;
|
|
BOOL brc = m_cdr.WorkspaceChecker(true) ;
|
|
SetCurrentDirectory(cscurdir) ;
|
|
|
|
// Save the project file's filespec.
|
|
|
|
m_csProjFSpec = lpszPathName ;
|
|
|
|
// Now save the document (workspace) file.
|
|
//
|
|
// NOTE: The value returned is virtually assured to be TRUE. This is
|
|
// done to make sure the document is saved when the user requests
|
|
// it. This has some unwanted side effects that I don't know
|
|
// how to avoid. First, if the save is happening because the
|
|
// document is closing, it will still close even if there are
|
|
// workspace errors that the user wants to see. Second, if the
|
|
// save is happening because the app is closing, the app will
|
|
// still close even if there are workspace errors that the user
|
|
// wants to see.
|
|
// raid 123448
|
|
if (m_mvMDWVersion.uvernum == MDW_VER_FILES_IN_W2K_TREE )
|
|
m_mvMDWVersion.uvernum = MDW_VER_YES_FILE_PATHS ;
|
|
|
|
return CDocument::OnSaveDocument(lpszPathName) ;
|
|
}
|
|
|
|
|
|
CString CProjectRecord::TargetPath(UINT ufFlags) const {
|
|
|
|
switch(ufFlags) {
|
|
case Win95:
|
|
return m_csWin95Path;
|
|
|
|
case WinNT3x:
|
|
return m_csNT3xPath;
|
|
|
|
case WinNT40:
|
|
return m_csNT40Path;
|
|
|
|
case Win2000:
|
|
return m_csW2000Path;
|
|
}
|
|
|
|
AfxThrowNotSupportedException();
|
|
|
|
return m_csWin95Path;
|
|
}
|
|
|
|
// This routine establishes the source RC file's name, and the initial paths
|
|
// for all of the potential targets.
|
|
|
|
void CProjectRecord::SetSourceRCFile(LPCTSTR lpstrSource) {
|
|
m_csSourceRCFile = lpstrSource;
|
|
|
|
m_csW2000Path = m_csNT40Path = m_csNT3xPath = m_csWin95Path =
|
|
m_csSourceRCFile.Left(m_csSourceRCFile.ReverseFind(_T('\\')));
|
|
|
|
// The last path component of the Windows 2000 files' directory, depends on
|
|
// the version of the MDW file.
|
|
|
|
CString cs ;
|
|
if (m_mvMDWVersion.uvernum >= MDW_VER_FILES_IN_W2K_TREE)
|
|
cs.LoadString(IDS_NewDriverRootDir) ;
|
|
else
|
|
cs.LoadString(IDS_OldDriverRootDir) ;
|
|
m_csW2000Path += _T("\\") ;
|
|
m_csW2000Path += cs ;
|
|
|
|
m_csNT40Path += _T("\\NT4");
|
|
m_csNT3xPath += _T("\\NT3");
|
|
|
|
// Trim the path name (including trailing \) to get driver name and RC
|
|
m_csRCName = m_csSourceRCFile.Mid(1 + m_csWin95Path.GetLength());
|
|
if (m_csRCName.Find('.') != -1)
|
|
m_csRCName = m_csRCName.Left(m_csRCName.Find('.'));
|
|
m_cdr.Rename(m_csRCName);
|
|
m_csRCName += _T(".RC");
|
|
m_ufStatus = 0;
|
|
}
|
|
|
|
// This is a helper function- it validates a new path name, and if it is
|
|
// valid, returns TRUE, and stores it in the given CString;
|
|
|
|
static BOOL ValidatePath(CString& csTarget, LPCTSTR lpstrPath) {
|
|
|
|
if (!csTarget.CompareNoCase(lpstrPath)) {
|
|
// Trivial- no change = success!
|
|
return TRUE;
|
|
}
|
|
|
|
// Determine the current directory, so we don't lose it.
|
|
|
|
CString csCurrentDirectory, csNewOne;
|
|
|
|
GetCurrentDirectory(MAX_PATH, csCurrentDirectory.GetBuffer(MAX_PATH));
|
|
|
|
csCurrentDirectory.ReleaseBuffer();
|
|
|
|
// Attempt to switch to the new directory. If we succeed, we're done.
|
|
|
|
if (SetCurrentDirectory(lpstrPath)) {
|
|
GetCurrentDirectory(MAX_PATH, csTarget.GetBuffer(MAX_PATH));
|
|
csTarget.ReleaseBuffer();
|
|
|
|
SetCurrentDirectory(csCurrentDirectory);
|
|
return TRUE;
|
|
}
|
|
|
|
// Attempt to create the new directory. If this succeeds, delete the
|
|
// directory, and note our success our failure, either way.
|
|
|
|
if (CreateDirectory(lpstrPath, NULL)) {
|
|
SetCurrentDirectory(lpstrPath);
|
|
GetCurrentDirectory(MAX_PATH, csTarget.GetBuffer(MAX_PATH));
|
|
csTarget.ReleaseBuffer();
|
|
|
|
SetCurrentDirectory(csCurrentDirectory);
|
|
RemoveDirectory(csTarget);
|
|
return TRUE;
|
|
}
|
|
return FALSE; // Nothing worked, give it up...
|
|
}
|
|
|
|
// The following loads all of the driver resources.
|
|
|
|
BOOL CProjectRecord::LoadResources() {
|
|
|
|
if (!m_cdr.Load(*this))
|
|
return FALSE;
|
|
|
|
m_ufStatus |= UniToolRun;
|
|
m_ufStatus &= ~(ConversionsDone | NTGPCDone);
|
|
SetModifiedFlag();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// The following member validates a new target path name.
|
|
|
|
BOOL CProjectRecord::SetPath(UINT ufTarget, LPCTSTR lpstrPath) {
|
|
|
|
switch (ufTarget) {
|
|
case Win2000:
|
|
m_ufStatus&= ~ConversionsDone;
|
|
return ValidatePath(m_csW2000Path, lpstrPath);
|
|
|
|
case WinNT40:
|
|
m_ufStatus&= ~(ConversionsDone | NTGPCDone);
|
|
return ValidatePath(m_csNT40Path, lpstrPath);
|
|
|
|
case WinNT3x:
|
|
m_ufStatus&= ~(ConversionsDone | NTGPCDone);
|
|
return ValidatePath(m_csNT3xPath, lpstrPath);
|
|
}
|
|
|
|
_ASSERTE(FALSE); // This should never happen!
|
|
return FALSE;
|
|
}
|
|
|
|
// When we create a new document (aka project, aka driver), we invoke the
|
|
// new project wizard
|
|
|
|
BOOL CProjectRecord::OnNewDocument() {
|
|
if (!CDocument::OnNewDocument())
|
|
return FALSE;
|
|
// raid 104822 : add real new document : kill below
|
|
// Invoke the wizard.
|
|
CNewConvertWizard cnpw(*this);
|
|
|
|
// Initialize the workspace's version number.
|
|
|
|
m_mvMDWVersion.uvernum = MDW_CURRENT_VERSION ;
|
|
|
|
return cnpw.DoModal() == ID_WIZFINISH;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CProjectRecord serialization
|
|
//
|
|
// See "MDT Workspace Versioning" in projrec.h for more information.
|
|
//
|
|
|
|
void CProjectRecord::Serialize(CArchive& car)
|
|
{
|
|
// The first thing to do when storing is to build and write out the MDW
|
|
// version information. Only do this when the workspace's version number
|
|
// is not MDW_DEFAULT_VERSION; IE, the WS has a version number.
|
|
|
|
if (car.IsStoring()) {
|
|
if (m_mvMDWVersion.uvernum > MDW_DEFAULT_VERSION) {
|
|
StringCchCopyA(m_mvMDWVersion.acvertag, CCHOF(m_mvMDWVersion.acvertag), VERTAGSTR) ;
|
|
car.Write(&m_mvMDWVersion, MDWVERSIONSIZE) ;
|
|
} ;
|
|
|
|
// When loading, CProjectRecord::OnOpenDocument() initializes and uses
|
|
// m_mvMDWVersion. Then the file is closed. The file is reopened at the
|
|
// beginning by CDocument::OnOpenDocument(). This means that when the file
|
|
// contains version info, we must skip passed it so that the rest of the
|
|
// serialization process can continue as expected.
|
|
|
|
} else if (m_mvMDWVersion.uvernum >= MDW_FIRST_UPGRADABLE_VER)
|
|
car.Read(&m_mvMDWVersion, MDWVERSIONSIZE) ;
|
|
|
|
// m_csW2000Path needs to be loaded before m_cdr.Serialize() is called
|
|
// so that the string can be used in the function and/or the routines it
|
|
// calls.
|
|
// raid 123448
|
|
if (m_mvMDWVersion.uvernum < MDW_VER_YES_FILE_PATHS) {
|
|
m_csW2000Path = car.GetFile()->GetFilePath() ;
|
|
m_csW2000Path = m_csW2000Path.Left(m_csW2000Path.ReverseFind(_T('\\'))) ;
|
|
|
|
// The last path component depends on the version of the MDW file.
|
|
|
|
CString cs ;
|
|
if (m_mvMDWVersion.uvernum >= MDW_VER_FILES_IN_W2K_TREE)
|
|
cs.LoadString(IDS_NewDriverRootDir) ;
|
|
else
|
|
cs.LoadString(IDS_OldDriverRootDir) ;
|
|
m_csW2000Path += _T("\\") ; // b. 2 lines : Raid 123448 !;; can cancel W2K dir.
|
|
m_csW2000Path += cs ;
|
|
} ;
|
|
|
|
// Now that versioning is done, get on with saving or restoring the
|
|
// workspace's state.
|
|
|
|
m_cdr.Serialize(car) ;
|
|
if (car.IsStoring()) {
|
|
if (m_mvMDWVersion.uvernum >= MDW_VER_YES_FILE_PATHS) // Raid 123448
|
|
car << m_csW2000Path ;
|
|
car << m_csNT40Path << m_csNT3xPath << m_csWin95Path <<
|
|
m_csSourceRCFile << m_ufTargets << m_ufStatus << m_csRCName ;
|
|
if (m_mvMDWVersion.uvernum >= MDW_VER_DEFAULT_CPAGE)
|
|
car << m_dwDefaultCodePage ;
|
|
if (m_mvMDWVersion.uvernum >= MDW_VER_RC_TIMESTAMP)
|
|
car << m_ctRCFileTimeStamp ;
|
|
} else {
|
|
if (m_mvMDWVersion.uvernum >= MDW_VER_YES_FILE_PATHS)
|
|
car >> m_csW2000Path ;
|
|
car >> m_csNT40Path >> m_csNT3xPath >> m_csWin95Path >>
|
|
m_csSourceRCFile >> m_ufTargets >> m_ufStatus >> m_csRCName ;
|
|
if (m_mvMDWVersion.uvernum >= MDW_VER_DEFAULT_CPAGE) {
|
|
car >> m_dwDefaultCodePage ;
|
|
|
|
// Use m_dwDefaultCodePage to compute m_dwDefaultCodePageNum so
|
|
// that a new MDW version is NOT needed to support
|
|
// m_dwDefaultCodePageNum. (See the declaration of these variables
|
|
// for more info.)
|
|
|
|
short scp = (short) ((WORD) m_dwDefaultCodePage) ;
|
|
switch (scp) {
|
|
case -10:
|
|
m_dwDefaultCodePageNum = 950 ;
|
|
break ;
|
|
case -16:
|
|
m_dwDefaultCodePageNum = 936 ;
|
|
break ;
|
|
case -17:
|
|
m_dwDefaultCodePageNum = 932 ;
|
|
break ;
|
|
case -18:
|
|
m_dwDefaultCodePageNum = 949 ;
|
|
break ;
|
|
default:
|
|
m_dwDefaultCodePageNum = m_dwDefaultCodePage ;
|
|
break ;
|
|
} ;
|
|
} ;
|
|
if (m_mvMDWVersion.uvernum >= MDW_VER_RC_TIMESTAMP)
|
|
car >> m_ctRCFileTimeStamp ;
|
|
}
|
|
|
|
|
|
// Last, tell the user that the driver in this workspace should be
|
|
// reconverted when there is no version information in the MDW file.
|
|
// Only do this when loading.
|
|
|
|
if (!car.IsStoring() && m_mvMDWVersion.uvernum == MDW_DEFAULT_VERSION) {
|
|
CString csmsg ;
|
|
csmsg.Format(IDS_NoVersionError, m_cdr.Name()) ;
|
|
AfxMessageBox(csmsg, MB_ICONEXCLAMATION) ;
|
|
} ;
|
|
}
|
|
|
|
|
|
// Private Worker Routine- this establishes a directory, by first attempting
|
|
// to go to it, then creating it if that failes. The current directory is
|
|
// preserved.
|
|
|
|
static BOOL Establish(CString csNew) {
|
|
CString csCurrent;
|
|
|
|
GetCurrentDirectory(MAX_PATH, csCurrent.GetBuffer(MAX_PATH));
|
|
csCurrent.ReleaseBuffer();
|
|
|
|
if (SetCurrentDirectory(csNew)) {
|
|
SetCurrentDirectory(csCurrent);
|
|
return TRUE;
|
|
}
|
|
|
|
return CreateDirectory(csNew, NULL);
|
|
}
|
|
|
|
// Private worker routine. This establishes the directory structure given it,
|
|
// consisting of a named route, and two branches.
|
|
|
|
static BOOL CreateStructure(const CString& csRoot, LPCTSTR lpstrFont,
|
|
LPCTSTR lpstrMap) {
|
|
return Establish(csRoot) && Establish(csRoot + '\\' + lpstrFont) &&
|
|
Establish(csRoot + '\\' + lpstrMap);
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::BuildStructure
|
|
|
|
This builds the directory structure needed for all conversion targets. This
|
|
is done before files are generated so that the renaming calls in many of the
|
|
project nodes do not fail.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CProjectRecord::BuildStructure(unsigned uVersion) {
|
|
|
|
switch (uVersion) {
|
|
|
|
case Win2000:
|
|
|
|
return CreateStructure(TargetPath(Win2000), _T("UFM"), _T("GTT"));
|
|
|
|
case WinNT40:
|
|
|
|
return CreateStructure(TargetPath(WinNT40), _T("IFI"), _T("RLE"));
|
|
|
|
case WinNT3x:
|
|
|
|
return CreateStructure(TargetPath(WinNT3x), _T("IFI"), _T("RLE"));
|
|
}
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::GenerateTargets
|
|
|
|
This one is a workhorse- it generates all of the files needed for all of the
|
|
enabled targets, using the Win 3.x files as a base, with the exception of the
|
|
NT GPC extensions, which require an interactive step.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CProjectRecord::GenerateTargets(WORD wfGPDConvert)
|
|
{
|
|
int nerrorid ; // Error message ID returned by some routines
|
|
|
|
// Generate the files needed for Win2K
|
|
|
|
if (!CreateStructure(TargetPath(Win2000), _TEXT("UFM"), _TEXT("GTT")))
|
|
return FALSE; // TODO: Feedback
|
|
|
|
m_cdr.ForceCommonRC(FALSE); // Don't use common.rc at all
|
|
|
|
// Find and remove the standard include files from the array of include
|
|
// files. This will keep them from being added to the RC file twice.
|
|
|
|
CString cs ;
|
|
cs.LoadString(IDS_StdIncludeFile1) ;
|
|
m_cdr.RemUnneededRCInclude(cs) ;
|
|
if (wfGPDConvert > 1) {
|
|
cs.LoadString(IDS_StdIncludeFile2) ;
|
|
m_cdr.RemUnneededRCInclude(cs) ;
|
|
} ;
|
|
cs.LoadString(IDS_StdIncludeFile3) ;
|
|
m_cdr.RemUnneededRCInclude(cs) ;
|
|
cs.LoadString(IDS_StdIncludeFile4) ;
|
|
m_cdr.RemUnneededRCInclude(cs) ;
|
|
cs.LoadString(IDS_StdIncludeFile5) ;
|
|
m_cdr.RemUnneededRCInclude(cs) ;
|
|
cs.LoadString(IDS_OldIncludeFile1) ;
|
|
m_cdr.RemUnneededRCInclude(cs) ;
|
|
|
|
// Generate the RC file
|
|
|
|
if (!m_cdr.Generate(Win2000, TargetPath(Win2000) + '\\' + m_csRCName))
|
|
return FALSE; // TODO: Cleanup and feedback
|
|
|
|
// Update the last time the RC file was written by the MDT timestamp.
|
|
|
|
GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
|
|
|
|
// Generate the GTT files
|
|
|
|
#if 0
|
|
for (unsigned u = 0; u < m_cdr.MapCount(); u++) {
|
|
|
|
CString csfspec ;
|
|
try {
|
|
csfspec = m_cdr.GlyphTable(u).FileName() ;
|
|
CFile cfGTT(csfspec,
|
|
CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);
|
|
|
|
if (!m_cdr.GlyphTable(u).Generate(cfGTT)) {
|
|
m_cdr.LogConvInfo(IDS_FileWriteError, 1, &csfspec) ;
|
|
return FALSE ;
|
|
} ;
|
|
}
|
|
catch (CException *pce) {
|
|
pce -> ReportError();
|
|
pce -> Delete();
|
|
m_cdr.LogConvInfo(IDS_FileWriteError, 1, &csfspec) ;
|
|
return FALSE;
|
|
}
|
|
}
|
|
#else
|
|
unsigned u ;
|
|
#endif
|
|
|
|
// Generate the UFM files
|
|
|
|
CGlyphMap* pcgm ;
|
|
for (u = 0; u < m_cdr.FontCount(); u++) {
|
|
CFontInfo& cfi = m_cdr.Font(u) ;
|
|
|
|
// Load the UFM's PFM if it hasn't been loaded already. This is done
|
|
// here to get possible GTT mapping info that is used if a GTT must be
|
|
// built for this UFM. This shouldn't fail. If it does fail, the
|
|
// conversion cannot continue.
|
|
|
|
if (!cfi.MapPFM()) {
|
|
CString csfspec ;
|
|
csfspec = cfi.FileName() ;
|
|
m_cdr.LogConvInfo(IDS_UFMGenError, 1, &csfspec) ;
|
|
return FALSE;
|
|
} ;
|
|
|
|
// Map the UFM -> GTT, so we can convert the UFM
|
|
//
|
|
// DEAD_BUG: The code page field in the font class instances has not
|
|
// been set yet so send 0 instead. This might be fixable.
|
|
|
|
/* res_PFMHEADER *pPFM = (res_PFMHEADER *) cfi.m_cbaPFM.GetData();
|
|
|
|
BYTE dfCharSet = pPFM ->dfCharSet;
|
|
WORD CharSetCodePage = 0;
|
|
switch (dfCharSet) {
|
|
case SHIFTJIS_CHARSET:
|
|
CharSetCodePage = 932;
|
|
break;
|
|
case GB2312_CHARSET:
|
|
CharSetCodePage = 936;
|
|
break;
|
|
case HANGEUL_CHARSET:
|
|
case JOHAB_CHARSET:
|
|
CharSetCodePage = 936;
|
|
break;
|
|
case CHINESEBIG5_CHARSET:
|
|
CharSetCodePage = 950;
|
|
break;
|
|
}
|
|
*/
|
|
//TRACE("*** GetFirstPFM() = %d\t\tGetLastPFM() = %d\n", cfi.GetFirstPFM(), cfi.GetLastPFM()) ;
|
|
pcgm = CGlyphMap::Public(cfi.Translation(), 0, GetDefaultCodePage(),
|
|
cfi.GetFirstPFM(), cfi.GetLastPFM()) ;
|
|
if (pcgm)
|
|
cfi.SetTranslation(pcgm) ;
|
|
else
|
|
for (unsigned uGTT = 0; uGTT < m_cdr.MapCount(); uGTT++)
|
|
if (cfi.Translation() ==
|
|
((WORD) m_cdr.GlyphTable(uGTT).nGetRCID())) {
|
|
cfi.SetTranslation(&m_cdr.GlyphTable(uGTT));
|
|
break;
|
|
}
|
|
|
|
// Log an error if the UFM could not be generated and stop. Continuing
|
|
// could cause things like the RC file and Workspace View to be wrong.
|
|
// In addition, delete any partially generated UFM file.
|
|
|
|
if ((nerrorid = cfi.Generate(cfi.FileName())) != 0) {
|
|
CString csfspec ;
|
|
csfspec =
|
|
(nerrorid == IDS_BadCTTID) ? cfi.SourceName() : cfi.FileName() ;
|
|
m_cdr.LogConvInfo(nerrorid, 1, &csfspec) ;
|
|
try {
|
|
CFile::Remove(cfi.FileName()) ;
|
|
}
|
|
catch(CFileException* pce) {
|
|
pce = pce ;
|
|
}
|
|
return FALSE;
|
|
} ;
|
|
}
|
|
|
|
// Generate the GPD files
|
|
|
|
if (!m_cdr.ConvertGPCData(*this, wfGPDConvert))
|
|
return FALSE; // Error will already have been reported to user.
|
|
|
|
// Simplest case is no NT versions selected. By definition, we are done.
|
|
|
|
if (!IsTargetEnabled(WinNT40 | WinNT3x)) {
|
|
m_ufStatus |= ConversionsDone;
|
|
return TRUE;
|
|
}
|
|
|
|
// Generate the files needed for NT 4.0
|
|
|
|
if (IsTargetEnabled(WinNT40)) {
|
|
if (!CreateStructure(TargetPath(WinNT40), _TEXT("IFI"), _TEXT("RLE")))
|
|
return FALSE; // TODO: Feedback
|
|
|
|
// Generate the RC file
|
|
if (!m_cdr.Generate(WinNT40, TargetPath(WinNT40) + '\\' + m_csRCName))
|
|
return FALSE; // TODO: Cleanup and feedback
|
|
|
|
// Update the last time the RC file was written by the MDT timestamp.
|
|
|
|
GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
|
|
|
|
// Copy the GPC file
|
|
if (!CopyFile(TargetPath(Win95) + m_cdr.GPCName(0),
|
|
TargetPath(WinNT40) + m_cdr.GPCName(0), FALSE))
|
|
return FALSE; // TODO: Cleanup and feedback
|
|
|
|
// Generate the RLE files
|
|
|
|
for (u = 0; u < m_cdr.MapCount(); u++) {
|
|
CString csName = TargetPath(WinNT40) + _TEXT("\\RLE\\") +
|
|
m_cdr.GlyphTable(u).Name() + _TEXT(".RLE");
|
|
|
|
CFile cfRLE;
|
|
|
|
if (!cfRLE.Open(csName,
|
|
CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive))
|
|
return FALSE; // As usal, TODO: Feedback...
|
|
|
|
if (!m_cdr.GlyphTable(u).RLE(cfRLE))
|
|
return FALSE; // TODO: Ditto
|
|
}
|
|
|
|
// Generate the IFI files
|
|
for (u = 0; u < m_cdr.OriginalFontCount(); u++) {
|
|
CString csName = TargetPath(WinNT40) + _TEXT("\\IFI\\") +
|
|
m_cdr.Font(u).Name() + _TEXT(".IFI");
|
|
if (!m_cdr.Font(u).Generate(csName))
|
|
return FALSE; // TODO: Ditto
|
|
}
|
|
}
|
|
|
|
// Generate the files needed for NT 3.x
|
|
|
|
if (IsTargetEnabled(WinNT3x)) {
|
|
if (!CreateStructure(TargetPath(WinNT3x), _TEXT("IFI"), _TEXT("RLE")))
|
|
return FALSE; // TODO: Feedback
|
|
|
|
// Generate the RC file
|
|
if (!m_cdr.Generate(WinNT3x, TargetPath(WinNT3x) + '\\' + m_csRCName))
|
|
return FALSE; // TODO: Cleanup and feedback
|
|
|
|
// Update the last time the RC file was written by the MDT timestamp.
|
|
|
|
GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
|
|
|
|
// Copy the GPC file
|
|
if (!CopyFile(TargetPath(Win95) + m_cdr.GPCName(0),
|
|
TargetPath(WinNT3x) + m_cdr.GPCName(0), FALSE))
|
|
return FALSE; // TODO: Cleanup and feedback
|
|
|
|
// Generate the RLE files
|
|
|
|
for (u = 0; u < m_cdr.MapCount(); u++) {
|
|
CString csName = TargetPath(WinNT40) + _TEXT("\\RLE\\") +
|
|
m_cdr.GlyphTable(u).Name() + _TEXT(".RLE");
|
|
|
|
CFile cfRLE;
|
|
|
|
if (!cfRLE.Open(csName,
|
|
CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive))
|
|
return FALSE; // As usal, TODO: Feedback...
|
|
|
|
if (!m_cdr.GlyphTable(u).RLE(cfRLE))
|
|
return FALSE; // TODO: Ditto
|
|
}
|
|
|
|
// Generate the IFI files
|
|
for (u = 0; u < m_cdr.OriginalFontCount(); u++) {
|
|
CString csName = TargetPath(WinNT3x) + _TEXT("\\IFI\\") +
|
|
m_cdr.Font(u).Name() + _TEXT(".IFI");
|
|
if (!m_cdr.Font(u).Generate(csName))
|
|
return FALSE; // TODO: Ditto
|
|
}
|
|
}
|
|
|
|
m_ufStatus |= ConversionsDone;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::GPDConversionCheck
|
|
|
|
If any of the GPD files have unresolved errors from the conversion process,
|
|
it will open all of them, if the user asks, so they can fix the problem(s)
|
|
forthwith- or leave them for the next time the workspace is edited.
|
|
|
|
******************************************************************************/
|
|
|
|
void CProjectRecord::GPDConversionCheck(BOOL bReportSuccess) {
|
|
CUIntArray cuaSuspects;
|
|
|
|
for (unsigned u = 0; u < m_cdr.Models(); u ++)
|
|
if (m_cdr.Model(u).HasErrors())
|
|
cuaSuspects.Add(u);
|
|
|
|
if (!cuaSuspects.GetSize()) {
|
|
if (bReportSuccess)
|
|
AfxMessageBox(IDS_NoErrorsAnywhere);
|
|
return;
|
|
}
|
|
|
|
if (AfxMessageBox(IDS_ConversionErrors, MB_YESNO) == IDNO)
|
|
return;
|
|
|
|
while (cuaSuspects.GetSize()) {
|
|
m_cdr.Model(cuaSuspects[0]).Edit();
|
|
cuaSuspects.RemoveAt(0);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CProjectRecord diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CProjectRecord::AssertValid() const {
|
|
CDocument::AssertValid();
|
|
}
|
|
|
|
void CProjectRecord::Dump(CDumpContext& dc) const {
|
|
CDocument::Dump(dc);
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CProjectRecord commands
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// VerUpdateFilePaths - Verify and update paths/filespecs in workspace file
|
|
//
|
|
// Use the information read from the workspace file to see if the Win2K RC
|
|
// file is where it is supposed to be. If it is, assume that all is ok. If
|
|
// not, assume that either the workspace (.MDW) file or the files reference by
|
|
// the workspace file have moved.
|
|
//
|
|
// Tell the user and ask if he wants to locate the RC file for us. If yes,
|
|
// prompt for and verify the new RC file path. Reprompt if it is wrong. If
|
|
// the user cancels, exit.
|
|
//
|
|
// Once a path to the RC file is verified, use the file's grandparent
|
|
// directory to update the paths used for all UFMs, GTTs, GPDs, and the rest
|
|
// of the paths read from the MDW file and managed by this document. The
|
|
// grandparent directory is used because it is needed to correct some of
|
|
// the filespecs saved in the workspace. All of the Win2K files are
|
|
// expected to be in directory(s) beneath the grandparent directory. Lastly,
|
|
// set the document's modified flag so that the updated paths can be saved
|
|
// later.
|
|
//
|
|
// void CProjectRecord::VerUpdateFilePaths()
|
|
//
|
|
// Args:
|
|
// None
|
|
//
|
|
// Returns
|
|
// Nothing
|
|
//
|
|
// Notes
|
|
// First, the Workspace View Add/Insert/Clone/Copy context menu commands
|
|
// must make sure that the destination files for these commands always
|
|
// end up in the appropriate workspace directories for this scheme to
|
|
// work.
|
|
//
|
|
// Second, if it is decided that more than one root directory is needed
|
|
// for a workspace, this function will have to prompt for multiple
|
|
// directories and then use the appropriate directory to update the paths
|
|
// for UFMs, GTTs, GPDs, and the rest of the paths referenced by the
|
|
// workspace file.
|
|
//
|
|
// Third, if this tool is ever enhanced to handle conversions to anything
|
|
// other than Win2K drivers, this routine will need to be enhanced to
|
|
// handle those cases too.
|
|
//
|
|
|
|
bool CProjectRecord::VerUpdateFilePaths()
|
|
{
|
|
CFileFind cff ; // Used to find the RC file
|
|
bool borig = true ; // True iff the original RC file was found
|
|
BOOL bfound ; // True iff an RC file was found
|
|
CString csprompt ; // Used to prompt the user
|
|
int nresponse = 0 ; // User's response to prompt
|
|
|
|
// Make a copy of the file path and build a filespec for the Win2000 RC file
|
|
|
|
CString csrcpath(m_csW2000Path) ;
|
|
CString csrcfspec(csrcpath) ;
|
|
if (csrcfspec.Right(1) != _T('\\'))
|
|
csrcfspec += _T("\\") ;
|
|
csrcfspec += m_csRCName ;
|
|
|
|
// Keep checking for the existence of the RC file and prompting the user
|
|
// until the file is found or the user doesn't want to continue any more.
|
|
|
|
while (true) {
|
|
// If the Win2000 RC file exists, we're done so exit.
|
|
|
|
if (bfound = cff.FindFile(csrcfspec))
|
|
break ;
|
|
|
|
// Explain the situation to the user and ask if they want to tell us where
|
|
// the file is. (Only do this the first time.)
|
|
|
|
if (borig) {
|
|
csprompt.Format(IDS_RCFindPrompt, DriverName(), csrcpath) ;
|
|
nresponse = AfxMessageBox(csprompt, MB_YESNOCANCEL+MB_ICONQUESTION);
|
|
if (nresponse != IDYES)
|
|
break ;
|
|
} ;
|
|
|
|
// Prompt the user for a new RC file
|
|
|
|
CFileDialog cfd(TRUE, _T(".RC"), m_csRCName,
|
|
OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
|
|
_T("RC File (*.rc)|*.rc||")) ;
|
|
cfd.m_ofn.lpstrInitialDir = csrcpath ;
|
|
if (cfd.DoModal() != IDOK)
|
|
break ;
|
|
|
|
// Prepare to check the new filespec
|
|
|
|
csrcfspec = cfd.GetPathName() ;
|
|
csrcpath = csrcfspec.Left(csrcfspec.ReverseFind(_T('\\'))) ;
|
|
borig = false ;
|
|
} ;
|
|
|
|
// If the original RC file was found or the user did not provide a new
|
|
// filespec or the user cancels, just return without changing anything.
|
|
// Return false if the user cancelled.
|
|
|
|
if (borig || !bfound)
|
|
return (nresponse != IDCANCEL) ;
|
|
|
|
// When the MDT performs a conversion, the resulting files are put into
|
|
// a directory tree with a root directory like NT4 or Win2K by default. The
|
|
// directory layout and files from that root directory on down are expected
|
|
// to be maintained. The RC file is expected to be in that root directory,
|
|
// too. Therefore, the paths in this workspace up to BUT NOT INCLUDING that
|
|
// root directory must be updated; ie, the path for the RC file's
|
|
// grandparent directory. So, get the new path for the grandparent
|
|
// directory.
|
|
|
|
CString csrcnewgrand(csrcpath) ;
|
|
csrcnewgrand = csrcnewgrand.Left(csrcnewgrand.ReverseFind(_T('\\')) + 1) ;
|
|
|
|
// As a safety measure, existing paths are only updated if they begin with
|
|
// the RC file's OLD grandparent directory.
|
|
|
|
CString csrcoldgrand(m_csW2000Path) ;
|
|
csrcoldgrand = csrcoldgrand.Left(csrcoldgrand.ReverseFind(_T('\\')) + 1) ;
|
|
int noldlen = csrcoldgrand.GetLength() ;
|
|
|
|
// Variables used to process arrays of objects and their paths
|
|
|
|
unsigned u ;
|
|
unsigned unumobjs ;
|
|
CString cspath ;
|
|
|
|
// Update UFM filespecs
|
|
|
|
for (unumobjs = m_cdr.FontCount(), u = 0 ; u < unumobjs ; u++) {
|
|
cspath = m_cdr.Font(u).GetPath() ;
|
|
if (cspath.Find(csrcoldgrand) == 0) {
|
|
cspath = csrcnewgrand + cspath.Right(cspath.GetLength() - noldlen) ;
|
|
m_cdr.Font(u).SetPath(cspath) ;
|
|
} ;
|
|
} ;
|
|
|
|
// Update GTT filespecs
|
|
|
|
for (unumobjs = m_cdr.MapCount(), u = 0 ; u < unumobjs ; u++) {
|
|
cspath = m_cdr.GlyphTable(u).GetPath() ;
|
|
if (cspath.Find(csrcoldgrand) == 0) {
|
|
cspath = csrcnewgrand + cspath.Right(cspath.GetLength() - noldlen) ;
|
|
m_cdr.GlyphTable(u).SetPath(cspath) ;
|
|
} ;
|
|
} ;
|
|
|
|
// Update GPD filespecs
|
|
|
|
for (unumobjs = m_cdr.Models(), u = 0 ; u < unumobjs ; u++) {
|
|
cspath = m_cdr.Model(u).GetPath() ;
|
|
if (cspath.Find(csrcoldgrand) == 0) {
|
|
cspath = csrcnewgrand + cspath.Right(cspath.GetLength() - noldlen) ;
|
|
m_cdr.Model(u).SetPath(cspath) ;
|
|
} ;
|
|
} ;
|
|
|
|
// Now, update the paths that are in the workspace.
|
|
|
|
if (m_csSourceRCFile.Find(csrcoldgrand) == 0)
|
|
m_csSourceRCFile = csrcnewgrand + m_csSourceRCFile.Right(m_csSourceRCFile.GetLength() - noldlen) ;
|
|
if (m_csW2000Path.Find(csrcoldgrand) == 0)
|
|
m_csW2000Path = csrcnewgrand + m_csW2000Path.Right(m_csW2000Path.GetLength() - noldlen) ;
|
|
if (m_csNT40Path.Find(csrcoldgrand) == 0)
|
|
m_csNT40Path = csrcnewgrand + m_csNT40Path.Right(m_csNT40Path.GetLength() - noldlen) ;
|
|
if (m_csNT3xPath.Find(csrcoldgrand) == 0)
|
|
m_csNT3xPath = csrcnewgrand + m_csNT3xPath.Right(m_csNT3xPath.GetLength() - noldlen) ;
|
|
if (m_csWin95Path.Find(csrcoldgrand) == 0)
|
|
m_csWin95Path = csrcnewgrand + m_csWin95Path.Right(m_csWin95Path.GetLength() - noldlen) ;
|
|
|
|
// Lastly, mark the workspace file as being dirty so that it can be saved
|
|
// later.
|
|
|
|
SetModifiedFlag() ;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
CProjectRecord::SaveModified
|
|
|
|
This overridable function is used to make sure that the "subdocuments"
|
|
associated with this document that are NOT file based are saved before this
|
|
document closes. The normal saving mechanisms employed by the MFC document
|
|
view architectured don't always work in these cases. The work required to
|
|
save each subdocument is subdocument dependent. The current list of
|
|
subdocuments that fall into this category are:
|
|
|
|
o String Table Editor - The editor just modifies the string table portion of
|
|
the RC file that is associated with the documented managed by this
|
|
instance of CProjectRecord. If the editor exists, tell it to save the
|
|
string table. If this succeeds, the document's save flags will be updated
|
|
when needed. If this fails, return FALSE so that the calling function
|
|
will know that this document should not be closed.
|
|
|
|
******************************************************************************/
|
|
|
|
BOOL CProjectRecord::SaveModified()
|
|
{
|
|
// Save the string table if it was modified.
|
|
//
|
|
// Begin by getting a pointer to the string editor for this project.
|
|
|
|
CMDIChildWnd* pcmcw = m_cdr.GetStringsNode()->GetEditor() ;
|
|
|
|
// If there is a string editor, call it to save the string table.
|
|
|
|
if (pcmcw != NULL) {
|
|
CStringEditorDoc* pcsed = (CStringEditorDoc*) pcmcw->GetActiveDocument() ;
|
|
|
|
// Return FALSE (do not close this document) if the string table needed
|
|
// to be saved but it couldn't be saved because it is invalid.
|
|
|
|
if (!pcsed->SaveStringTable()) {
|
|
pcmcw->SetFocus() ;
|
|
return FALSE ;
|
|
} ;
|
|
} ;
|
|
|
|
return CDocument::SaveModified();
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGetDefCodePage dialog
|
|
|
|
|
|
CGetDefCodePage::CGetDefCodePage(CWnd* pParent /*=NULL*/)
|
|
: CDialog(CGetDefCodePage::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(CGetDefCodePage)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
}
|
|
|
|
|
|
void CGetDefCodePage::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CGetDefCodePage)
|
|
DDX_Control(pDX, IDC_CodePageList, m_clbCodePages);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CGetDefCodePage, CDialog)
|
|
//{{AFX_MSG_MAP(CGetDefCodePage)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGetDefCodePage message handlers
|
|
|
|
BOOL CGetDefCodePage::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
// Find out how many code pages are installed on the machine.
|
|
|
|
CCodePageInformation ccpi ;
|
|
unsigned unumcps = ccpi.InstalledCount() ;
|
|
|
|
// Get the installed code page numbers and load them into the code page
|
|
// list box.
|
|
|
|
DWORD dwcp, dwdefcp ;
|
|
dwdefcp = GetACP() ;
|
|
TCHAR accp[32] ;
|
|
int n2 ; ;
|
|
for (unsigned u = 0 ; u < unumcps ; u++) {
|
|
dwcp = ccpi.Installed(u) ;
|
|
|
|
StringCchPrintf(accp, CCHOF(accp), _T("%5d"), dwcp) ;
|
|
|
|
n2 = m_clbCodePages.AddString(accp) ;
|
|
if (dwcp == dwdefcp)
|
|
m_clbCodePages.SetCurSel(n2) ;
|
|
} ;
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
|
|
void CGetDefCodePage::OnOK()
|
|
{
|
|
// Get the index of the currently selected list box item.
|
|
|
|
int nsel ;
|
|
if ((nsel = m_clbCodePages.GetCurSel()) == LB_ERR) {
|
|
AfxMessageBox(IDS_MustSelCP, MB_ICONINFORMATION) ;
|
|
return ;
|
|
} ;
|
|
|
|
// Get the selected list box string, turn it into a number, and save it.
|
|
|
|
CString cs ;
|
|
m_clbCodePages.GetText(nsel, cs) ;
|
|
|
|
// Turn the string into a number and convert the number into the
|
|
// corresponding predefined GTT code for Far East code pages when
|
|
// applicable.
|
|
|
|
short scp = (short) atoi(cs) ;
|
|
m_dwDefaultCodePageNum = (DWORD) scp ; // Save real CP number first
|
|
switch (scp) {
|
|
case 932:
|
|
scp = -17 ;
|
|
break ;
|
|
case 936:
|
|
scp = -16 ;
|
|
break ;
|
|
case 949:
|
|
scp = -18 ;
|
|
break ;
|
|
case 950:
|
|
scp = -10 ;
|
|
break ;
|
|
} ;
|
|
DWORD dwcp = (DWORD) scp ;
|
|
|
|
m_dwDefaultCodePage = dwcp ;
|
|
|
|
// All went well so...
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
|
|
BOOL CProjectRecord::CreateFromNew(CStringArray &csaUFMFiles, CStringArray &csaGTTFiles, CString &csGpdPath, CString &csModelName, CString &csRC,CStringArray& csaRcid)
|
|
{
|
|
|
|
|
|
// customize GPD keyword value
|
|
CModelData cmd ;
|
|
CString cspath, csmodel, csdll ;
|
|
cspath = csGpdPath.Mid(csGpdPath.ReverseFind('\\') + 1 ) ;
|
|
|
|
cmd.SetKeywordValue(csGpdPath,_T("*GPDFileName"),cspath);
|
|
cmd.SetKeywordValue(csGpdPath,_T("*ModelName"),csModelName) ;
|
|
cmd.SetKeywordValue(csGpdPath,_T("*ResourceDLL"),csRC + _T(".dll") ) ;
|
|
|
|
|
|
// Fill RC member data : m_csRCName, m_csW2000Path ;
|
|
m_csW2000Path = csGpdPath.Left(csGpdPath.ReverseFind('\\') ) ;
|
|
m_csRCName = csRC + _T(".rc") ;
|
|
GetRCFileTimeStamp(m_ctRCFileTimeStamp) ; // set the last time stamp
|
|
SetRCModifiedFlag(TRUE ) ;
|
|
|
|
// Set project version
|
|
m_mvMDWVersion.uvernum = MDW_VER_FILES_IN_W2K_TREE ;
|
|
m_dwDefaultCodePage =
|
|
m_dwDefaultCodePageNum = 1252 ;
|
|
|
|
// Set project name; top name in the tree
|
|
CString csPrjname;
|
|
csPrjname = m_csW2000Path.Mid(m_csW2000Path.ReverseFind('\\') + 1 ) ;
|
|
Rename(csPrjname ) ;
|
|
|
|
|
|
// copy the resource data to project member data
|
|
m_cdr.CopyResources(csaUFMFiles,csaGTTFiles, csGpdPath, csaRcid) ;
|
|
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|