FILE.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:28k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /****************************** Module Header *******************************
  11. * Module Name: file.c
  12. *
  13. * This file contains the high level routines that begin opening
  14. * and saving files.
  15. *
  16. * Functions:
  17. *    Open()
  18. *    BuildFilterString()
  19. *    DoWeSave()
  20. *    Save()
  21. *    OpenCmdLineFile()
  22. *    FileInPath()
  23. *    ShowFileStatus()
  24. *    DifferentDirs()
  25. *    HasPath()
  26. *    WriteDWordPad()
  27. *    BuildDefSaveName()
  28. *    WriteTheFile()
  29. *    FormTempFileName()
  30. *    FileCat()
  31. *
  32. * Comments:
  33. *
  34. ****************************************************************************/
  35. #include "dlgedit.h"
  36. #include "dlgfuncs.h"
  37. #include "dlgextrn.h"
  38. #include "dialogs.h"
  39. #include <wchar.h>
  40. #include <commdlg.h>
  41. /*
  42.  * File types.
  43.  */
  44. #define FILE_RES    0               // Resource (.RES) file.
  45. #define FILE_DLG    1               // Dialog (.DLG) file.
  46. #define FILE_INC    2               // Include (.H) file.
  47. STATICFN VOID BuildDefSaveName(INT FileType, LPTSTR pszFullFileName,
  48.     LPTSTR pszFileName, LPTSTR pszOtherFullFileName, LPTSTR pszOtherFileName,
  49.     LPTSTR pszFullFileNameBuffer, INT cchBuffer);
  50. STATICFN BOOL WriteTheFile(LPTSTR pszFile, INT fmt);
  51. STATICFN VOID FormTempFileName(LPTSTR pszBaseName,  LPTSTR pszBuffer);
  52. STATICFN VOID FileCat(LPTSTR pchName, LPTSTR pchCat, BOOL fChop);
  53. /************************************************************************
  54. * Open
  55. *
  56. * Handles opening of resource and include files.
  57. * Saves current dialog in the resource.
  58. * Might put up a message box.
  59. * Cancels moves.
  60. * Changes szFullResFile, pszResFile, szFullIncludeFile, pszIncludeFile
  61. * Puts up dialog boxes.
  62. * Restores dialog box from resource.
  63. * Sets changed flags.
  64. *
  65. * Arguments:
  66. *   INT FileType - FILE_RESOURCE or FILE_INCLUDE.
  67. *
  68. * Returns:
  69. *   TRUE if successful, FALSE if not.
  70. *
  71. ************************************************************************/
  72. BOOL Open(
  73.     INT FileType)
  74. {
  75.     BOOL fSuccess;
  76.     BOOL fGotName;
  77.     OPENFILENAME ofn;
  78.     TCHAR szNewFileName[CCHMAXPATH];
  79.     TCHAR szInitialDir[CCHMAXPATH];
  80.     TCHAR szFilter[CCHTEXTMAX];
  81.     INT idPrevDlg;
  82.     /*
  83.      * Cancel any outstanding selection(s).
  84.      */
  85.     CancelSelection(TRUE);
  86.     /*
  87.      * Put current dialog back into the resource buffer.
  88.      */
  89.     if (!SynchDialogResource())
  90.         return FALSE;
  91.     /*
  92.      * Begin setting up the globals and the open file dialog structure.
  93.      */
  94.     fSuccess = FALSE;
  95.     *szNewFileName = CHAR_NULL;
  96.     /*
  97.      * Build up the filter string.
  98.      */
  99.     BuildFilterString(FileType, szFilter);
  100.     ofn.lStructSize = sizeof(ofn);
  101.     ofn.hwndOwner = ghwndMain;
  102.     ofn.hInstance = NULL;
  103.     ofn.lpstrFilter = szFilter;
  104.     ofn.lpstrCustomFilter = NULL;
  105.     ofn.nMaxCustFilter = 0;
  106.     ofn.nFilterIndex = 1;
  107.     ofn.lpstrFile = szNewFileName;
  108.     ofn.nMaxFile = CCHMAXPATH;
  109.     ofn.lpstrFileTitle = NULL;
  110.     ofn.nMaxFileTitle = 0;
  111.     if (FileType == FILE_INCLUDE) {
  112.         /*
  113.          * If there is a res file, set the default include file
  114.          * name to open to be the basename of the res file with
  115.          * a .H extension, if such a file exists.  We use szInitialDir
  116.          * here as a temporary buffer.
  117.          */
  118.         if (pszResFile) {
  119.             lstrcpy(szInitialDir, szFullResFile);
  120.             FileCat(szInitialDir, ids(IDS_DOTH), TRUE);
  121.             if (GetFileAttributes(szInitialDir) != -1) {
  122.                 lstrcpy(szNewFileName, pszResFile);
  123.                 FileCat(szNewFileName, ids(IDS_DOTH), TRUE);
  124.             }
  125.         }
  126.         ofn.lpstrTitle = ids(IDS_INCOPENTITLE);
  127.         ofn.lpstrDefExt = ids(IDS_INCEXT);
  128.     }
  129.     else {
  130.         ofn.lpstrTitle = ids(IDS_RESOPENTITLE);
  131.         ofn.lpstrDefExt = ids(IDS_RESEXT);
  132.     }
  133.     /*
  134.      * If they have already opened one res file, start looking for
  135.      * any new files to open in the same directory.  Otherwise, just
  136.      * default to the current directory.
  137.      */
  138.     if (pszResFile) {
  139.         lstrcpy(szInitialDir, szFullResFile);
  140.         *FileInPath(szInitialDir) = CHAR_NULL;
  141.         ofn.lpstrInitialDir = szInitialDir;
  142.     }
  143.     else {
  144.         ofn.lpstrInitialDir = NULL;
  145.     }
  146.     ofn.Flags = OFN_HIDEREADONLY | OFN_SHOWHELP | OFN_FILEMUSTEXIST;
  147.     ofn.lCustData = 0;
  148.     ofn.lpfnHook = NULL;
  149.     ofn.lpTemplateName = NULL;
  150.     /*
  151.      * Fire off the dialog box to open the file.
  152.      */
  153.     EnteringDialog((FileType == FILE_INCLUDE) ?
  154.             DID_COMMONFILEOPENINCLUDE : DID_COMMONFILEOPENRES,
  155.             &idPrevDlg, TRUE);
  156.     fGotName = GetOpenFileName(&ofn);
  157.     EnteringDialog(idPrevDlg, NULL, FALSE);
  158.     if (fGotName) {
  159.         if (FileType == FILE_INCLUDE) {
  160.             if (OpenIncludeFile(szNewFileName)) {
  161.                 /*
  162.                  * Since we just loaded a new include file, we mark the
  163.                  * resource as changed so that the .RES and .DLG files
  164.                  * will be written out with the proper name in the
  165.                  * DLGINCLUDE statement.
  166.                  */
  167.                 gfResChged = TRUE;
  168.                 fSuccess = TRUE;
  169.             }
  170.         }
  171.         else {
  172.             if (OpenResFile(szNewFileName))
  173.                 fSuccess = TRUE;
  174.         }
  175.     }
  176.     ShowFileStatus(TRUE);
  177.     return fSuccess;
  178. }
  179. /************************************************************************
  180. * BuildFilterString
  181. *
  182. * This function creates a filter string to be passed into the
  183. * standard file open and save dialogs.  This will be something like:
  184. * "Resource (*.res)*.res"
  185. *
  186. * Arguments:
  187. *   INT FileType      - Flags for type of file, FILE_INCLUDE, FILE_RESOURCE
  188. *                       or FILE_DLL.
  189. *   LPTSTR pszFilter  - Where to return the filter string.
  190. *
  191. ************************************************************************/
  192. VOID BuildFilterString(
  193.     INT FileType,
  194.     LPTSTR pszFilter)
  195. {
  196.     INT idsFileSpecName;
  197.     INT idsFileSpec;
  198.     LPTSTR psz;
  199.     if (FileType & FILE_INCLUDE) {
  200.         idsFileSpecName = IDS_DEFINCFILESPECNAME;
  201.         idsFileSpec = IDS_DEFINCFILESPEC;
  202.     }
  203.     else if (FileType & FILE_RESOURCE) {
  204.         idsFileSpecName = IDS_DEFRESFILESPECNAME;
  205.         idsFileSpec = IDS_DEFRESFILESPEC;
  206.     }
  207.     else { // Must be a DLL.
  208.         idsFileSpecName = IDS_DEFDLLFILESPECNAME;
  209.         idsFileSpec = IDS_DEFDLLFILESPEC;
  210.     }
  211.     /*
  212.      * Build up the filter string.  This will be something like:
  213.      * "Resource (*.res)*.res"
  214.      */
  215.     psz = (LPTSTR)WriteSz(pszFilter, ids(idsFileSpecName));
  216.     psz = (LPTSTR)WriteSz(psz, ids(idsFileSpec));
  217.     *psz = CHAR_NULL;
  218. }
  219. /************************************************************************
  220. * OpenCmdLineFile
  221. *
  222. * Handles opening of the resource file specified on the command line.
  223. *
  224. * Arguments:
  225. *   LPTSTR - pointer to the file name string
  226. *
  227. ************************************************************************/
  228. VOID OpenCmdLineFile(
  229.     LPTSTR pszFileName)
  230. {
  231.     TCHAR szFullPath[CCHMAXPATH];
  232.     LPTSTR pszOnlyFileName;
  233.     if (SearchPath(L".", pszFileName, ids(IDS_DOTRES), CCHMAXPATH,
  234.             szFullPath, &pszOnlyFileName) == -1) {
  235.         Message(MSG_CANTOPENRES, pszFileName);
  236.     }
  237.     else {
  238.         OpenResFile(szFullPath);
  239.     }
  240. }
  241. /************************************************************************
  242. * DoWeSave
  243. *
  244. * This function checks to see if the include file or the resource file
  245. * needs to be saved.  It first checks the changed flags and if TRUE,
  246. * asks the user if they want to save the file.  If they say yes, it
  247. * calls Save to do the actual work.
  248. *
  249. * Arguments:
  250. *     INT rgbFlags = FILE_RESOURCE or FILE_INCLUDE (but not both).
  251. *
  252. * Returns:
  253. *     IDYES    - The user wanted to save the file AND the save
  254. *                was successful, or the file has not been changed.
  255. *     IDNO     - The file had been changed but the user did not
  256. *                want it saved.
  257. *     IDCANCEL - The file had been changed, and either the user wanted
  258. *                it saved and the save failed, or they specified that
  259. *                they wanted the operation cancelled.
  260. *
  261. ************************************************************************/
  262. INT DoWeSave(
  263.     INT rgbFlags)
  264. {
  265.     LPTSTR pszFile;
  266.     INT MsgCode;
  267.     BOOL fChanged;
  268.     INT nRet = IDYES;
  269.     /*
  270.      * First set variables for current case.
  271.      */
  272.     if (rgbFlags & FILE_RESOURCE) {
  273.         fChanged = gfResChged;
  274.         MsgCode = MSG_CLOSING;
  275.         pszFile = pszResFile ? pszResFile : ids(IDS_UNTITLED);
  276.     }
  277.     else {
  278.         fChanged = gfIncChged;
  279.         MsgCode = MSG_INCLCLOSING;
  280.         pszFile = pszIncludeFile ? pszIncludeFile : ids(IDS_UNTITLED);
  281.     }
  282.     if (fChanged) {
  283.         nRet = Message(MsgCode, pszFile);
  284.         if (nRet == IDYES) {
  285.             if (!Save(FILE_NOSHOW | rgbFlags))
  286.                 nRet = IDCANCEL;
  287.         }
  288.     }
  289.     return nRet;
  290. }
  291. /************************************************************************
  292. * Save
  293. *
  294. * Handles all saving of files based on menu choice.  Does a
  295. * CancelSelection and a SynchDialogResource.
  296. *
  297. * Arguments:
  298. *     INT rgbFlags - Can include FILE_SHOW, FILE_INCLUDE, FILE_SAVEAS.
  299. *
  300. * Returns:
  301. *     TRUE if the file was saved, FALSE if not.
  302. *
  303. ************************************************************************/
  304. BOOL Save(
  305.     INT rgbFlags)
  306. {
  307.     OPENFILENAME ofn;
  308.     BOOL fGotName;
  309.     LPTSTR pszFileName;
  310.     LPTSTR pszFileNameDlg;
  311.     LPTSTR pszFullFileName;
  312.     BOOL fSuccess = FALSE;
  313.     TCHAR szInitialDir[CCHMAXPATH];
  314.     TCHAR szSaveFileName[CCHMAXPATH];
  315.     TCHAR szSaveFileNameDlg[CCHMAXPATH];
  316.     TCHAR szFilter[CCHTEXTMAX];
  317.     INT idPrevDlg;
  318.     /*
  319.      * Put current dialog back into the resource buffer.
  320.      */
  321.     if (!SynchDialogResource())
  322.         return FALSE;
  323.     /*
  324.      * If the file being saved has not been named, force a "Save As".
  325.      */
  326.     if ((rgbFlags & FILE_INCLUDE) ? !pszIncludeFile : !pszResFile)
  327.         rgbFlags |= FILE_SAVEAS;
  328.     if (rgbFlags & FILE_SAVEAS) {
  329.         ofn.lStructSize = sizeof(ofn);
  330.         ofn.hwndOwner = ghwndMain;
  331.         ofn.hInstance = NULL;
  332.         /*
  333.          * Build up the filter string.
  334.          */
  335.         BuildFilterString(rgbFlags, szFilter);
  336.         ofn.lpstrFilter = szFilter;
  337.         ofn.lpstrCustomFilter = NULL;
  338.         ofn.nMaxCustFilter = 0;
  339.         ofn.nFilterIndex = 1;
  340.         ofn.lpstrFile = szSaveFileName;
  341.         ofn.nMaxFile = CCHMAXPATH;
  342.         ofn.lpstrFileTitle = NULL;
  343.         ofn.nMaxFileTitle = 0;
  344.         if (rgbFlags & FILE_INCLUDE) {
  345.             ofn.lpstrTitle = ids(IDS_INCSAVETITLE);
  346.             ofn.lpstrDefExt = ids(IDS_INCEXT);
  347.             BuildDefSaveName(FILE_INCLUDE,
  348.                     szFullIncludeFile, pszIncludeFile,
  349.                     szFullResFile, pszResFile,
  350.                     szInitialDir, CCHMAXPATH);
  351.         }
  352.         else {
  353.             ofn.lpstrTitle = ids(IDS_RESSAVETITLE);
  354.             ofn.lpstrDefExt = ids(IDS_RESEXT);
  355.             BuildDefSaveName(FILE_RESOURCE,
  356.                     szFullResFile, pszResFile,
  357.                     szFullIncludeFile, pszIncludeFile,
  358.                     szInitialDir, CCHMAXPATH);
  359.         }
  360.         /*
  361.          * At this point, szInitialDir contains the full path to
  362.          * the suggested save file name.  Find the end of the path,
  363.          * copy just the filename to the file name buffer and cut
  364.          * the filename portion off the initial directory buffer.
  365.          */
  366.         pszFileName = FileInPath(szInitialDir);
  367.         lstrcpy(szSaveFileName, pszFileName);
  368.         *pszFileName = CHAR_NULL;
  369.         ofn.lpstrInitialDir = szInitialDir;
  370.         ofn.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_SHOWHELP;
  371.         ofn.lCustData = 0;
  372.         ofn.lpfnHook = NULL;
  373.         ofn.lpTemplateName = NULL;
  374.         /*
  375.          * Fire off the dialog box to get the file name to use.
  376.          */
  377.         EnteringDialog((rgbFlags & FILE_INCLUDE) ?
  378.                 DID_COMMONFILESAVEINCLUDE : DID_COMMONFILESAVERES,
  379.                 &idPrevDlg, TRUE);
  380.         fGotName = GetSaveFileName(&ofn);
  381.         EnteringDialog(idPrevDlg, NULL, FALSE);
  382.         if (fGotName) {
  383.             pszFullFileName = szSaveFileName;
  384.             pszFileName = FileInPath(szSaveFileName);
  385.             fSuccess = TRUE;
  386.         }
  387.     }
  388.     else {
  389.         if (rgbFlags & FILE_INCLUDE) {
  390.             pszFileName = pszIncludeFile;
  391.             pszFullFileName = szFullIncludeFile;
  392.         }
  393.         else {
  394.             pszFileName = pszResFile;
  395.             pszFullFileName = szFullResFile;
  396.         }
  397.         fSuccess = TRUE;
  398.     }
  399.     if (fSuccess) {
  400.         if (rgbFlags & FILE_INCLUDE) {
  401.             /*
  402.              * Save include file.
  403.              */
  404.             if (!WriteTheFile(pszFullFileName, FILE_INC)) {
  405.                 Message(MSG_CANTCREATE, pszFileName);
  406.                 fSuccess = FALSE;
  407.             }
  408.         }
  409.         else {
  410.             /*
  411.              * Form the same name as the .res file but with
  412.              * a .dlg extension.
  413.              */
  414.             lstrcpy(szSaveFileNameDlg, pszFullFileName);
  415.             pszFileNameDlg = FileInPath(szSaveFileNameDlg);
  416.             FileCat(pszFileNameDlg, ids(IDS_DOTDLG), TRUE);
  417.             /*
  418.              * Save .RES file, then the .DLG file.  It is done
  419.              * in this order so that makes wil notice that the
  420.              * .dlg file has a newer time stamp than the .res
  421.              * and will cause the .res to be rebuilt.  This
  422.              * could be necessary to pick up other changes
  423.              * in the resources in a project.
  424.              */
  425.             if (!WriteTheFile(pszFullFileName, FILE_RES)) {
  426.                 Message(MSG_CANTCREATE, pszFileName);
  427.                 fSuccess = FALSE;
  428.             }
  429.             else if (!WriteTheFile(szSaveFileNameDlg, FILE_DLG)) {
  430.                 Message(MSG_CANTCREATE, pszFileNameDlg);
  431.                 fSuccess = FALSE;
  432.             }
  433.             else {
  434.                 /*
  435.                  * Successfully saved both files.  Update our
  436.                  * globals.
  437.                  */
  438.                 lstrcpy(szFullResFile, pszFullFileName);
  439.                 pszResFile = FileInPath(szFullResFile);
  440.                 gfResChged = FALSE;
  441.             }
  442.         }
  443.     }
  444.     ShowFileStatus(TRUE);
  445.     return fSuccess;
  446. }
  447. /************************************************************************
  448. * BuildDefSaveName
  449. *
  450. * This function takes the filenames of the current resource and include
  451. * files and builds the default filename that will be shown in the
  452. * "Save As" dialog.  If the current file is still untitled, it will
  453. * attempt to pick a default name based on the other files name.
  454. *
  455. * To use, pass in the file type (FILE_RESOURCE or FILE_INCLUDE) and
  456. * give the current file name and full file name of both the current
  457. * file you are building, and the other type of file.  The following
  458. * rules will be followed, in order:
  459. *
  460. *   1. If the file name is valid (not NULL) and it is either the
  461. *      include file we are naming or it is the res file but there
  462. *      is no include file, it will copy the full file name to the
  463. *      output buffer.
  464. *
  465. *   2. If the other file name is valid, it will take this name, add the
  466. *      appropriate extension and copy it to the output buffer.
  467. *
  468. *   3. If neither of the file names are valid (they are BOTH untitled),
  469. *      it will assume the current directory and make a default file
  470. *      name with the appropriate extension.
  471. *
  472. * Rule 1 is a little complicated, but it's purpose is to make it so
  473. * that if a default res file name is being requested, and they changed
  474. * the directory and/or name for the include file that was just saved,
  475. * the default directory and name for the res file will be the same
  476. * directory and base name as the new include file directory and name.
  477. *
  478. * Arguments:
  479. *   INT FileType                 - Either FILE_RESOURE or FILE_INCLUDE.
  480. *   LPTSTR pszFullFileName       - The full file name.  This will only
  481. *                                  be used if pszFileName is not NULL.
  482. *   LPTSTR pszFileName           - File name to use, or NULL if it is
  483. *                                  currently untitled.
  484. *   LPTSTR pszOtherFullFileName  - Full file name of the other file.  Only
  485. *                                  considered valid if pszOtherFileName is
  486. *                                  not NULL.
  487. *   LPTSTR pszOtherFileName      - File name of the other file, or NULL if
  488. *                                  it is untitled.
  489. *   LPTSTR pszFullFileNameBuffer - Where to put the full file name.
  490. *   INT cchBuffer                - Size of the buffer in characters.
  491. *
  492. ************************************************************************/
  493. STATICFN VOID BuildDefSaveName(
  494.     INT FileType,
  495.     LPTSTR pszFullFileName,
  496.     LPTSTR pszFileName,
  497.     LPTSTR pszOtherFullFileName,
  498.     LPTSTR pszOtherFileName,
  499.     LPTSTR pszFullFileNameBuffer,
  500.     INT cchBuffer)
  501. {
  502.     TCHAR szBuffer[CCHMAXPATH];
  503.     if (pszFileName && (FileType == FILE_INCLUDE || !pszOtherFileName)) {
  504.         /*
  505.          * Simple case.  The file already has a title.
  506.          */
  507.         lstrcpy(pszFullFileNameBuffer, pszFullFileName);
  508.     }
  509.     else if (pszOtherFileName) {
  510.         /*
  511.          * Copy the other files name and add the proper extension.
  512.          */
  513.         lstrcpy(pszFullFileNameBuffer, pszOtherFullFileName);
  514.         FileCat(pszFullFileNameBuffer,
  515.                 (FileType == FILE_INCLUDE) ? ids(IDS_DOTH) :
  516.                 ids(IDS_DOTRES), TRUE);
  517.     }
  518.     else {
  519.         /*
  520.          * Pick a default name in the current directory and
  521.          * add the proper extension.
  522.          */
  523.         lstrcpy(szBuffer, ids(IDS_DEFSAVENAME));
  524.         FileCat(szBuffer,
  525.                 (FileType == FILE_INCLUDE) ? ids(IDS_DOTH) :
  526.                 ids(IDS_DOTRES), TRUE);
  527.         GetFullPathName(szBuffer, cchBuffer, pszFullFileNameBuffer, NULL);
  528.     }
  529. }
  530. /************************************************************************
  531. * WriteTheFile
  532. *
  533. * This function accepts a pointer to a resource buffer and a format
  534. * type.  It writes the buffer out in the appropriate format.  It
  535. * gets the file name from pszFile, adding the appropriate extension
  536. * for the type of file.  The file is first written to a temporary file
  537. * then the old file is removed and finally the new file is renamed.
  538. *
  539. * Arguments:
  540. *   LPTSTR pszFile  - The name to save to.
  541. *   INT fmt         - format to write the buffer out in,
  542. *                     FILE_RES, FILE_INC or FILE_DLG.
  543. *
  544. * Returns:
  545. *     TRUE => File successfully written.
  546. *     FALSE => Failure in writing file.
  547. *
  548. ************************************************************************/
  549. STATICFN BOOL WriteTheFile(
  550.     LPTSTR pszFile,
  551.     INT fmt)
  552. {
  553.     TCHAR szTempFile[CCHMAXPATH]; /* Used for temporary filename            */
  554.     TCHAR szSrcFile[CCHMAXPATH];  /* Source file with proper extension      */
  555.     HANDLE hfWrite;
  556.     HCURSOR hcurSave;
  557.     BOOL fSuccess = FALSE;
  558.     WORD idsExt;
  559.     hcurSave = SetCursor(hcurWait);
  560.     switch (fmt) {
  561.         case FILE_RES:
  562.             idsExt = IDS_DOTRES;
  563.             break;
  564.         case FILE_DLG:
  565.             idsExt = IDS_DOTDLG;
  566.             break;
  567.         case FILE_INC:
  568.             idsExt = IDS_DOTH;
  569.             break;
  570.     }
  571.     /*
  572.      * Append appropriate file name extension.
  573.      */
  574.     lstrcpy(szSrcFile, pszFile);
  575.     FileCat(szSrcFile, ids(idsExt), fmt == FILE_DLG ? TRUE : FALSE);
  576.     /*
  577.      * Generate appropriate temporary file name in the same directory.
  578.      * It is done in the same directory so that a simple rename can
  579.      * be done later.
  580.      */
  581.     FormTempFileName(szSrcFile, szTempFile);
  582.     if ((hfWrite = CreateFile(szTempFile, GENERIC_READ | GENERIC_WRITE,
  583.             FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  584.             NULL)) == (HANDLE)-1)
  585.         goto Exit;
  586.     switch (fmt) {
  587.         case FILE_RES:
  588.             if (!WriteRes(hfWrite, szSrcFile))
  589.                 goto CloseAndExit;
  590.             break;
  591.         case FILE_DLG:
  592.             if (!WriteDlg(hfWrite, szSrcFile))
  593.                 goto CloseAndExit;
  594.             break;
  595.         case FILE_INC:
  596.             if (!WriteInc(hfWrite))
  597.                 goto CloseAndExit;
  598.             break;
  599.     }
  600.     CloseHandle((HANDLE)hfWrite);
  601.     DeleteFile(szSrcFile);
  602.     if (!MoveFile(szTempFile, szSrcFile)) {
  603.         DeleteFile(szTempFile);
  604.         goto Exit;
  605.     }
  606.     fSuccess = TRUE;
  607.     /*
  608.      * If we just wrote to the include file, read it to get the new
  609.      * file offsets, etc.
  610.      */
  611.     if (fmt == FILE_INC) {
  612.         if (!OpenIncludeFile(szSrcFile))
  613.             fSuccess = FALSE;
  614.     }
  615. Exit:
  616.     SetCursor(hcurSave);
  617.     return fSuccess;
  618. CloseAndExit:
  619.     CloseHandle(hfWrite);
  620.     DeleteFile(szTempFile);
  621.     SetCursor(hcurSave);
  622.     return fSuccess;
  623. }
  624. /************************************************************************
  625. * FormTempFileName
  626. *
  627. * This function forms a temporary file name in the provided string.
  628. * The provided string is assumed to have been filled with a filename
  629. * that includes a path.  The temp file will be created in the same
  630. * directory as the file that is currently in the string.
  631. *
  632. * Arguments:
  633. *   LPTSTR pszBaseName - The base name (a filename that includes a path).
  634. *   LPTSTR pszBuffer   - Where to return the
  635. *
  636. ************************************************************************/
  637. STATICFN VOID FormTempFileName(
  638.     LPTSTR pszBaseName,
  639.     LPTSTR pszBuffer)
  640. {
  641.     TCHAR szBuffer[CCHMAXPATH];
  642.     LPTSTR psz;
  643.     /*
  644.      * Cut the base file name down to just the path portion.
  645.      */
  646.     lstrcpy(szBuffer, pszBaseName);
  647.     psz = FileInPath(szBuffer);
  648.     psz--;
  649.     *psz = TEXT('');
  650.     /*
  651.      * Create a temporary file in the same directory.
  652.      */
  653.     GetTempFileName(szBuffer, L"dlg", 0, pszBuffer);
  654. }
  655. /************************************************************************
  656. * FileInPath
  657. *
  658. * This function takes a path and returns a pointer to the file name
  659. * portion of it.  For instance, it will return a pointer to
  660. * "abc.res" if it is given the following path: "c:windowsabc.res".
  661. *
  662. * Arguments:
  663. *   LPTSTR pszPath - Path to look through.
  664. *
  665. ************************************************************************/
  666. LPTSTR FileInPath(
  667.     LPTSTR pszPath)
  668. {
  669.     LPTSTR psz;
  670.     psz = pszPath + lstrlen(pszPath);
  671.     while (psz > pszPath) {
  672.         psz--;
  673.         if (*psz == CHAR_BACKSLASH || *psz == CHAR_COLON) {
  674.             psz++;
  675.             break;
  676.         }
  677.     }
  678.     return psz;
  679. }
  680. /************************************************************************
  681. * FileCat
  682. *
  683. * This function puts the extension pchCat on the file spec pch.
  684. * If fChop, this is done regardless of whether pch has an extension
  685. * or not (replacing the old extension).  Otherwise, pchCat is added
  686. * only if there is no extension on the spec pch.
  687. *
  688. * Arguments:
  689. *     LPTSTR pch        - The file spec to "cat" the extension to.
  690. *     LPTSTR pchCat     - The extension to "cat" on to pch,
  691. *                         including the '.'
  692. *
  693. ************************************************************************/
  694. STATICFN VOID FileCat(
  695.     LPTSTR pchName,
  696.     LPTSTR pchCat,
  697.     BOOL fChop)
  698. {
  699.     LPTSTR pch;
  700.     pch = pchName + lstrlen(pchName);
  701.     pch--;
  702.     /* back up to '.' or '\' */
  703.     while (*pch != CHAR_DOT) {
  704.         if (*pch == CHAR_BACKSLASH || pch <= pchName) {
  705.             /* no extension, add one */
  706.             lstrcat(pchName, pchCat);
  707.             return;
  708.         }
  709.         pch--;
  710.     }
  711.     if (fChop)
  712.         lstrcpy(pch, pchCat);
  713. }
  714. /************************************************************************
  715. * ShowFileStatus
  716. *
  717. * This function displays the title of the Dialog Editor, along with
  718. * the file names for the RES and H files with asterisks if they have
  719. * changed.  It displays this information only if one of these items
  720. * has changed or if fForce is TRUE.
  721. *
  722. * Arguments:
  723. *   BOOL fForce - TRUE if the title should be updated even if the value
  724. *                 of gfResChged or gfIncChged has not changed since the
  725. *                 last call.  This function should be called with fForce
  726. *                 equal to TRUE if it is known that one of the file names
  727. *                 has just been changed.
  728. *
  729. ************************************************************************/
  730. VOID ShowFileStatus(
  731.     BOOL fForce)
  732. {
  733.     static BOOL fResChgedSave = FALSE;
  734.     static BOOL fIncChgedSave = FALSE;
  735.     TCHAR szTitle[CCHTEXTMAX];
  736.     if (gfResChged != fResChgedSave || gfIncChged != fIncChgedSave ||
  737.             fForce) {
  738.         lstrcpy(szTitle, ids(IDS_DLGEDIT));
  739.         lstrcat(szTitle, L" - ");
  740.         lstrcat(szTitle, pszResFile ? pszResFile : ids(IDS_UNTITLED));
  741.         if (gfResChged)
  742.             lstrcat(szTitle, L"*");
  743.         lstrcat(szTitle, L", ");
  744.         lstrcat(szTitle, pszIncludeFile ? pszIncludeFile : ids(IDS_UNTITLED));
  745.         if (gfIncChged)
  746.             lstrcat(szTitle, L"*");
  747.         SetWindowText(ghwndMain, szTitle);
  748.         fResChgedSave = gfResChged;
  749.         fIncChgedSave = gfIncChged;
  750.     }
  751. }
  752. /************************************************************************
  753. * DifferentDirs
  754. *
  755. * This function returns TRUE if the given full paths are to files
  756. * that are in different directories.
  757. *
  758. * Arguments:
  759. *   LPTSTR pszPath1 - First path.
  760. *   LPTSTR pszPath2 - Second path.
  761. *
  762. ************************************************************************/
  763. BOOL DifferentDirs(
  764.     LPTSTR pszPath1,
  765.     LPTSTR pszPath2)
  766. {
  767.     INT nLen1;
  768.     INT nLen2;
  769.     LPTSTR pszFile1;
  770.     LPTSTR pszFile2;
  771.     pszFile1 = FileInPath(pszPath1);
  772.     pszFile2 = FileInPath(pszPath2);
  773.     nLen1 = lstrlen(pszPath1) - lstrlen(pszFile1);
  774.     nLen2 = lstrlen(pszPath2) - lstrlen(pszFile2);
  775.     if (nLen1 != nLen2 || _wcsnicmp(pszPath1, pszPath2, nLen1) != 0)
  776.         return TRUE;
  777.     else
  778.         return FALSE;
  779. }
  780. /************************************************************************
  781. * HasPath
  782. *
  783. * This function returns TRUE if the given filespec includes a path
  784. * specification.  It returns false if it is a filename without a
  785. * path.
  786. *
  787. * A filespec is considered to have a path if a backslash character ()
  788. * is found in it.
  789. *
  790. * Arguments:
  791. *   LPTSTR pszFileSpec - File spec to check.
  792. *
  793. ************************************************************************/
  794. BOOL HasPath(
  795.     LPTSTR pszFileSpec)
  796. {
  797.     LPTSTR psz;
  798.     for (psz = pszFileSpec; *psz; psz = CharNext(psz))
  799.         if (*psz == CHAR_BACKSLASH)
  800.             return TRUE;
  801.     return FALSE;
  802. }
  803. /************************************************************************
  804. * WriteDWordPad
  805. *
  806. * This function writes nulls to the specified file until it is
  807. * dword aligned.  If the file is already dword aligned, nothing
  808. * will be written.
  809. *
  810. * Arguments:
  811. *   HANDLE hf    - The file to write to.
  812. *   DWORD cbFile - Where the file pointer is at in the file.
  813. *
  814. * Returns:
  815. *   TRUE if successful, FALSE otherwise.
  816. *
  817. ************************************************************************/
  818. BOOL WriteDWordPad(
  819.     HANDLE hf,
  820.     DWORD cbFile)
  821. {
  822.     static BYTE Buf[3] = {0, 0, 0};
  823.     WORD cb;
  824.     cb = (WORD)((4 - (((WORD)cbFile) & 3)) % 4);
  825.     if (cb) {
  826.         if (_lwrite((HFILE)hf, (LPSTR)Buf, cb) == -1)
  827.             return FALSE;
  828.     }
  829.     return TRUE;
  830. }