2025-04-27 07:49:33 -04:00

466 lines
14 KiB
C++

/******************************************************************************
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 Bob_Kjelgaard@prodigy.net Created it
******************************************************************************/
#include "StdAfx.H"
#include "MiniDev.H"
#include "ModlData\Resource.H"
#include "NewProj.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 = WinNT50;
m_ufStatus = 0;
}
CProjectRecord::~CProjectRecord() {
}
CString CProjectRecord::TargetPath(UINT ufFlags) const {
switch(ufFlags) {
case Win95:
return m_csWin95Path;
case WinNT3x:
return m_csNT3xPath;
case WinNT40:
return m_csNT40Path;
case WinNT50:
return m_csNT50Path;
}
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_csNT50Path = m_csNT40Path = m_csNT3xPath = m_csWin95Path =
m_csSourceRCFile.Left(m_csSourceRCFile.ReverseFind(_T('\\')));
m_csNT50Path += _T("\\NT5");
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 WinNT50:
m_ufStatus&= ~ConversionsDone;
return ValidatePath(m_csNT50Path, 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;
// Invoke the wizard.
CNewProjectWizard cnpw(*this);
return cnpw.DoModal() == ID_WIZFINISH;
}
/////////////////////////////////////////////////////////////////////////////
// CProjectRecord serialization
void CProjectRecord::Serialize(CArchive& car) {
m_cdr.Serialize(car);
if (car.IsStoring()) {
car << m_csNT50Path << m_csNT40Path << m_csNT3xPath << m_csWin95Path <<
m_csSourceRCFile << m_ufTargets << m_ufStatus << m_csRCName;
}
else {
car >> m_csNT50Path >> m_csNT40Path >> m_csNT3xPath >> m_csWin95Path >>
m_csSourceRCFile >> m_ufTargets >> m_ufStatus >> m_csRCName;
}
}
// 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 WinNT50:
return CreateStructure(TargetPath(WinNT50), _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) {
// Generate the files needed for NT 5.0
if (!CreateStructure(TargetPath(WinNT50), _TEXT("UFM"), _TEXT("GTT")))
return FALSE; // TODO: Feedback
// Generate the RC file
m_cdr.ForceCommonRC(wfGPDConvert > 1); // All higher values require it.
if (!m_cdr.Generate(WinNT50, TargetPath(WinNT50) + '\\' + m_csRCName))
return FALSE; // TODO: Cleanup and feedback
// Generate the GTT files
for (unsigned u = 0; u < m_cdr.MapCount(); u++) {
try {
CFile cfGTT(m_cdr.GlyphTable(u).FileName(),
CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);
if (!m_cdr.GlyphTable(u).Generate(cfGTT))
return FALSE; // TODO: Ditto
}
catch (CException *pce) {
pce -> ReportError();
pce -> Delete();
return FALSE;
}
}
// Generate the UFM files
for (u = 0; u < m_cdr.FontCount(); u++) {
// Map the UFM -> GTT, so we can convert the UFM
if (CGlyphMap::Public(m_cdr.Font(u).Translation())) {
m_cdr.Font(u).SetTranslation(
CGlyphMap::Public(m_cdr.Font(u).Translation()));
}
else
for (unsigned uGTT = 0; uGTT < m_cdr.MapCount(); uGTT++)
if (m_cdr.Font(u).Translation() ==
m_cdr.GlyphTable(uGTT).GetID()) {
m_cdr.Font(u).SetTranslation(&m_cdr.GlyphTable(uGTT));
break;
}
if (!m_cdr.Font(u).Generate(m_cdr.Font(u).FileName()))
return FALSE; // TODO: Ditto
}
// 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
// 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 (unsigned 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
// 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 (unsigned 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