home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / WIN_UTL2 / VULCAN.ZIP / VULSRC.ZIP / BROWSE.CPP next >
C/C++ Source or Header  |  1994-02-08  |  21KB  |  449 lines

  1. // BROWSE.CPP Part of VULCAN
  2. // Copyright (c) 1993 John Deurbrouck
  3. #include<windows.h>
  4. #include<stdio.h>
  5. #include<dos.h>
  6. #include<fcntl.h>
  7. #include<time.h>
  8. #include<commdlg.h>
  9. #include<sys\types.h>
  10. #include<sys\stat.h>
  11. #include"browse.hpp"
  12. #include"cancel.hpp"
  13. #include"vulcan.hpp"
  14. #include"filedate.hpp"
  15. #include"resource.h"
  16. #include"vcn.hpp"
  17.  
  18. static const int FILENAME_BUFFER_SIZE=130;//per OPENFILENAME info on nMaxFile
  19. static const int BROWSE_BUF_ITEMS=512;
  20.  
  21. static FARPROC lpfnBrowseDlgProc=NULL;
  22. HWND hBrowseDlg=NULL;
  23. static long browse_buf[BROWSE_BUF_ITEMS];
  24.  
  25. static int nuke_and_fill_listbox();
  26. static int restore_file(vcn_info& vi,char* target_name=NULL);// 0=wanna quit
  27. static int get_saveas_location(vcn_info& vi,char* buf,size_t siz);//1=success
  28.  
  29. BOOL FAR PASCAL _export BrowseDlgProc(HWND hDlg,unsigned message,WORD wParam,
  30. LONG lParam){
  31.     switch(message){
  32.     case WM_COMMAND:
  33.         switch(wParam){
  34.         case IDC_BLIST: // LBN_xxx
  35.             switch(HIWORD(lParam)){
  36.             case LBN_SETFOCUS:
  37.             case LBN_SELCHANGE:
  38.                 // first enable/disable appropriate buttons
  39.                 LRESULT numitems=SendDlgItemMessage(hBrowseDlg,IDC_BLIST,
  40.                     LB_GETSELCOUNT,0,0L);
  41.                 if(!numitems){ // disable all but cancel
  42.                     EnableWindow(GetDlgItem(hDlg,IDC_BRESTORE),  FALSE);
  43.                     EnableWindow(GetDlgItem(hDlg,IDC_BRESTOREAS),FALSE);
  44.                     EnableWindow(GetDlgItem(hDlg,IDC_BDELETE),   FALSE);
  45.                 }
  46.                 else if(numitems==1){ // enable all
  47.                     EnableWindow(GetDlgItem(hDlg,IDC_BRESTORE),  TRUE );
  48.                     EnableWindow(GetDlgItem(hDlg,IDC_BRESTOREAS),TRUE );
  49.                     EnableWindow(GetDlgItem(hDlg,IDC_BDELETE),   TRUE );
  50.                 }
  51.                 else{ // enable all but Restore As...
  52.                     EnableWindow(GetDlgItem(hDlg,IDC_BRESTORE),  TRUE );
  53.                     EnableWindow(GetDlgItem(hDlg,IDC_BRESTOREAS),FALSE);
  54.                     EnableWindow(GetDlgItem(hDlg,IDC_BDELETE),   TRUE );
  55.                 }
  56.                 // user moved cursor, paint appropriate file data
  57.                 LRESULT l=SendDlgItemMessage(hBrowseDlg,IDC_BLIST,
  58.                     LB_GETCARETINDEX,0,0L);
  59.                 LRESULT idx=SendDlgItemMessage(hBrowseDlg,IDC_BLIST,
  60.                     LB_GETITEMDATA,(WPARAM)l,0L);
  61.                 vcn_info vi;
  62.                 if(vcnGetInfo((long)idx,vi)){
  63.                                                         // IDC_BS_FILENAME
  64.                     wsprintf(pacBigScratchBuffer,"Name: %s",
  65.                         (LPSTR)vi.FileName);
  66.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_FILENAME,
  67.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  68.                                                         // IDC_BS_SSIZE
  69.                     wsprintf(pacBigScratchBuffer,"File size: %ld",
  70.                         vi.StoredSize);
  71.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_SSIZE,
  72.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  73.                                                         // IDC_BS_SDT
  74.                     get_ascii_time(pacBigScratchBuffer2,
  75.                         vi.StoredTime,vi.StoredDate);
  76.                     wsprintf(pacBigScratchBuffer,"When stored: %s",
  77.                         (LPSTR)pacBigScratchBuffer2);
  78.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_SDT,
  79.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  80.                                                         // IDC_BS_INDEX
  81.                     wsprintf(pacBigScratchBuffer,"Vulcan name: %08ld.VCN",
  82.                         vi.Index);
  83.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_INDEX,
  84.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  85. #ifdef COMPRESSION
  86.                                                         // IDC_BS_COMPRESSED
  87.                     wsprintf(pacBigScratchBuffer,"File is%scompressed",
  88.                         (LPSTR)(vi.compressed?" ":" not "));
  89.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_COMPRESSED,
  90.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  91. #endif
  92.                                                         // IDC_BS_OSIZE
  93.                     wsprintf(pacBigScratchBuffer,"File size: %ld",
  94.                         vi.FileSize);
  95.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_OSIZE,
  96.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  97.                                                         // IDC_BS_OATTR
  98.                     if(!(vi.Attrib&(_A_ARCH|_A_HIDDEN|_A_SYSTEM|_A_RDONLY)))
  99.                         lstrcpy(pacBigScratchBuffer,"Attributes: --none--");
  100.                     else{
  101.                         lstrcpy(pacBigScratchBuffer,"Attributes:");
  102.                         if(vi.Attrib&_A_ARCH)
  103.                             lstrcat(pacBigScratchBuffer," Arch");
  104.                         if(vi.Attrib&_A_RDONLY)
  105.                             lstrcat(pacBigScratchBuffer," R/O");
  106.                         if(vi.Attrib&_A_HIDDEN)
  107.                             lstrcat(pacBigScratchBuffer," Hid");
  108.                         if(vi.Attrib&_A_SYSTEM)
  109.                             lstrcat(pacBigScratchBuffer," Sys");
  110.                     }
  111.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_OATTR,
  112.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  113.                                                         // IDC_BS_ODT
  114.                     get_ascii_time(pacBigScratchBuffer2,
  115.                         vi.FileTime,vi.FileDate);
  116.                     wsprintf(pacBigScratchBuffer,"Date && time: %s",
  117.                         (LPSTR)pacBigScratchBuffer2);
  118.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_ODT,
  119.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  120.                                                         // IDC_BS_FULLPATH
  121.                     wsprintf(pacBigScratchBuffer,"Path: %s",
  122.                         (LPSTR)vi.FullName);
  123.                     SendDlgItemMessage(hBrowseDlg,IDC_BS_FULLPATH,
  124.                         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  125.                 }
  126.                 break;
  127.             }
  128.             return FALSE;
  129.         case IDM_GETSTARTED:
  130.             if(!nuke_and_fill_listbox()){
  131.                 MessageBox(CURR_WINDOW,"Can't load list box",
  132.                     szAppErrorTitle,MB_OK);
  133.             }
  134.             SetFocus(GetDlgItem(hDlg,IDC_BLIST));
  135.             return FALSE; // because set focus
  136.         case IDCANCEL:
  137.             EndDialog(hDlg,0); //==++
  138.             hBrowseDlg=NULL;
  139.             EnableWindow(hMainWindow,TRUE);
  140.             return TRUE;
  141.         case IDC_BRESTORE:
  142.         case IDC_BRESTOREAS:
  143.         case IDC_BDELETE:
  144.             for(;;){ // just keep driving until done...
  145.                 LRESULT numitems=SendDlgItemMessage(hBrowseDlg,IDC_BLIST,
  146.                     LB_GETSELCOUNT,0,0L);
  147.                 if(numitems>BROWSE_BUF_ITEMS){
  148.                     wsprintf(pacBigScratchBuffer,"You selected %ld files. "
  149.                         "Vulcan can handle no more than %ld.\n\n"
  150.                         "Please alter your selection and try again.",
  151.                         (long)numitems,(long)BROWSE_BUF_ITEMS);
  152.                     MessageBox(CURR_WINDOW,pacBigScratchBuffer,
  153.                         szAppErrorTitle,MB_OK);
  154.                     break;
  155.                 }
  156.                 LRESULT actual=SendDlgItemMessage(hBrowseDlg,IDC_BLIST,
  157.                     LB_GETSELITEMS,
  158.                     BROWSE_BUF_ITEMS,(LPARAM)(LPSTR)browse_buf);
  159.                 if((actual!=numitems)||(actual<1)||
  160.                 ((wParam==IDC_BRESTOREAS)&&(actual!=(LRESULT)1))){
  161.                     MessageBox(CURR_WINDOW,"Could not process command. "
  162.                         "Please try again.",szAppErrorTitle,MB_OK);
  163.                     break;
  164.                 }
  165.                 // ok now translate list box indexes to actual numbers
  166.                 // work from end of int array to beginning, writing
  167.                 //  into long array occupying same space
  168.                 int x=(int)actual;
  169.                 int *intptr=(int *)browse_buf;
  170.                 while(x--){
  171.                     LRESULT idx=SendDlgItemMessage(hBrowseDlg,IDC_BLIST,
  172.                         LB_GETITEMDATA,(WPARAM)intptr[x],0L);
  173.                     vcn_info vi;
  174.                     if(!vcnGetInfo((long)idx,vi)){
  175.                         actual=0;
  176.                         break;
  177.                     }
  178.                     browse_buf[x]=vi.Index;
  179.                 }
  180.                 if(!actual){
  181.                     MessageBox(CURR_WINDOW,"Could not retrieve information "
  182.                         "on file. Please close VULCAN and try again.",
  183.                         szAppErrorTitle,MB_OK);
  184.                     break;
  185.                 }
  186.                 start_cancel_dialog_box(); // so we can show progress
  187.                 // now we have array of 'actual' longs in browse_buf
  188.                 // these are vcn_info.Index values, on which the action
  189.                 //  should be taken...so do it
  190.                 while(actual--){ // now actual is index into browse_buf
  191.                     char *p;
  192.                     switch(wParam){ // first prepare cancel dialog box
  193.                     case IDC_BRESTOREAS:p="Restoring this file elsewhere";
  194.                                                             break;
  195.                     case IDC_BRESTORE:  p="Restoring";      break;
  196.                     case IDC_BDELETE:   p="Deleting";       break;
  197.                     }
  198.                     vcn_info vi; // now get data on file by Index no
  199.                     if(!vcnGetInfo(browse_buf[actual],vi)){
  200.                         wsprintf(pacBigScratchBuffer,"Couldn't get data on "
  201.                             "%08ld.VCN. File skipped.",browse_buf[actual]);
  202.                         MessageBox(CURR_WINDOW,pacBigScratchBuffer,
  203.                             szAppErrorTitle,MB_OK);
  204.                         continue;
  205.                     }
  206.                     // show cancel box text
  207.                     set_cancel_dialog_box_text(p,vi.FullName);
  208.                     // perform deletes here
  209.                     if(wParam==IDC_BDELETE){
  210.                         if(check_cancel_dialog_box())break;
  211.                         vcnDeleteItem(vi.Index);
  212.                         continue; // delete processing all done
  213.                     }
  214.                     // for Restore As... must get user's target filename
  215.                     char target_filename[FILENAME_BUFFER_SIZE];
  216.                     if(wParam==IDC_BRESTOREAS){
  217.                         if(!get_saveas_location(vi,target_filename,
  218.                         sizeof(target_filename))){
  219.                             break;
  220.                         }
  221.                         // got location, show new data
  222.                         wsprintf(pacBigScratchBuffer,
  223.                             "Saving %s to",(LPSTR)vi.FileName);
  224.                         set_cancel_dialog_box_text(pacBigScratchBuffer,
  225.                             target_filename);
  226.                     }
  227.                     // now restore the file...bail out if user quit
  228.                     if(!restore_file(vi,wParam==IDC_BRESTOREAS?
  229.                     target_filename:NULL)){
  230.                         break;
  231.                     }
  232.                 }
  233.                 end_cancel_dialog_box(); // so browse box lives again
  234.                 // refresh listbox if deleted items
  235.                 if(wParam==IDC_BDELETE)nuke_and_fill_listbox();
  236.                 break;
  237.             }
  238.             // for all these, gather the selections
  239.             return TRUE;
  240.         }
  241.         return TRUE;
  242.     case WM_INITDIALOG:
  243.         hBrowseDlg=hDlg;
  244.         PostMessage(hDlg,WM_COMMAND,IDM_GETSTARTED,0L);
  245.         return TRUE;
  246.     default:
  247.         return FALSE;
  248.     }
  249. }
  250. void start_browse_dialog_box(void){
  251.     lpfnBrowseDlgProc=MakeProcInstance((int(__far __pascal *)
  252.         (void))BrowseDlgProc,hMainInstance);
  253.     DialogBox(hMainInstance,
  254.         MAKEINTRESOURCE(IDD_BROWSEDIALOG),CURR_WINDOW,lpfnBrowseDlgProc);
  255.     hBrowseDlg=NULL;
  256. //    if(hCancelDlg!=NULL)EnableWindow(hMainWindow,FALSE); ==++
  257. }
  258. static int nuke_and_fill_listbox(){
  259.     // 1 is success, 0 is fail
  260.     SendDlgItemMessage(hBrowseDlg,IDC_BLIST,LB_RESETCONTENT,0,0L); //empty it
  261.     // initialize static text fields too
  262.     lstrcpy(pacBigScratchBuffer," ");
  263.     SendDlgItemMessage(hBrowseDlg,IDC_BS_FILENAME,
  264.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  265.     SendDlgItemMessage(hBrowseDlg,IDC_BS_SSIZE,
  266.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  267.     SendDlgItemMessage(hBrowseDlg,IDC_BS_SDT,
  268.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  269.     SendDlgItemMessage(hBrowseDlg,IDC_BS_INDEX,
  270.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  271. #ifdef COMPRESSION
  272.     SendDlgItemMessage(hBrowseDlg,IDC_BS_COMPRESSED,
  273.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  274. #endif
  275.     SendDlgItemMessage(hBrowseDlg,IDC_BS_OSIZE,
  276.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  277.     SendDlgItemMessage(hBrowseDlg,IDC_BS_OATTR,
  278.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  279.     SendDlgItemMessage(hBrowseDlg,IDC_BS_ODT,
  280.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  281.     SendDlgItemMessage(hBrowseDlg,IDC_BS_FULLPATH,
  282.         WM_SETTEXT,0,(LONG)(LPSTR)pacBigScratchBuffer);
  283.     // also turn RESTORE, RESTORE AS... and DELETE buttons off
  284.     EnableWindow(GetDlgItem(hBrowseDlg,IDC_BRESTORE),  FALSE);
  285.     EnableWindow(GetDlgItem(hBrowseDlg,IDC_BRESTOREAS),FALSE);
  286.     EnableWindow(GetDlgItem(hBrowseDlg,IDC_BDELETE),   FALSE);
  287.     // now set the tab stops for the listbox control
  288.     int tabstops=100;
  289.     SendDlgItemMessage(hBrowseDlg,IDC_BLIST,LB_SETTABSTOPS,1,
  290.         (LPARAM)(int FAR*)&tabstops);
  291.     // now loop through all items, adding to list box
  292.     long head,tail;
  293.     vcnGetFilenumberRange(tail,head);
  294.     if(head<tail)return 1; // no items, return
  295.     vcn_info vi;
  296.     if(!vcnGetInfo(head,vi))return 0;
  297.     do{
  298.         wsprintf(pacBigScratchBuffer,"%s\t%c",
  299.             (LPSTR)vi.FileName,(char)vi.DispChar);
  300.         LRESULT res=SendDlgItemMessage(hBrowseDlg,IDC_BLIST,LB_ADDSTRING,0,
  301.             (LPARAM)(LPCSTR)pacBigScratchBuffer);
  302.         if(res==LB_ERR)return 0;
  303.         res=SendDlgItemMessage(hBrowseDlg,IDC_BLIST,LB_SETITEMDATA,
  304.             (WPARAM)res,(LPARAM)vi.Index);
  305.         if(res==LB_ERR)return 0;
  306.     }while(vcnGetRecordBefore(vi.Index,vi));
  307.     return 1;
  308. }
  309. static int restore_file(vcn_info& vi,char* target_name){
  310.     // 0=wanna quit nonzero=user wants to continue
  311.     // will return nonzero even if file doesn't copy
  312.     // first open the origin file
  313.     int ifh,ofh; // input and output file handle
  314.     wsprintf(pszTargetDirFile,"%08ld.VCN",vi.Index);
  315.     {
  316.         vcn_info junker;
  317.         if(_dos_open(szTargetDirectory,_O_RDONLY,&ifh)|| // input no open
  318.         !vcnReadEntry(&junker,pacBigScratchBuffer,ifh)){
  319.             wsprintf(pacBigScratchBuffer,"Could not open or read %s. "
  320.                 "Restore failed.",(LPSTR)szTargetDirectory);
  321.             MessageBox(CURR_WINDOW,pacBigScratchBuffer,szAppErrorTitle,MB_OK);
  322.             return 1; // all done
  323.         }
  324.     } // now ifh is queued up to beginning of file data
  325.     // now check if target file exists, confirm if necessary
  326.     LPSTR target_pointer;
  327.     if(target_name==NULL){ // destination is vi.FullName
  328.         struct _stat statbuf;
  329.         target_pointer=vi.FullName;
  330.         if(WarnOnOverwrite){ // see if file exists already
  331.             lstrcpy(pacBigScratchBuffer,target_pointer);
  332.             if(!_stat(pacBigScratchBuffer,&statbuf)){ // yep it's there
  333.                 wsprintf(pacBigScratchBuffer,
  334.                     "Restoring %s will overwrite a file. Do you want to "
  335.                     "proceed?\n\n"
  336.                     "YES means go ahead and overwrite.\n\n"
  337.                     "NO means cancel restoration of this file\n\n",
  338.                     target_pointer);
  339.                 switch(MessageBox(CURR_WINDOW,pacBigScratchBuffer,
  340.                 szAppWarningTitle,MB_YESNO)){
  341.                 case IDYES:                             break; // go ahead
  342.                 case IDNO:          _dos_close(ifh);    return 1; // quit
  343.                 }
  344.             }
  345.         }
  346.     }
  347.     else{
  348.         target_pointer=(LPSTR)target_name; // overwrite already confirmed
  349.     }
  350.     // delete target file if it exists
  351.     lstrcpy(pacBigScratchBuffer,target_pointer);
  352.     _dos_setfileattr(pacBigScratchBuffer,_A_NORMAL);
  353.     remove(pacBigScratchBuffer);
  354.     // create the target file
  355.     if(_dos_creat(pacBigScratchBuffer,vi.Attrib,&ofh)){
  356.         wsprintf(pacBigScratchBuffer2,
  357.             "Could not create output file %s.\n\nRestore failed.",
  358.             (LPSTR)pacBigScratchBuffer);
  359.         MessageBox(CURR_WINDOW,pacBigScratchBuffer2,szAppErrorTitle,MB_OK);
  360.         _dos_close(ifh);
  361.         return 1;
  362.     } // now ifh and ofh ready to go
  363.     // pacBigScratchBuffer also hold output filename
  364.     // read a buffer of data at a time
  365.     long filebytes=vi.FileSize;
  366.     while(filebytes){
  367.         unsigned thistime=(unsigned)sizeof(pacBigScratchBuffer2);
  368.         int userquit=0;
  369.         unsigned actual_read,actual_write;
  370.         if((long)thistime>filebytes)thistime=(unsigned)filebytes;
  371.         if((userquit=check_cancel_dialog_box())|| // user quit
  372.         _dos_read(ifh,pacBigScratchBuffer2,thistime,&actual_read)|| // input
  373.         actual_read!=thistime|| // didn't get enough data
  374.         _dos_write(ofh,pacBigScratchBuffer2,thistime,&actual_write)|| //out
  375.         actual_write!=thistime   // didn't write all data
  376.         ){                      // handle failure case by shutting down
  377.             _dos_close(ifh);
  378.             _dos_close(ofh);
  379.             _dos_setfileattr(pacBigScratchBuffer,_A_NORMAL);
  380.             remove(pacBigScratchBuffer);
  381.             if(!userquit){
  382.                 wsprintf(pacBigScratchBuffer2,
  383.                     "Read or write error copying to %s. Restore "
  384.                     "aborted.",(LPSTR)pacBigScratchBuffer);
  385.                 MessageBox(CURR_WINDOW,pacBigScratchBuffer2,
  386.                     szAppErrorTitle,MB_OK);
  387.             }
  388.             return userquit?0:1;
  389.         }
  390.         filebytes-=(long)thistime; // well, this buffer-full went ok
  391.     } // after loop, file is copied
  392.     // now close input file
  393.     _dos_close(ifh);
  394.     // set file date, time
  395.     _dos_setftime(ofh,vi.FileDate,vi.FileTime);
  396.     // close output file
  397.     _dos_close(ofh);
  398.     return 1;
  399. }
  400. static int get_saveas_location(vcn_info& vi,char* buf,size_t bufsiz){
  401.     // 1=success, filename copied to buf
  402.     // 0=fail, user pressed cancel
  403.     // copy incoming filename to buf
  404.     lstrcpy(buf,vi.FileName);
  405.     // now create initial directory string
  406.     char dirbuf[FILENAME_BUFFER_SIZE];
  407.     lstrcpy(dirbuf,vi.FullName);
  408.     // now complete name is in dirbuf...let's strip off filename
  409.     {
  410.         char *p=dirbuf;
  411.         while(*p)p++; // point at null terminator
  412.         while(*p!='\\')*p--; // point at trailing backslash
  413.         if(p[-1]==':')p++; // don't kill backslash if root
  414.         *p=0;
  415.     }
  416.     // create title bar
  417.     wsprintf(pacBigScratchBuffer,"Vulcan -- Restore %s as",
  418.         (LPSTR)vi.FileName);
  419.     OPENFILENAME ofn;
  420.     // setup structure for common dialog box
  421.     ofn.lStructSize=sizeof(ofn);
  422.     ofn.hwndOwner=CURR_WINDOW;
  423.     ofn.hInstance=hMainInstance;
  424.     ofn.lpstrFilter="All files\0*.*\0";
  425.     ofn.lpstrCustomFilter=NULL;
  426.     ofn.nMaxCustFilter=0;
  427.     ofn.nFilterIndex=1;
  428.     ofn.lpstrFile=buf; // full path name to existing file
  429.     ofn.nMaxFile=bufsiz;
  430.     ofn.lpstrFileTitle=NULL;
  431.     ofn.nMaxFileTitle=0;
  432.     ofn.lpstrInitialDir=dirbuf;
  433.     ofn.lpstrTitle=pacBigScratchBuffer;
  434.     ofn.Flags=OFN_HIDEREADONLY|     // Save As read-only???
  435.         OFN_PATHMUSTEXIST;          // can't restore to nonexistent place
  436.     if(WarnOnOverwrite)
  437.         ofn.Flags|=OFN_OVERWRITEPROMPT; // let user know overwriting...
  438.     ofn.nFileOffset=0;
  439.     ofn.nFileExtension=0;
  440.     ofn.lpstrDefExt=NULL;
  441.     ofn.lCustData=NULL;
  442.     ofn.lpfnHook=NULL;
  443.     ofn.lpTemplateName=NULL;
  444.     // call common dialog box
  445.     if(!GetSaveFileName(&ofn))return 0;
  446.     // anaylze return...valid?
  447.     return 1;
  448. }
  449.