Leaked source code of windows server 2003
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

  1. /******************************************************************************
  2. Source File: Project Record.CPP
  3. This implements the project record class, which tracks the details for
  4. multiple mini-drivers.
  5. Copyright (c) 1997 by Microsoft Corporation. All Rights Reserved.
  6. A Pretty Penny Enterprises Production.
  7. Change History:
  8. 02-03-1997 Bob_Kjelgaard@prodigy.net Created it
  9. ******************************************************************************/
  10. #include "StdAfx.H"
  11. #include <gpdparse.h>
  12. #include "MiniDev.H"
  13. #include "Resource.H"
  14. #include "comctrls.h"
  15. #include "NewProj.H"
  16. #include "projnode.h"
  17. #include "StrEdit.h"
  18. #include "codepage.h"
  19. #include <io.h>
  20. #ifdef _DEBUG
  21. #define new DEBUG_NEW
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CProjectRecord
  27. IMPLEMENT_DYNCREATE(CProjectRecord, CDocument)
  28. BEGIN_MESSAGE_MAP(CProjectRecord, CDocument)
  29. //{{AFX_MSG_MAP(CProjectRecord)
  30. // NOTE - the ClassWizard will add and remove mapping macros here.
  31. // DO NOT EDIT what you see in these blocks of generated code!
  32. //}}AFX_MSG_MAP
  33. END_MESSAGE_MAP()
  34. /////////////////////////////////////////////////////////////////////////////
  35. // CProjectRecord construction/destruction
  36. CProjectRecord::CProjectRecord() {
  37. m_ufTargets = Win2000;
  38. m_ufStatus = 0;
  39. m_bRCModifiedFlag = FALSE ;
  40. m_ctRCFileTimeStamp = (time_t) 0 ;
  41. m_dwDefaultCodePage = 1252 ; // Not always correct but better than nothing
  42. m_dwDefaultCodePageNum = 1252 ; // Not always correct but better than nothing
  43. }
  44. CProjectRecord::~CProjectRecord() {
  45. }
  46. /******************************************************************************
  47. CProjectRecord::OnOpenDocument
  48. First, open the file directly and try to read version information from it.
  49. Complain and fail the open if the file's version is greater than the MDT's
  50. current version number. IE, fail if someone is trying to open a workspace
  51. on a down level (older) version of the MDT.
  52. Second, open a workspace in the normal way. Then check the workspace's
  53. version to see if it is out of date. If it is and the user agrees, do what is
  54. necessary to bring it up to date and then save the updated workspace file.
  55. All version related upgrade work should be managed from this routine.
  56. Depending on the age of the workspace file, there may be multiple upgrade
  57. steps required. Be that as it may, the user should only be prompted once.
  58. NEW UPGRADE CHECKS AND STEPS SHOULD FOLLOW THE FORMAT LAYED OUT BELOW.
  59. There are various other workspace related checks that need to be done. For
  60. example, the timestamp of the RC file needs to be checked to see if it has
  61. been changed by something other than the the MDT. That work should be done
  62. and/or managed by code in this routine, too. If possible (and I'm not sure
  63. it is), prompt the user no more than once per file (eg, RC or INF) for these
  64. things, too. AGAIN, FOLLOW THE FORMAT LAYED OUT BELOW.
  65. The last thing done in this routine is to try to verify and - if necessary -
  66. update the location of files in the workspace. If this fails and the user
  67. doesn't want to continue anyway, the Open is failed. See VerUpdateFilePaths()
  68. for more information.
  69. ******************************************************************************/
  70. BOOL CProjectRecord::OnOpenDocument(LPCTSTR lpszPathName)
  71. {
  72. // Complain and fail if the user is trying to open a bogus file.
  73. CString cstmp(lpszPathName), cstmp2 ;
  74. cstmp.MakeUpper() ;
  75. cstmp2.LoadString(IDS_MDWExtension) ;
  76. if (cstmp.Find(cstmp2) == -1) {
  77. cstmp.LoadString(IDS_UnExpFilTypError) ;
  78. AfxMessageBox(cstmp, MB_ICONEXCLAMATION) ;
  79. return FALSE ;
  80. } ;
  81. // Start by reading the MDW file's version stamp.
  82. try {
  83. CFile cfmdw(lpszPathName, CFile::modeRead | CFile::shareDenyNone) ;
  84. cfmdw.Read(&m_mvMDWVersion, MDWVERSIONSIZE) ;
  85. cfmdw.Close() ;
  86. }
  87. catch (CException* pce) {
  88. pce->ReportError() ;
  89. pce->Delete() ;
  90. return FALSE ;
  91. } ;
  92. // If the version tag is invalid, set the version number to the
  93. // default version number; IE, 0.
  94. if (strncmp(m_mvMDWVersion.acvertag, VERTAGSTR, MDWVERSIONSIZE) != 0)
  95. m_mvMDWVersion.uvernum = MDW_DEFAULT_VERSION ;
  96. // Now. make sure that the MDW's version isn't newer than the MDT's version.
  97. if (m_mvMDWVersion.uvernum > MDW_CURRENT_VERSION) {
  98. CString csmsg, cstmp ;
  99. cstmp = lpszPathName ;
  100. int nloc = cstmp.ReverseFind(_T('\\')) ;
  101. if (nloc >= 0)
  102. cstmp = cstmp.Right(cstmp.GetLength() - nloc - 1) ;
  103. csmsg.Format(IDS_MDWTooNewError, cstmp, m_mvMDWVersion.uvernum,
  104. MDW_CURRENT_VERSION) ;
  105. AfxMessageBox(csmsg, MB_ICONEXCLAMATION) ;
  106. return FALSE ;
  107. } ;
  108. if (!CDocument::OnOpenDocument(lpszPathName))
  109. return FALSE ;
  110. // Save the project file's filespec.
  111. m_csProjFSpec = lpszPathName ;
  112. // If the workspace version is too old to upgrade, just return TRUE to
  113. // indicate that the file was successfully opened and that nothing else
  114. // can be done.
  115. if (m_mvMDWVersion.uvernum < MDW_FIRST_UPGRADABLE_VER)
  116. return TRUE ;
  117. // *** Beginning of workspace upgrade management code.
  118. //
  119. // o Declare flags for each of the required upgrade steps. These
  120. // flags will be set in the following switch statement.
  121. // o There is also a flag that is set when any workspace upgrading is
  122. // required.
  123. // o Make sure that all flags are initialized to false.
  124. //
  125. // NOTE: That the cases in the switch statement do not end with break
  126. // statements. This is so that all of the upgrade flags for a workspace
  127. // currently at a particular version will be set when needed. The
  128. // switch statement is set up so that if the workspace is version X, then
  129. // all of the upgrade flags for versions > X are set.
  130. //
  131. // Whenever a new workspace version is added:
  132. // o Declare a new flag for it.
  133. // o Add a new case statement to the switch statement for it. (See note
  134. // above. You are actually adding a case statement for the previous
  135. // version that will set the new version's flag.)
  136. // o Bupgradeneeded should always be set by the last case statement.
  137. // Move the bupgradeneeded setting statement to the last case statement
  138. // whenever a new case statement is added.
  139. bool bupgradeneeded, brctimestamp, bdefaultcodepage, bresdllnamechanged ;
  140. bool bnodrpathsinmdw, bfilesinw2ktree ;
  141. bupgradeneeded = brctimestamp = bdefaultcodepage = false ;
  142. bresdllnamechanged = bnodrpathsinmdw = bfilesinw2ktree = false ;
  143. switch (m_mvMDWVersion.uvernum) {
  144. case MDW_VER_STRING_RCIDS:
  145. bdefaultcodepage = true ;
  146. case MDW_VER_DEFAULT_CPAGE:
  147. brctimestamp = true ;
  148. case MDW_VER_RC_TIMESTAMP:
  149. bresdllnamechanged = true ;
  150. case MDW_VER_NEW_DLLNAME:
  151. bnodrpathsinmdw = true ;
  152. case MDW_VER_NO_FILE_PATHS:
  153. bfilesinw2ktree = true ;
  154. bupgradeneeded = true ;
  155. } ;
  156. // If upgrade(s) are needed, declare a flag that indicates if any upgrading,
  157. // checking, or updating error has occurred. If this flag is set, all
  158. // processing should stop. Then...
  159. bool bprocerror = false ;
  160. bool buserwantstoupgrade = false ;
  161. CString csprompt ;
  162. if (bupgradeneeded) {
  163. // ... Build a customized prompt for the user.
  164. // o Statements about upgrade tasks relevant to the user should also
  165. // be added to the prompt. For example, it should be noted when
  166. // the RC file will be rewritten. In this case (and below when
  167. // other RC related checks are made), it is only necessary to
  168. // test the "newest" RC related flag. IE, the one associated with
  169. // the latest MDW version. This works because if any of the older
  170. // RC flags are set, the newest one must be set too.
  171. // o Be concise so the message doesn't get too long.
  172. csprompt.Format(IDS_MDWUpgradeMsg1, DriverName()) ;
  173. if (bresdllnamechanged) {
  174. cstmp.LoadString(IDS_RCFileChanging) ;
  175. csprompt += cstmp ;
  176. } ;
  177. cstmp.LoadString(IDS_MDWUpgradeMsg2) ;
  178. csprompt += cstmp ;
  179. // ... Do the work if the user wants to upgrade.
  180. // o Each upgrade step should be enclosed in an if statement that
  181. // checks its individual flag and the processing error flag.
  182. if (AfxMessageBox(csprompt, MB_ICONQUESTION + MB_YESNO) == IDYES) {
  183. buserwantstoupgrade = true ;
  184. // If required, prompt the user for a default code page for the
  185. // driver and save it.
  186. if (!bprocerror && bdefaultcodepage)
  187. bprocerror = !UpdateDfltCodePage() ;
  188. // Reparse the RC file, rewrite it, and update its timestamp when
  189. // required.
  190. if (!bprocerror && bresdllnamechanged)
  191. bprocerror = !UpdateRCFile() ;
  192. // If required, rename the driver's subtree root directory from
  193. // "NT5" to "W2K".
  194. if (!bprocerror && bfilesinw2ktree)
  195. bprocerror = !UpdateDrvSubtreeRootName() ;
  196. // If everything is ok, update the MDW's version number. (The MDW
  197. // file is saved later so that this only has to be done once.)
  198. if (!bprocerror)
  199. m_mvMDWVersion.uvernum = MDW_CURRENT_VERSION ;
  200. } ;
  201. } ;
  202. // *** End of workspace upgrade management code except for possible MDW
  203. // *** file reload. (See below for details.)
  204. // *** Begin workspace related checks and updates
  205. //
  206. // o All of the checks for a specific file should be grouped together in
  207. // one if statement so that only one prompt is required when the file
  208. // needs to be updated.
  209. // o The if statement must contain the specific checks and, optionally,
  210. // test if a related MDW upgrade step has already been performed or
  211. // if a processing error has already occurred.
  212. // o If all of the checks/tests are "passed", perform whatever processing
  213. // is required.
  214. // o If any updates are performed that require the MDW file to be
  215. // rewritten, set bupgradeneeded.
  216. // o Always set bprocerror if an error occurs and tell the user what
  217. // happened.
  218. // Reread the RC file if it has been changed and user oks it.
  219. if (!bprocerror && !bresdllnamechanged && RCFileChanged()) {
  220. cstmp = m_csRCName ;
  221. cstmp.MakeUpper() ;
  222. csprompt.Format(IDS_UpdateRCFile, cstmp) ;
  223. if (AfxMessageBox(csprompt, MB_ICONQUESTION + MB_YESNO) == IDYES) {
  224. if (!(bprocerror = !UpdateRCFile()))
  225. bupgradeneeded = true ;
  226. } ;
  227. } ;
  228. // *** End of workspace related checks and updates
  229. // Save any MDW file changes that were made by any of the code above.
  230. if (bupgradeneeded && !bprocerror)
  231. bprocerror = (bool) !CDocument::OnSaveDocument(lpszPathName) ;
  232. // Occassionally, one of the changes done above requires the reloading of
  233. // the driver's MDW file. That is done here. The reasons are listed below.
  234. // o When the driver's subtree root has been renamed from "NT5" to "W2K",
  235. // there are still copies of "NT5" in paths and filespecs in class
  236. // instances all over the place. The easiest way to correct those paths,
  237. // etc is by reloading the MDW file.
  238. if (buserwantstoupgrade && bfilesinw2ktree && !bprocerror)
  239. if (!CDocument::OnOpenDocument(lpszPathName))
  240. return FALSE ;
  241. // Try to detect if driver files were moved and if they can be found.
  242. // Continue processing if the files were found or the user wants to
  243. // continue anyway. Otherwise, cancel the loading of the workspace.
  244. if (!VerUpdateFilePaths())
  245. return FALSE ;
  246. // Workspace was loaded so return TRUE.
  247. // DEAD_BUG: Should I return TRUE even if there was a processing error???
  248. return TRUE ;
  249. }
  250. /******************************************************************************
  251. CProjectRecord::RCFileChanged
  252. If the MDW version is NOT large enough for this info to be relevant, return
  253. false. If the version is large enough but m_ctRCFileTimeStamp is
  254. uninitialized, assert.
  255. If the everything is ok, get the timestamp for the RC file and compare it
  256. with m_ctRCFileTimeStamp. If the RC file has changed, return true.
  257. Otherwise, return false.
  258. ******************************************************************************/
  259. bool CProjectRecord::RCFileChanged()
  260. {
  261. // Return no change if the MDW version is too low.
  262. if (m_mvMDWVersion.uvernum < MDW_VER_RC_TIMESTAMP)
  263. return false ;
  264. // Blow if the saved time is uninitialized.
  265. ASSERT(m_ctRCFileTimeStamp.GetTime() > 0) ;
  266. // Get the timestamp for the RC file, compare it with the time the MDT last
  267. // modified the file, and return the result.
  268. CTime ct ;
  269. if (!GetRCFileTimeStamp(ct))
  270. return false ;
  271. //TRACE("RC timestamp = %s Saved timestamp = %s\n", ct.Format("%c"), m_ctRCFileTimeStamp.Format("%c")) ;
  272. if (ct > m_ctRCFileTimeStamp)
  273. return true ;
  274. else
  275. return false ;
  276. }
  277. /******************************************************************************
  278. CProjectRecord::GetRCFileTimeStamp
  279. Get the last modified time stamp for this project's RC file and load it into
  280. the specified parameter. Return true if this succeeds. Otherwise, return
  281. false.
  282. ******************************************************************************/
  283. bool CProjectRecord::GetRCFileTimeStamp(CTime& ct)
  284. {
  285. try {
  286. // Open the RC file
  287. CString csrcfspec(TargetPath(Win2000) + '\\' + m_csRCName) ;
  288. CFile cfrc(csrcfspec, CFile::modeRead + CFile::shareDenyNone) ;
  289. // Get RC file status information
  290. CFileStatus cfs ;
  291. cfrc.GetStatus(cfs) ;
  292. // Copy the last modified time stamp into the caller's variable
  293. ct = cfs.m_mtime ;
  294. // All went well so...
  295. return true ;
  296. }
  297. catch (CException* pce) {
  298. pce->ReportError() ;
  299. pce->Delete() ;
  300. return false ;
  301. } ;
  302. return false ;
  303. }
  304. /******************************************************************************
  305. CProjectRecord::UpdateRCFile
  306. This routine is called when it has been determined that the RC file was
  307. modified outside of the MDT. This routine will reparse the RC file to
  308. update the internal data structures, merge the new data with the old data,
  309. and write a new RC file based on the combined information. Then the
  310. timestamp for the last time the MDT modified the RC file is updated.
  311. Return true if all goes well. Otherwise, return false.
  312. ******************************************************************************/
  313. bool CProjectRecord::UpdateRCFile()
  314. {
  315. // Build a filespec for the RC file.
  316. CString csrcfspec(TargetPath(Win2000) + '\\' + m_csRCName) ;
  317. // Reparse the RC file and update internal data structures.
  318. if (!m_cdr.ReparseRCFile(csrcfspec))
  319. return false ;
  320. // Write a new RC file base on the updated information.
  321. if (!m_cdr.Generate(Win2000, csrcfspec)) {
  322. AfxMessageBox(IDS_RCWriteError) ;
  323. return false ; // TODO: Cleanup and backtracking
  324. } ;
  325. // Update the last time the RC file was written by the MDT timestamp.
  326. GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
  327. // All went well so...
  328. return true ;
  329. }
  330. /******************************************************************************
  331. CProjectRecord::UpdateDfltCodePage
  332. Prompt the user for a default code page and save it. Fail (return) false if
  333. the user cancels. Return true if all goes well.
  334. ******************************************************************************/
  335. bool CProjectRecord::UpdateDfltCodePage()
  336. {
  337. // Display the dialog box to prompt for the code page.
  338. CGetDefCodePage dlg ;
  339. if (dlg.DoModal() == IDCANCEL)
  340. return false ;
  341. // A code page was selected, get it out of the dialog class and save it in
  342. // this class. Both the cp/translated Far East resource ID and the real
  343. // CP are saved.
  344. SetDefaultCodePage(dlg.GetDefaultCodePage()) ;
  345. SetDefaultCodePageNum(dlg.GetDefaultCodePageNum()) ;
  346. // All went well so...
  347. return true ;
  348. }
  349. /******************************************************************************
  350. CProjectRecord::UpdateDrvSubtreeRootName
  351. This routine is called when the root of the driver's subtree needs to be
  352. renamed. Older versions of the MDT would create a directory named "NT5" in
  353. which to put the driver's files and subdirectories. Now that NT 5.0 has
  354. been renamed to Windows 2000 the new driver root directory should be called
  355. "W2K". This routine will rename the driver's "NT5" directory to "W2K".
  356. Return true if the directory rename is successful. Otherwise, return false.
  357. ******************************************************************************/
  358. bool CProjectRecord::UpdateDrvSubtreeRootName()
  359. {
  360. // Isolate the path for the MDW file.
  361. int npos = m_csProjFSpec.ReverseFind(_T('\\')) ;
  362. CString cspath = m_csProjFSpec.Left(npos + 1) ;
  363. // Now use the MDW file's path to build the old and new root directory
  364. // paths.
  365. CString csoldpath, csnewpath ;
  366. csoldpath.LoadString(IDS_OldDriverRootDir) ;
  367. csoldpath = cspath + csoldpath ;
  368. csnewpath.LoadString(IDS_NewDriverRootDir) ;
  369. csnewpath = cspath + csnewpath ;
  370. // Rename the directory. Complain and return false if this fails.
  371. try {
  372. if (rename(csoldpath, csnewpath) != 0)
  373. return false ;
  374. }
  375. catch (CException *pce) {
  376. pce->ReportError() ;
  377. pce->Delete() ;
  378. return FALSE ;
  379. } ;
  380. // Update this path so that the RC file checks will work later in the
  381. // code.
  382. m_csW2000Path = csnewpath ;
  383. // All went well so...
  384. return true ;
  385. }
  386. /******************************************************************************
  387. CProjectRecord::OnSaveDocument
  388. Before saving the document, rebuild the RC file when needed and check the
  389. workspace for consistency.
  390. ******************************************************************************/
  391. BOOL CProjectRecord::OnSaveDocument(LPCTSTR lpszPathName)
  392. {
  393. // Check to see if the RC file needs to be rewritten first. If the RC file
  394. // needs to be rewritten but this operation fails, return false (FAILURE).
  395. if (m_bRCModifiedFlag) {
  396. // If the workspace has no version information, rewriting the RC file
  397. // will erase the string table from the file. The user probably
  398. // won't want to do this. Only continue if he says so.
  399. int nqr = IDYES ; // Query result
  400. if (m_mvMDWVersion.uvernum == MDW_DEFAULT_VERSION) {
  401. CString csmsg ;
  402. csmsg.Format(IDS_RCRewriteQuestion, m_cdr.Name(), m_csRCName) ;
  403. nqr = AfxMessageBox(csmsg, MB_YESNO+MB_ICONQUESTION+MB_DEFBUTTON2) ;
  404. } ;
  405. if (nqr == IDYES) {
  406. if (!m_cdr.Generate(Win2000, TargetPath(Win2000) + '\\' + m_csRCName)) {
  407. AfxMessageBox(IDS_RCWriteError) ;
  408. return FALSE ; // TODO: Cleanup and backtracking
  409. } ;
  410. // Update the last time the RC file was written by the MDT timestamp.
  411. GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
  412. } ;
  413. m_bRCModifiedFlag = FALSE ;
  414. } ;
  415. // Check the workspace for consistency before continuing. Save, set, and
  416. // restore the directory around this call.
  417. CString cscurdir ;
  418. ::GetCurrentDirectory(512, cscurdir.GetBuffer(512)) ;
  419. cscurdir.ReleaseBuffer() ;
  420. SetCurrentDirectory(m_csW2000Path) ;
  421. BOOL brc = m_cdr.WorkspaceChecker(true) ;
  422. SetCurrentDirectory(cscurdir) ;
  423. // Save the project file's filespec.
  424. m_csProjFSpec = lpszPathName ;
  425. // Now save the document (workspace) file.
  426. //
  427. // NOTE: The value returned is virtually assured to be TRUE. This is
  428. // done to make sure the document is saved when the user requests
  429. // it. This has some unwanted side effects that I don't know
  430. // how to avoid. First, if the save is happening because the
  431. // document is closing, it will still close even if there are
  432. // workspace errors that the user wants to see. Second, if the
  433. // save is happening because the app is closing, the app will
  434. // still close even if there are workspace errors that the user
  435. // wants to see.
  436. // raid 123448
  437. if (m_mvMDWVersion.uvernum == MDW_VER_FILES_IN_W2K_TREE )
  438. m_mvMDWVersion.uvernum = MDW_VER_YES_FILE_PATHS ;
  439. return CDocument::OnSaveDocument(lpszPathName) ;
  440. }
  441. CString CProjectRecord::TargetPath(UINT ufFlags) const {
  442. switch(ufFlags) {
  443. case Win95:
  444. return m_csWin95Path;
  445. case WinNT3x:
  446. return m_csNT3xPath;
  447. case WinNT40:
  448. return m_csNT40Path;
  449. case Win2000:
  450. return m_csW2000Path;
  451. }
  452. AfxThrowNotSupportedException();
  453. return m_csWin95Path;
  454. }
  455. // This routine establishes the source RC file's name, and the initial paths
  456. // for all of the potential targets.
  457. void CProjectRecord::SetSourceRCFile(LPCTSTR lpstrSource) {
  458. m_csSourceRCFile = lpstrSource;
  459. m_csW2000Path = m_csNT40Path = m_csNT3xPath = m_csWin95Path =
  460. m_csSourceRCFile.Left(m_csSourceRCFile.ReverseFind(_T('\\')));
  461. // The last path component of the Windows 2000 files' directory, depends on
  462. // the version of the MDW file.
  463. CString cs ;
  464. if (m_mvMDWVersion.uvernum >= MDW_VER_FILES_IN_W2K_TREE)
  465. cs.LoadString(IDS_NewDriverRootDir) ;
  466. else
  467. cs.LoadString(IDS_OldDriverRootDir) ;
  468. m_csW2000Path += _T("\\") ;
  469. m_csW2000Path += cs ;
  470. m_csNT40Path += _T("\\NT4");
  471. m_csNT3xPath += _T("\\NT3");
  472. // Trim the path name (including trailing \) to get driver name and RC
  473. m_csRCName = m_csSourceRCFile.Mid(1 + m_csWin95Path.GetLength());
  474. if (m_csRCName.Find('.') != -1)
  475. m_csRCName = m_csRCName.Left(m_csRCName.Find('.'));
  476. m_cdr.Rename(m_csRCName);
  477. m_csRCName += _T(".RC");
  478. m_ufStatus = 0;
  479. }
  480. // This is a helper function- it validates a new path name, and if it is
  481. // valid, returns TRUE, and stores it in the given CString;
  482. static BOOL ValidatePath(CString& csTarget, LPCTSTR lpstrPath) {
  483. if (!csTarget.CompareNoCase(lpstrPath)) {
  484. // Trivial- no change = success!
  485. return TRUE;
  486. }
  487. // Determine the current directory, so we don't lose it.
  488. CString csCurrentDirectory, csNewOne;
  489. GetCurrentDirectory(MAX_PATH, csCurrentDirectory.GetBuffer(MAX_PATH));
  490. csCurrentDirectory.ReleaseBuffer();
  491. // Attempt to switch to the new directory. If we succeed, we're done.
  492. if (SetCurrentDirectory(lpstrPath)) {
  493. GetCurrentDirectory(MAX_PATH, csTarget.GetBuffer(MAX_PATH));
  494. csTarget.ReleaseBuffer();
  495. SetCurrentDirectory(csCurrentDirectory);
  496. return TRUE;
  497. }
  498. // Attempt to create the new directory. If this succeeds, delete the
  499. // directory, and note our success our failure, either way.
  500. if (CreateDirectory(lpstrPath, NULL)) {
  501. SetCurrentDirectory(lpstrPath);
  502. GetCurrentDirectory(MAX_PATH, csTarget.GetBuffer(MAX_PATH));
  503. csTarget.ReleaseBuffer();
  504. SetCurrentDirectory(csCurrentDirectory);
  505. RemoveDirectory(csTarget);
  506. return TRUE;
  507. }
  508. return FALSE; // Nothing worked, give it up...
  509. }
  510. // The following loads all of the driver resources.
  511. BOOL CProjectRecord::LoadResources() {
  512. if (!m_cdr.Load(*this))
  513. return FALSE;
  514. m_ufStatus |= UniToolRun;
  515. m_ufStatus &= ~(ConversionsDone | NTGPCDone);
  516. SetModifiedFlag();
  517. return TRUE;
  518. }
  519. // The following member validates a new target path name.
  520. BOOL CProjectRecord::SetPath(UINT ufTarget, LPCTSTR lpstrPath) {
  521. switch (ufTarget) {
  522. case Win2000:
  523. m_ufStatus&= ~ConversionsDone;
  524. return ValidatePath(m_csW2000Path, lpstrPath);
  525. case WinNT40:
  526. m_ufStatus&= ~(ConversionsDone | NTGPCDone);
  527. return ValidatePath(m_csNT40Path, lpstrPath);
  528. case WinNT3x:
  529. m_ufStatus&= ~(ConversionsDone | NTGPCDone);
  530. return ValidatePath(m_csNT3xPath, lpstrPath);
  531. }
  532. _ASSERTE(FALSE); // This should never happen!
  533. return FALSE;
  534. }
  535. // When we create a new document (aka project, aka driver), we invoke the
  536. // new project wizard
  537. BOOL CProjectRecord::OnNewDocument() {
  538. if (!CDocument::OnNewDocument())
  539. return FALSE;
  540. // raid 104822 : add real new document : kill below
  541. // Invoke the wizard.
  542. CNewConvertWizard cnpw(*this);
  543. // Initialize the workspace's version number.
  544. m_mvMDWVersion.uvernum = MDW_CURRENT_VERSION ;
  545. return cnpw.DoModal() == ID_WIZFINISH;
  546. return TRUE;
  547. }
  548. /////////////////////////////////////////////////////////////////////////////
  549. // CProjectRecord serialization
  550. //
  551. // See "MDT Workspace Versioning" in projrec.h for more information.
  552. //
  553. void CProjectRecord::Serialize(CArchive& car)
  554. {
  555. // The first thing to do when storing is to build and write out the MDW
  556. // version information. Only do this when the workspace's version number
  557. // is not MDW_DEFAULT_VERSION; IE, the WS has a version number.
  558. if (car.IsStoring()) {
  559. if (m_mvMDWVersion.uvernum > MDW_DEFAULT_VERSION) {
  560. StringCchCopyA(m_mvMDWVersion.acvertag, CCHOF(m_mvMDWVersion.acvertag), VERTAGSTR) ;
  561. car.Write(&m_mvMDWVersion, MDWVERSIONSIZE) ;
  562. } ;
  563. // When loading, CProjectRecord::OnOpenDocument() initializes and uses
  564. // m_mvMDWVersion. Then the file is closed. The file is reopened at the
  565. // beginning by CDocument::OnOpenDocument(). This means that when the file
  566. // contains version info, we must skip passed it so that the rest of the
  567. // serialization process can continue as expected.
  568. } else if (m_mvMDWVersion.uvernum >= MDW_FIRST_UPGRADABLE_VER)
  569. car.Read(&m_mvMDWVersion, MDWVERSIONSIZE) ;
  570. // m_csW2000Path needs to be loaded before m_cdr.Serialize() is called
  571. // so that the string can be used in the function and/or the routines it
  572. // calls.
  573. // raid 123448
  574. if (m_mvMDWVersion.uvernum < MDW_VER_YES_FILE_PATHS) {
  575. m_csW2000Path = car.GetFile()->GetFilePath() ;
  576. m_csW2000Path = m_csW2000Path.Left(m_csW2000Path.ReverseFind(_T('\\'))) ;
  577. // The last path component depends on the version of the MDW file.
  578. CString cs ;
  579. if (m_mvMDWVersion.uvernum >= MDW_VER_FILES_IN_W2K_TREE)
  580. cs.LoadString(IDS_NewDriverRootDir) ;
  581. else
  582. cs.LoadString(IDS_OldDriverRootDir) ;
  583. m_csW2000Path += _T("\\") ; // b. 2 lines : Raid 123448 !;; can cancel W2K dir.
  584. m_csW2000Path += cs ;
  585. } ;
  586. // Now that versioning is done, get on with saving or restoring the
  587. // workspace's state.
  588. m_cdr.Serialize(car) ;
  589. if (car.IsStoring()) {
  590. if (m_mvMDWVersion.uvernum >= MDW_VER_YES_FILE_PATHS) // Raid 123448
  591. car << m_csW2000Path ;
  592. car << m_csNT40Path << m_csNT3xPath << m_csWin95Path <<
  593. m_csSourceRCFile << m_ufTargets << m_ufStatus << m_csRCName ;
  594. if (m_mvMDWVersion.uvernum >= MDW_VER_DEFAULT_CPAGE)
  595. car << m_dwDefaultCodePage ;
  596. if (m_mvMDWVersion.uvernum >= MDW_VER_RC_TIMESTAMP)
  597. car << m_ctRCFileTimeStamp ;
  598. } else {
  599. if (m_mvMDWVersion.uvernum >= MDW_VER_YES_FILE_PATHS)
  600. car >> m_csW2000Path ;
  601. car >> m_csNT40Path >> m_csNT3xPath >> m_csWin95Path >>
  602. m_csSourceRCFile >> m_ufTargets >> m_ufStatus >> m_csRCName ;
  603. if (m_mvMDWVersion.uvernum >= MDW_VER_DEFAULT_CPAGE) {
  604. car >> m_dwDefaultCodePage ;
  605. // Use m_dwDefaultCodePage to compute m_dwDefaultCodePageNum so
  606. // that a new MDW version is NOT needed to support
  607. // m_dwDefaultCodePageNum. (See the declaration of these variables
  608. // for more info.)
  609. short scp = (short) ((WORD) m_dwDefaultCodePage) ;
  610. switch (scp) {
  611. case -10:
  612. m_dwDefaultCodePageNum = 950 ;
  613. break ;
  614. case -16:
  615. m_dwDefaultCodePageNum = 936 ;
  616. break ;
  617. case -17:
  618. m_dwDefaultCodePageNum = 932 ;
  619. break ;
  620. case -18:
  621. m_dwDefaultCodePageNum = 949 ;
  622. break ;
  623. default:
  624. m_dwDefaultCodePageNum = m_dwDefaultCodePage ;
  625. break ;
  626. } ;
  627. } ;
  628. if (m_mvMDWVersion.uvernum >= MDW_VER_RC_TIMESTAMP)
  629. car >> m_ctRCFileTimeStamp ;
  630. }
  631. // Last, tell the user that the driver in this workspace should be
  632. // reconverted when there is no version information in the MDW file.
  633. // Only do this when loading.
  634. if (!car.IsStoring() && m_mvMDWVersion.uvernum == MDW_DEFAULT_VERSION) {
  635. CString csmsg ;
  636. csmsg.Format(IDS_NoVersionError, m_cdr.Name()) ;
  637. AfxMessageBox(csmsg, MB_ICONEXCLAMATION) ;
  638. } ;
  639. }
  640. // Private Worker Routine- this establishes a directory, by first attempting
  641. // to go to it, then creating it if that failes. The current directory is
  642. // preserved.
  643. static BOOL Establish(CString csNew) {
  644. CString csCurrent;
  645. GetCurrentDirectory(MAX_PATH, csCurrent.GetBuffer(MAX_PATH));
  646. csCurrent.ReleaseBuffer();
  647. if (SetCurrentDirectory(csNew)) {
  648. SetCurrentDirectory(csCurrent);
  649. return TRUE;
  650. }
  651. return CreateDirectory(csNew, NULL);
  652. }
  653. // Private worker routine. This establishes the directory structure given it,
  654. // consisting of a named route, and two branches.
  655. static BOOL CreateStructure(const CString& csRoot, LPCTSTR lpstrFont,
  656. LPCTSTR lpstrMap) {
  657. return Establish(csRoot) && Establish(csRoot + '\\' + lpstrFont) &&
  658. Establish(csRoot + '\\' + lpstrMap);
  659. }
  660. /******************************************************************************
  661. CProjectRecord::BuildStructure
  662. This builds the directory structure needed for all conversion targets. This
  663. is done before files are generated so that the renaming calls in many of the
  664. project nodes do not fail.
  665. ******************************************************************************/
  666. BOOL CProjectRecord::BuildStructure(unsigned uVersion) {
  667. switch (uVersion) {
  668. case Win2000:
  669. return CreateStructure(TargetPath(Win2000), _T("UFM"), _T("GTT"));
  670. case WinNT40:
  671. return CreateStructure(TargetPath(WinNT40), _T("IFI"), _T("RLE"));
  672. case WinNT3x:
  673. return CreateStructure(TargetPath(WinNT3x), _T("IFI"), _T("RLE"));
  674. }
  675. _ASSERTE(FALSE);
  676. return FALSE;
  677. }
  678. /******************************************************************************
  679. CProjectRecord::GenerateTargets
  680. This one is a workhorse- it generates all of the files needed for all of the
  681. enabled targets, using the Win 3.x files as a base, with the exception of the
  682. NT GPC extensions, which require an interactive step.
  683. ******************************************************************************/
  684. BOOL CProjectRecord::GenerateTargets(WORD wfGPDConvert)
  685. {
  686. int nerrorid ; // Error message ID returned by some routines
  687. // Generate the files needed for Win2K
  688. if (!CreateStructure(TargetPath(Win2000), _TEXT("UFM"), _TEXT("GTT")))
  689. return FALSE; // TODO: Feedback
  690. m_cdr.ForceCommonRC(FALSE); // Don't use common.rc at all
  691. // Find and remove the standard include files from the array of include
  692. // files. This will keep them from being added to the RC file twice.
  693. CString cs ;
  694. cs.LoadString(IDS_StdIncludeFile1) ;
  695. m_cdr.RemUnneededRCInclude(cs) ;
  696. if (wfGPDConvert > 1) {
  697. cs.LoadString(IDS_StdIncludeFile2) ;
  698. m_cdr.RemUnneededRCInclude(cs) ;
  699. } ;
  700. cs.LoadString(IDS_StdIncludeFile3) ;
  701. m_cdr.RemUnneededRCInclude(cs) ;
  702. cs.LoadString(IDS_StdIncludeFile4) ;
  703. m_cdr.RemUnneededRCInclude(cs) ;
  704. cs.LoadString(IDS_StdIncludeFile5) ;
  705. m_cdr.RemUnneededRCInclude(cs) ;
  706. cs.LoadString(IDS_OldIncludeFile1) ;
  707. m_cdr.RemUnneededRCInclude(cs) ;
  708. // Generate the RC file
  709. if (!m_cdr.Generate(Win2000, TargetPath(Win2000) + '\\' + m_csRCName))
  710. return FALSE; // TODO: Cleanup and feedback
  711. // Update the last time the RC file was written by the MDT timestamp.
  712. GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
  713. // Generate the GTT files
  714. #if 0
  715. for (unsigned u = 0; u < m_cdr.MapCount(); u++) {
  716. CString csfspec ;
  717. try {
  718. csfspec = m_cdr.GlyphTable(u).FileName() ;
  719. CFile cfGTT(csfspec,
  720. CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);
  721. if (!m_cdr.GlyphTable(u).Generate(cfGTT)) {
  722. m_cdr.LogConvInfo(IDS_FileWriteError, 1, &csfspec) ;
  723. return FALSE ;
  724. } ;
  725. }
  726. catch (CException *pce) {
  727. pce -> ReportError();
  728. pce -> Delete();
  729. m_cdr.LogConvInfo(IDS_FileWriteError, 1, &csfspec) ;
  730. return FALSE;
  731. }
  732. }
  733. #else
  734. unsigned u ;
  735. #endif
  736. // Generate the UFM files
  737. CGlyphMap* pcgm ;
  738. for (u = 0; u < m_cdr.FontCount(); u++) {
  739. CFontInfo& cfi = m_cdr.Font(u) ;
  740. // Load the UFM's PFM if it hasn't been loaded already. This is done
  741. // here to get possible GTT mapping info that is used if a GTT must be
  742. // built for this UFM. This shouldn't fail. If it does fail, the
  743. // conversion cannot continue.
  744. if (!cfi.MapPFM()) {
  745. CString csfspec ;
  746. csfspec = cfi.FileName() ;
  747. m_cdr.LogConvInfo(IDS_UFMGenError, 1, &csfspec) ;
  748. return FALSE;
  749. } ;
  750. // Map the UFM -> GTT, so we can convert the UFM
  751. //
  752. // DEAD_BUG: The code page field in the font class instances has not
  753. // been set yet so send 0 instead. This might be fixable.
  754. /* res_PFMHEADER *pPFM = (res_PFMHEADER *) cfi.m_cbaPFM.GetData();
  755. BYTE dfCharSet = pPFM ->dfCharSet;
  756. WORD CharSetCodePage = 0;
  757. switch (dfCharSet) {
  758. case SHIFTJIS_CHARSET:
  759. CharSetCodePage = 932;
  760. break;
  761. case GB2312_CHARSET:
  762. CharSetCodePage = 936;
  763. break;
  764. case HANGEUL_CHARSET:
  765. case JOHAB_CHARSET:
  766. CharSetCodePage = 936;
  767. break;
  768. case CHINESEBIG5_CHARSET:
  769. CharSetCodePage = 950;
  770. break;
  771. }
  772. */
  773. //TRACE("*** GetFirstPFM() = %d\t\tGetLastPFM() = %d\n", cfi.GetFirstPFM(), cfi.GetLastPFM()) ;
  774. pcgm = CGlyphMap::Public(cfi.Translation(), 0, GetDefaultCodePage(),
  775. cfi.GetFirstPFM(), cfi.GetLastPFM()) ;
  776. if (pcgm)
  777. cfi.SetTranslation(pcgm) ;
  778. else
  779. for (unsigned uGTT = 0; uGTT < m_cdr.MapCount(); uGTT++)
  780. if (cfi.Translation() ==
  781. ((WORD) m_cdr.GlyphTable(uGTT).nGetRCID())) {
  782. cfi.SetTranslation(&m_cdr.GlyphTable(uGTT));
  783. break;
  784. }
  785. // Log an error if the UFM could not be generated and stop. Continuing
  786. // could cause things like the RC file and Workspace View to be wrong.
  787. // In addition, delete any partially generated UFM file.
  788. if ((nerrorid = cfi.Generate(cfi.FileName())) != 0) {
  789. CString csfspec ;
  790. csfspec =
  791. (nerrorid == IDS_BadCTTID) ? cfi.SourceName() : cfi.FileName() ;
  792. m_cdr.LogConvInfo(nerrorid, 1, &csfspec) ;
  793. try {
  794. CFile::Remove(cfi.FileName()) ;
  795. }
  796. catch(CFileException* pce) {
  797. pce = pce ;
  798. }
  799. return FALSE;
  800. } ;
  801. }
  802. // Generate the GPD files
  803. if (!m_cdr.ConvertGPCData(*this, wfGPDConvert))
  804. return FALSE; // Error will already have been reported to user.
  805. // Simplest case is no NT versions selected. By definition, we are done.
  806. if (!IsTargetEnabled(WinNT40 | WinNT3x)) {
  807. m_ufStatus |= ConversionsDone;
  808. return TRUE;
  809. }
  810. // Generate the files needed for NT 4.0
  811. if (IsTargetEnabled(WinNT40)) {
  812. if (!CreateStructure(TargetPath(WinNT40), _TEXT("IFI"), _TEXT("RLE")))
  813. return FALSE; // TODO: Feedback
  814. // Generate the RC file
  815. if (!m_cdr.Generate(WinNT40, TargetPath(WinNT40) + '\\' + m_csRCName))
  816. return FALSE; // TODO: Cleanup and feedback
  817. // Update the last time the RC file was written by the MDT timestamp.
  818. GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
  819. // Copy the GPC file
  820. if (!CopyFile(TargetPath(Win95) + m_cdr.GPCName(0),
  821. TargetPath(WinNT40) + m_cdr.GPCName(0), FALSE))
  822. return FALSE; // TODO: Cleanup and feedback
  823. // Generate the RLE files
  824. for (u = 0; u < m_cdr.MapCount(); u++) {
  825. CString csName = TargetPath(WinNT40) + _TEXT("\\RLE\\") +
  826. m_cdr.GlyphTable(u).Name() + _TEXT(".RLE");
  827. CFile cfRLE;
  828. if (!cfRLE.Open(csName,
  829. CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive))
  830. return FALSE; // As usal, TODO: Feedback...
  831. if (!m_cdr.GlyphTable(u).RLE(cfRLE))
  832. return FALSE; // TODO: Ditto
  833. }
  834. // Generate the IFI files
  835. for (u = 0; u < m_cdr.OriginalFontCount(); u++) {
  836. CString csName = TargetPath(WinNT40) + _TEXT("\\IFI\\") +
  837. m_cdr.Font(u).Name() + _TEXT(".IFI");
  838. if (!m_cdr.Font(u).Generate(csName))
  839. return FALSE; // TODO: Ditto
  840. }
  841. }
  842. // Generate the files needed for NT 3.x
  843. if (IsTargetEnabled(WinNT3x)) {
  844. if (!CreateStructure(TargetPath(WinNT3x), _TEXT("IFI"), _TEXT("RLE")))
  845. return FALSE; // TODO: Feedback
  846. // Generate the RC file
  847. if (!m_cdr.Generate(WinNT3x, TargetPath(WinNT3x) + '\\' + m_csRCName))
  848. return FALSE; // TODO: Cleanup and feedback
  849. // Update the last time the RC file was written by the MDT timestamp.
  850. GetRCFileTimeStamp(m_ctRCFileTimeStamp) ;
  851. // Copy the GPC file
  852. if (!CopyFile(TargetPath(Win95) + m_cdr.GPCName(0),
  853. TargetPath(WinNT3x) + m_cdr.GPCName(0), FALSE))
  854. return FALSE; // TODO: Cleanup and feedback
  855. // Generate the RLE files
  856. for (u = 0; u < m_cdr.MapCount(); u++) {
  857. CString csName = TargetPath(WinNT40) + _TEXT("\\RLE\\") +
  858. m_cdr.GlyphTable(u).Name() + _TEXT(".RLE");
  859. CFile cfRLE;
  860. if (!cfRLE.Open(csName,
  861. CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive))
  862. return FALSE; // As usal, TODO: Feedback...
  863. if (!m_cdr.GlyphTable(u).RLE(cfRLE))
  864. return FALSE; // TODO: Ditto
  865. }
  866. // Generate the IFI files
  867. for (u = 0; u < m_cdr.OriginalFontCount(); u++) {
  868. CString csName = TargetPath(WinNT3x) + _TEXT("\\IFI\\") +
  869. m_cdr.Font(u).Name() + _TEXT(".IFI");
  870. if (!m_cdr.Font(u).Generate(csName))
  871. return FALSE; // TODO: Ditto
  872. }
  873. }
  874. m_ufStatus |= ConversionsDone;
  875. return TRUE;
  876. }
  877. /******************************************************************************
  878. CProjectRecord::GPDConversionCheck
  879. If any of the GPD files have unresolved errors from the conversion process,
  880. it will open all of them, if the user asks, so they can fix the problem(s)
  881. forthwith- or leave them for the next time the workspace is edited.
  882. ******************************************************************************/
  883. void CProjectRecord::GPDConversionCheck(BOOL bReportSuccess) {
  884. CUIntArray cuaSuspects;
  885. for (unsigned u = 0; u < m_cdr.Models(); u ++)
  886. if (m_cdr.Model(u).HasErrors())
  887. cuaSuspects.Add(u);
  888. if (!cuaSuspects.GetSize()) {
  889. if (bReportSuccess)
  890. AfxMessageBox(IDS_NoErrorsAnywhere);
  891. return;
  892. }
  893. if (AfxMessageBox(IDS_ConversionErrors, MB_YESNO) == IDNO)
  894. return;
  895. while (cuaSuspects.GetSize()) {
  896. m_cdr.Model(cuaSuspects[0]).Edit();
  897. cuaSuspects.RemoveAt(0);
  898. }
  899. }
  900. /////////////////////////////////////////////////////////////////////////////
  901. // CProjectRecord diagnostics
  902. #ifdef _DEBUG
  903. void CProjectRecord::AssertValid() const {
  904. CDocument::AssertValid();
  905. }
  906. void CProjectRecord::Dump(CDumpContext& dc) const {
  907. CDocument::Dump(dc);
  908. }
  909. #endif //_DEBUG
  910. /////////////////////////////////////////////////////////////////////////////
  911. // CProjectRecord commands
  912. /////////////////////////////////////////////////////////////////////////////
  913. // VerUpdateFilePaths - Verify and update paths/filespecs in workspace file
  914. //
  915. // Use the information read from the workspace file to see if the Win2K RC
  916. // file is where it is supposed to be. If it is, assume that all is ok. If
  917. // not, assume that either the workspace (.MDW) file or the files reference by
  918. // the workspace file have moved.
  919. //
  920. // Tell the user and ask if he wants to locate the RC file for us. If yes,
  921. // prompt for and verify the new RC file path. Reprompt if it is wrong. If
  922. // the user cancels, exit.
  923. //
  924. // Once a path to the RC file is verified, use the file's grandparent
  925. // directory to update the paths used for all UFMs, GTTs, GPDs, and the rest
  926. // of the paths read from the MDW file and managed by this document. The
  927. // grandparent directory is used because it is needed to correct some of
  928. // the filespecs saved in the workspace. All of the Win2K files are
  929. // expected to be in directory(s) beneath the grandparent directory. Lastly,
  930. // set the document's modified flag so that the updated paths can be saved
  931. // later.
  932. //
  933. // void CProjectRecord::VerUpdateFilePaths()
  934. //
  935. // Args:
  936. // None
  937. //
  938. // Returns
  939. // Nothing
  940. //
  941. // Notes
  942. // First, the Workspace View Add/Insert/Clone/Copy context menu commands
  943. // must make sure that the destination files for these commands always
  944. // end up in the appropriate workspace directories for this scheme to
  945. // work.
  946. //
  947. // Second, if it is decided that more than one root directory is needed
  948. // for a workspace, this function will have to prompt for multiple
  949. // directories and then use the appropriate directory to update the paths
  950. // for UFMs, GTTs, GPDs, and the rest of the paths referenced by the
  951. // workspace file.
  952. //
  953. // Third, if this tool is ever enhanced to handle conversions to anything
  954. // other than Win2K drivers, this routine will need to be enhanced to
  955. // handle those cases too.
  956. //
  957. bool CProjectRecord::VerUpdateFilePaths()
  958. {
  959. CFileFind cff ; // Used to find the RC file
  960. bool borig = true ; // True iff the original RC file was found
  961. BOOL bfound ; // True iff an RC file was found
  962. CString csprompt ; // Used to prompt the user
  963. int nresponse = 0 ; // User's response to prompt
  964. // Make a copy of the file path and build a filespec for the Win2000 RC file
  965. CString csrcpath(m_csW2000Path) ;
  966. CString csrcfspec(csrcpath) ;
  967. if (csrcfspec.Right(1) != _T('\\'))
  968. csrcfspec += _T("\\") ;
  969. csrcfspec += m_csRCName ;
  970. // Keep checking for the existence of the RC file and prompting the user
  971. // until the file is found or the user doesn't want to continue any more.
  972. while (true) {
  973. // If the Win2000 RC file exists, we're done so exit.
  974. if (bfound = cff.FindFile(csrcfspec))
  975. break ;
  976. // Explain the situation to the user and ask if they want to tell us where
  977. // the file is. (Only do this the first time.)
  978. if (borig) {
  979. csprompt.Format(IDS_RCFindPrompt, DriverName(), csrcpath) ;
  980. nresponse = AfxMessageBox(csprompt, MB_YESNOCANCEL+MB_ICONQUESTION);
  981. if (nresponse != IDYES)
  982. break ;
  983. } ;
  984. // Prompt the user for a new RC file
  985. CFileDialog cfd(TRUE, _T(".RC"), m_csRCName,
  986. OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
  987. _T("RC File (*.rc)|*.rc||")) ;
  988. cfd.m_ofn.lpstrInitialDir = csrcpath ;
  989. if (cfd.DoModal() != IDOK)
  990. break ;
  991. // Prepare to check the new filespec
  992. csrcfspec = cfd.GetPathName() ;
  993. csrcpath = csrcfspec.Left(csrcfspec.ReverseFind(_T('\\'))) ;
  994. borig = false ;
  995. } ;
  996. // If the original RC file was found or the user did not provide a new
  997. // filespec or the user cancels, just return without changing anything.
  998. // Return false if the user cancelled.
  999. if (borig || !bfound)
  1000. return (nresponse != IDCANCEL) ;
  1001. // When the MDT performs a conversion, the resulting files are put into
  1002. // a directory tree with a root directory like NT4 or Win2K by default. The
  1003. // directory layout and files from that root directory on down are expected
  1004. // to be maintained. The RC file is expected to be in that root directory,
  1005. // too. Therefore, the paths in this workspace up to BUT NOT INCLUDING that
  1006. // root directory must be updated; ie, the path for the RC file's
  1007. // grandparent directory. So, get the new path for the grandparent
  1008. // directory.
  1009. CString csrcnewgrand(csrcpath) ;
  1010. csrcnewgrand = csrcnewgrand.Left(csrcnewgrand.ReverseFind(_T('\\')) + 1) ;
  1011. // As a safety measure, existing paths are only updated if they begin with
  1012. // the RC file's OLD grandparent directory.
  1013. CString csrcoldgrand(m_csW2000Path) ;
  1014. csrcoldgrand = csrcoldgrand.Left(csrcoldgrand.ReverseFind(_T('\\')) + 1) ;
  1015. int noldlen = csrcoldgrand.GetLength() ;
  1016. // Variables used to process arrays of objects and their paths
  1017. unsigned u ;
  1018. unsigned unumobjs ;
  1019. CString cspath ;
  1020. // Update UFM filespecs
  1021. for (unumobjs = m_cdr.FontCount(), u = 0 ; u < unumobjs ; u++) {
  1022. cspath = m_cdr.Font(u).GetPath() ;
  1023. if (cspath.Find(csrcoldgrand) == 0) {
  1024. cspath = csrcnewgrand + cspath.Right(cspath.GetLength() - noldlen) ;
  1025. m_cdr.Font(u).SetPath(cspath) ;
  1026. } ;
  1027. } ;
  1028. // Update GTT filespecs
  1029. for (unumobjs = m_cdr.MapCount(), u = 0 ; u < unumobjs ; u++) {
  1030. cspath = m_cdr.GlyphTable(u).GetPath() ;
  1031. if (cspath.Find(csrcoldgrand) == 0) {
  1032. cspath = csrcnewgrand + cspath.Right(cspath.GetLength() - noldlen) ;
  1033. m_cdr.GlyphTable(u).SetPath(cspath) ;
  1034. } ;
  1035. } ;
  1036. // Update GPD filespecs
  1037. for (unumobjs = m_cdr.Models(), u = 0 ; u < unumobjs ; u++) {
  1038. cspath = m_cdr.Model(u).GetPath() ;
  1039. if (cspath.Find(csrcoldgrand) == 0) {
  1040. cspath = csrcnewgrand + cspath.Right(cspath.GetLength() - noldlen) ;
  1041. m_cdr.Model(u).SetPath(cspath) ;
  1042. } ;
  1043. } ;
  1044. // Now, update the paths that are in the workspace.
  1045. if (m_csSourceRCFile.Find(csrcoldgrand) == 0)
  1046. m_csSourceRCFile = csrcnewgrand + m_csSourceRCFile.Right(m_csSourceRCFile.GetLength() - noldlen) ;
  1047. if (m_csW2000Path.Find(csrcoldgrand) == 0)
  1048. m_csW2000Path = csrcnewgrand + m_csW2000Path.Right(m_csW2000Path.GetLength() - noldlen) ;
  1049. if (m_csNT40Path.Find(csrcoldgrand) == 0)
  1050. m_csNT40Path = csrcnewgrand + m_csNT40Path.Right(m_csNT40Path.GetLength() - noldlen) ;
  1051. if (m_csNT3xPath.Find(csrcoldgrand) == 0)
  1052. m_csNT3xPath = csrcnewgrand + m_csNT3xPath.Right(m_csNT3xPath.GetLength() - noldlen) ;
  1053. if (m_csWin95Path.Find(csrcoldgrand) == 0)
  1054. m_csWin95Path = csrcnewgrand + m_csWin95Path.Right(m_csWin95Path.GetLength() - noldlen) ;
  1055. // Lastly, mark the workspace file as being dirty so that it can be saved
  1056. // later.
  1057. SetModifiedFlag() ;
  1058. return TRUE;
  1059. }
  1060. /******************************************************************************
  1061. CProjectRecord::SaveModified
  1062. This overridable function is used to make sure that the "subdocuments"
  1063. associated with this document that are NOT file based are saved before this
  1064. document closes. The normal saving mechanisms employed by the MFC document
  1065. view architectured don't always work in these cases. The work required to
  1066. save each subdocument is subdocument dependent. The current list of
  1067. subdocuments that fall into this category are:
  1068. o String Table Editor - The editor just modifies the string table portion of
  1069. the RC file that is associated with the documented managed by this
  1070. instance of CProjectRecord. If the editor exists, tell it to save the
  1071. string table. If this succeeds, the document's save flags will be updated
  1072. when needed. If this fails, return FALSE so that the calling function
  1073. will know that this document should not be closed.
  1074. ******************************************************************************/
  1075. BOOL CProjectRecord::SaveModified()
  1076. {
  1077. // Save the string table if it was modified.
  1078. //
  1079. // Begin by getting a pointer to the string editor for this project.
  1080. CMDIChildWnd* pcmcw = m_cdr.GetStringsNode()->GetEditor() ;
  1081. // If there is a string editor, call it to save the string table.
  1082. if (pcmcw != NULL) {
  1083. CStringEditorDoc* pcsed = (CStringEditorDoc*) pcmcw->GetActiveDocument() ;
  1084. // Return FALSE (do not close this document) if the string table needed
  1085. // to be saved but it couldn't be saved because it is invalid.
  1086. if (!pcsed->SaveStringTable()) {
  1087. pcmcw->SetFocus() ;
  1088. return FALSE ;
  1089. } ;
  1090. } ;
  1091. return CDocument::SaveModified();
  1092. }
  1093. /////////////////////////////////////////////////////////////////////////////
  1094. // CGetDefCodePage dialog
  1095. CGetDefCodePage::CGetDefCodePage(CWnd* pParent /*=NULL*/)
  1096. : CDialog(CGetDefCodePage::IDD, pParent)
  1097. {
  1098. //{{AFX_DATA_INIT(CGetDefCodePage)
  1099. // NOTE: the ClassWizard will add member initialization here
  1100. //}}AFX_DATA_INIT
  1101. }
  1102. void CGetDefCodePage::DoDataExchange(CDataExchange* pDX)
  1103. {
  1104. CDialog::DoDataExchange(pDX);
  1105. //{{AFX_DATA_MAP(CGetDefCodePage)
  1106. DDX_Control(pDX, IDC_CodePageList, m_clbCodePages);
  1107. //}}AFX_DATA_MAP
  1108. }
  1109. BEGIN_MESSAGE_MAP(CGetDefCodePage, CDialog)
  1110. //{{AFX_MSG_MAP(CGetDefCodePage)
  1111. //}}AFX_MSG_MAP
  1112. END_MESSAGE_MAP()
  1113. /////////////////////////////////////////////////////////////////////////////
  1114. // CGetDefCodePage message handlers
  1115. BOOL CGetDefCodePage::OnInitDialog()
  1116. {
  1117. CDialog::OnInitDialog();
  1118. // Find out how many code pages are installed on the machine.
  1119. CCodePageInformation ccpi ;
  1120. unsigned unumcps = ccpi.InstalledCount() ;
  1121. // Get the installed code page numbers and load them into the code page
  1122. // list box.
  1123. DWORD dwcp, dwdefcp ;
  1124. dwdefcp = GetACP() ;
  1125. TCHAR accp[32] ;
  1126. int n2 ; ;
  1127. for (unsigned u = 0 ; u < unumcps ; u++) {
  1128. dwcp = ccpi.Installed(u) ;
  1129. StringCchPrintf(accp, CCHOF(accp), _T("%5d"), dwcp) ;
  1130. n2 = m_clbCodePages.AddString(accp) ;
  1131. if (dwcp == dwdefcp)
  1132. m_clbCodePages.SetCurSel(n2) ;
  1133. } ;
  1134. return TRUE; // return TRUE unless you set the focus to a control
  1135. // EXCEPTION: OCX Property Pages should return FALSE
  1136. }
  1137. void CGetDefCodePage::OnOK()
  1138. {
  1139. // Get the index of the currently selected list box item.
  1140. int nsel ;
  1141. if ((nsel = m_clbCodePages.GetCurSel()) == LB_ERR) {
  1142. AfxMessageBox(IDS_MustSelCP, MB_ICONINFORMATION) ;
  1143. return ;
  1144. } ;
  1145. // Get the selected list box string, turn it into a number, and save it.
  1146. CString cs ;
  1147. m_clbCodePages.GetText(nsel, cs) ;
  1148. // Turn the string into a number and convert the number into the
  1149. // corresponding predefined GTT code for Far East code pages when
  1150. // applicable.
  1151. short scp = (short) atoi(cs) ;
  1152. m_dwDefaultCodePageNum = (DWORD) scp ; // Save real CP number first
  1153. switch (scp) {
  1154. case 932:
  1155. scp = -17 ;
  1156. break ;
  1157. case 936:
  1158. scp = -16 ;
  1159. break ;
  1160. case 949:
  1161. scp = -18 ;
  1162. break ;
  1163. case 950:
  1164. scp = -10 ;
  1165. break ;
  1166. } ;
  1167. DWORD dwcp = (DWORD) scp ;
  1168. m_dwDefaultCodePage = dwcp ;
  1169. // All went well so...
  1170. CDialog::OnOK();
  1171. }
  1172. BOOL CProjectRecord::CreateFromNew(CStringArray &csaUFMFiles, CStringArray &csaGTTFiles, CString &csGpdPath, CString &csModelName, CString &csRC,CStringArray& csaRcid)
  1173. {
  1174. // customize GPD keyword value
  1175. CModelData cmd ;
  1176. CString cspath, csmodel, csdll ;
  1177. cspath = csGpdPath.Mid(csGpdPath.ReverseFind('\\') + 1 ) ;
  1178. cmd.SetKeywordValue(csGpdPath,_T("*GPDFileName"),cspath);
  1179. cmd.SetKeywordValue(csGpdPath,_T("*ModelName"),csModelName) ;
  1180. cmd.SetKeywordValue(csGpdPath,_T("*ResourceDLL"),csRC + _T(".dll") ) ;
  1181. // Fill RC member data : m_csRCName, m_csW2000Path ;
  1182. m_csW2000Path = csGpdPath.Left(csGpdPath.ReverseFind('\\') ) ;
  1183. m_csRCName = csRC + _T(".rc") ;
  1184. GetRCFileTimeStamp(m_ctRCFileTimeStamp) ; // set the last time stamp
  1185. SetRCModifiedFlag(TRUE ) ;
  1186. // Set project version
  1187. m_mvMDWVersion.uvernum = MDW_VER_FILES_IN_W2K_TREE ;
  1188. m_dwDefaultCodePage =
  1189. m_dwDefaultCodePageNum = 1252 ;
  1190. // Set project name; top name in the tree
  1191. CString csPrjname;
  1192. csPrjname = m_csW2000Path.Mid(m_csW2000Path.ReverseFind('\\') + 1 ) ;
  1193. Rename(csPrjname ) ;
  1194. // copy the resource data to project member data
  1195. m_cdr.CopyResources(csaUFMFiles,csaGTTFiles, csGpdPath, csaRcid) ;
  1196. return TRUE;
  1197. }