home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / Ph 1.1.1 / Lib / vol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-28  |  21.1 KB  |  712 lines  |  [TEXT/MPS ]

  1. /*______________________________________________________________________
  2.  
  3.     vol.c - Volume Selection Module.
  4.     
  5.     Copyright © 1988-1991 Northwestern University.
  6.     
  7.     This reusable module implements volume selection as in Apple's 
  8.     standard file package.
  9.     
  10.     The caller supplies a Drive button, an Eject button, and a rectangle
  11.     in which the name of the currently selected volume should be displayed.
  12.     
  13.     The module takes care of cycling through selected on-line volumes,
  14.     processing hits in the drive and eject buttons, properly hiliting
  15.     these buttons, processing disk insertion events, and drawing the 
  16.     volume name in response to update events.
  17.     
  18.     In addition to the volume name displayed in a rectangle, the caller 
  19.     can also request that small floppy and hard drive icons be displayed.  
  20.     The module displays the appropriate small icon in a caller-specified 
  21.     rectangle.  The caller supplies the small icons.
  22.     
  23.     If the current system supports popup menus, the volume name rectangle is
  24.     framed with a drop shadow.  If the user clicks in this rectangle a popup
  25.     menu is presented listing all mounted volumes.
  26.     
  27.     All of the routines do error checking, and return an error code
  28.     as their function result.
  29.     
  30.     This module should only be used in a modal environment (e.g., modal
  31.     dialogs).  The reason is that it assumes only it is mounting and
  32.     unmounting volumes.  In a non-modal environment this assumption
  33.     is invalid.
  34.     
  35.     All of the code placed in its own segment named "vol", except for the
  36.     vol_Init routine, which is placed in segment voli.
  37. _____________________________________________________________________*/
  38.  
  39. #pragma load "precompile"
  40. #include "vol.h"
  41. #include "utl.h"
  42.  
  43. #pragma segment vol
  44.  
  45. /*______________________________________________________________________
  46.  
  47.     Global Variables.
  48. _____________________________________________________________________*/
  49.  
  50. static ControlHandle    DriveH;        /* handle to drive push button */
  51. static ControlHandle    EjectH;        /* handle to eject push button */
  52. static Rect                *NameRect;    /* pointer to volume name rectangle */
  53. static Rect                AdjNameRect;    /* rectangle enclosing current vol name,
  54.                                                 adjusted for width of name */
  55. static Rect                *IconRect;    /* pointer to small vol icon rectangle */
  56. static Handle            FloppyH;        /*    handle to small floppy icon */
  57. static Handle            HardH;        /* handle to small hard drive icon */
  58. static Boolean            UnmountFlag;    /* true to unmount ejected volumes */
  59. static short            CurVol;        /* index of currently selected volume,
  60.                                                 or 0 if none */
  61. static short            ApplVol;        /* vol ref num of vol contng current appl */
  62. static short            SysVol;        /* vol ref num of system vol */
  63. static Boolean            HavePopUp;     /* true if system supports popup menus */
  64.  
  65. /*______________________________________________________________________
  66.  
  67.     NextVol - Advance to the Next Volume.
  68.     
  69.     Exit:        function result = error code.
  70. _____________________________________________________________________*/
  71.  
  72. static OSErr NextVol(void)
  73.  
  74. {
  75.     HParamBlockRec    pBlock;                /* vol info param block */
  76.     OSErr                rCode;                /* result code */
  77.     short                volInx;                /* volume index */
  78.     
  79.     pBlock.volumeParam.ioNamePtr = nil;
  80.     volInx = CurVol;
  81.     while (true) {
  82.         pBlock.volumeParam.ioVolIndex = ++volInx;
  83.         pBlock.volumeParam.ioVRefNum = 0;
  84.         if (rCode = PBHGetVInfo(&pBlock, false)) {
  85.             volInx = 0;
  86.         } else if (pBlock.volumeParam.ioVDrvInfo) {
  87.             CurVol = volInx;
  88.             return noErr;
  89.         }
  90.         if (volInx == CurVol) {
  91.             CurVol = 0;
  92.             return noErr;
  93.         }
  94.     }
  95. }
  96.  
  97. /*______________________________________________________________________
  98.  
  99.     HiliteDrive() - Hilite the Drive Button.
  100.     
  101.     The drive button is hilited iff there are at least two on-line
  102.     volumes.
  103. _____________________________________________________________________*/
  104.  
  105. static void HiliteDrive(void)
  106.  
  107. {
  108.     HParamBlockRec    pBlock;                /* vol info param block */
  109.     short                volInx;                /* vol index */
  110.     short                numOnLine;            /* number of online vols */
  111.     OSErr                rCode;                /* result code */
  112.     
  113.     pBlock.volumeParam.ioNamePtr = nil;
  114.     volInx = 0;
  115.     numOnLine = 0;
  116.     while (true) {
  117.         pBlock.volumeParam.ioVolIndex = ++volInx;
  118.         pBlock.volumeParam.ioVRefNum = 0;
  119.         if (rCode = PBHGetVInfo(&pBlock, false)) break;
  120.         if (pBlock.volumeParam.ioVDrvInfo) numOnLine++;
  121.         if (numOnLine > 1 ) {
  122.             HiliteControl(DriveH, 0);
  123.             return;
  124.         }
  125.     }
  126.     HiliteControl(DriveH, 255);
  127. }
  128.  
  129. /*______________________________________________________________________
  130.  
  131.     HiliteEject() - Hilite the eject Button.
  132.     
  133.     Exit:        function result = error code.
  134.     
  135.     The eject button is hilited iff the current volume is ejectable.
  136. _____________________________________________________________________*/
  137.  
  138. static OSErr HiliteEject(void)
  139.  
  140. {
  141.     short                vRefNum;                /* vol ref num of cur vol */
  142.     OSErr                rCode;                /* result code */
  143.     
  144.     /* If there is no current volume unhilite the eject button. */
  145.     
  146.     if (!CurVol) {
  147.         HiliteControl(EjectH, 255);
  148.         return noErr;
  149.     }
  150.     
  151.     /* Hilite the button iff the cur vol is ejectable. */
  152.     
  153.     if (rCode = vol_GetSel(&vRefNum)) return rCode;
  154.     HiliteControl(EjectH, utl_Ejectable(vRefNum) ? 0 : 255);
  155.     return noErr;
  156. }
  157.  
  158. /*______________________________________________________________________
  159.  
  160.     Inval - Invalidate the volume name and icon rectangles.
  161. _____________________________________________________________________*/
  162.  
  163. static void Inval(void)
  164.  
  165. {
  166.     Rect        boxRect;
  167.  
  168.     boxRect = *NameRect;
  169.     InsetRect(&boxRect, -2, -2);
  170.     InvalRect(&boxRect);
  171.     if (IconRect) InvalRect(IconRect);
  172. }
  173.  
  174. /*______________________________________________________________________
  175.  
  176.     vol_Init - Initialize.
  177.     
  178.     Entry:    driveH = handle to drive push button control.
  179.                 ejectH = handle to eject push button control.
  180.                 nameRect = pointer to volume name rectangle.
  181.                 iconRect = pointer to small volume icon rectangle, 
  182.                     or nil if none.
  183.                 floppyH = handle to small floppy icon, or nil if none.
  184.                 hardH = handle to small hard drive icon, or nil if none.
  185.                 applSel = true if the initial volume should be the volume
  186.                     containing the current application.  False if the initial
  187.                     volume should be some other volume (if there is one).
  188.                 unmmountFlag = true if ejected floppies should also be 
  189.                     unmounted.  The boot volume and the volume containing the 
  190.                     current application are never unmounted.
  191.                     
  192.     Exit:        function result = error code.
  193.                     
  194.     vol_Init must be called before calling any of the other routines
  195.     in the module.  It may be called more than once to reinitialize
  196.     the module.
  197.                     
  198.     vol_Init saves the parameters in private globals, selects an 
  199.     appropriate initial volume, and hilites the drive and eject buttons 
  200.     appropriately.
  201.     
  202.     Don't forget to do a SetPort to the window before calling this routine.
  203. _____________________________________________________________________*/
  204.  
  205. #pragma segment voli
  206.  
  207. OSErr vol_Init (ControlHandle driveH, ControlHandle ejectH, 
  208.     Rect *nameRect, Rect *icnRect, Handle floppyH, 
  209.     Handle hardH, Boolean applSel, Boolean unmountFlag)
  210.     
  211. {
  212.  
  213.     HParamBlockRec    pBlock;                /* Vol info param block */
  214.     short                applInx;                /* index of application volume */
  215.     OSErr                rCode;                /* result code */
  216.     
  217.     /* Save parameter values in private global variables. */
  218.     
  219.     DriveH = driveH;
  220.     EjectH = ejectH;
  221.     NameRect = nameRect;
  222.     IconRect = icnRect;
  223.     FloppyH = floppyH;
  224.     HardH = hardH;
  225.     UnmountFlag = unmountFlag;
  226.     
  227.     /* Get applInx = index of volume containing current application,
  228.         and ApplVol = vol ref num of applicaton volume. */
  229.     
  230.     pBlock.volumeParam.ioNamePtr = nil;
  231.     ApplVol = utl_GetApplVol();
  232.     applInx = 0;
  233.     do {
  234.         pBlock.volumeParam.ioVolIndex = ++applInx;
  235.         pBlock.volumeParam.ioVRefNum = 0;
  236.         rCode = PBHGetVInfo(&pBlock, false);
  237.     } while (!rCode && pBlock.volumeParam.ioVRefNum != ApplVol);
  238.     if (rCode) return rCode;
  239.     
  240.     /* Select initial volume.  */
  241.     
  242.     if (applSel) {
  243.         CurVol = applInx;
  244.     } else {
  245.         CurVol = 0;
  246.         do {
  247.             pBlock.volumeParam.ioVolIndex = ++CurVol;
  248.             pBlock.volumeParam.ioVRefNum = 0;
  249.             rCode = PBHGetVInfo(&pBlock, false);
  250.         } while (!rCode && (!pBlock.volumeParam.ioVDrvInfo || 
  251.             pBlock.volumeParam.ioVRefNum == ApplVol));
  252.         if (rCode) CurVol = applInx;
  253.     }
  254.     
  255.     /* Get SysVol = vol ref num of system volume. */
  256.     
  257.     SysVol = utl_GetSysVol();
  258.     
  259.     /* Find out whether the system supports popup menus. */
  260.     
  261.     HavePopUp = utl_SysHasPopUp();
  262.         
  263.     /* Hilite buttons and invalidate rectangles. */
  264.     
  265.     HiliteDrive();
  266.     if (rCode = HiliteEject()) return rCode;
  267.     Inval();
  268.     return noErr;
  269. }
  270.  
  271. #pragma segment vol
  272.  
  273. /*______________________________________________________________________
  274.  
  275.     vol_DoDrive - Process Drive Button Hit.
  276.                     
  277.     Exit:        function result = error code.
  278.     
  279.     This routine must be called whenever there's a hit in the Drive
  280.     button.  It advances to the next on-line volume, hilites the 
  281.     eject button appropriately, and invalidates the volume name and 
  282.     icon rectangles.
  283.     
  284.     To perfectly mimic the standard file package, you can also call this
  285.     routine whenever the tab key is pressed.
  286.     
  287.     Don't forget to do a SetPort to the window before calling this routine.
  288. _____________________________________________________________________*/
  289.  
  290. OSErr vol_DoDrive (void)
  291.  
  292. {
  293.     OSErr        rCode;            /* result code */
  294.  
  295.     if (rCode = NextVol()) return rCode;
  296.     if (rCode = HiliteEject()) return rCode;
  297.     Inval();
  298.     return noErr;
  299. }
  300.  
  301. /*______________________________________________________________________
  302.  
  303.     vol_DoPopUp - Present Volume Popup Menu.
  304.     
  305.     Entry:    where = location of mouse down, local coords.
  306.                 menuID = menu id to use for popup menu.
  307.                     
  308.     Exit:        function result = error code.
  309.     
  310.     This routine should be called whenever there's a mouse hit in the volume 
  311.     name rectangle.  It builds and presents a pop up menu listing all the 
  312.     mounted volumes.  The current volume is set to the volume selected from 
  313.     the menu by the user.
  314.     
  315.     The routine returns immediately if the mouse down event is not inside
  316.     the volume name rectangle.  It also returns immediately if the ROM or
  317.     system does not support popup menus.
  318.     
  319.     Don't forget to do a SetPort to the window before calling this routine.
  320. _____________________________________________________________________*/
  321.  
  322. OSErr vol_DoPopUp (Point where, short menuID)
  323.  
  324. {
  325.     MenuHandle        theMenu;                /* handle to popup menu */
  326.     long                theItem;                /* 16/menu number, 16/item number */
  327.     short                volInx;                /* index in volume list */
  328.     HParamBlockRec    pBlock;                /* vol info param block */
  329.     Str255            volName;                /* vol name */
  330.     OSErr                rCode;                /* result code */
  331.     Point                whereMenu;            /* loc of popup menu, global coords */
  332.     short                item;                    /* menu item number */
  333.     short                checkedItem;        /* menu item number of checked item */
  334.     unsigned char    *p;                    /* pointer into vol name string */
  335.     Rect                invertRect;            /* rectangle to be inverted */
  336.     Rect                popTestRect;        /* rectangle to hit test */
  337.     
  338.     /* Return if pop up menus are not available on this sytem. */
  339.     
  340.     if (!HavePopUp) return noErr;
  341.     
  342.     /* Return if mousedown not in volume name rectangle. */
  343.     
  344.     popTestRect = *NameRect;
  345.     popTestRect.right = AdjNameRect.right - 1;
  346.     if (!PtInRect(where, &popTestRect)) return noErr;
  347.     
  348.     /* Return if there is no current volume. */
  349.     
  350.     if (!CurVol) return noErr;
  351.     
  352.     /* Create the menu. */
  353.     
  354.     theMenu = NewMenu(menuID, "\p");
  355.     
  356.     /* Fill the menu with the names of all currently mounted volumes.  Put
  357.         a check mark next to the currently selected volume. */
  358.     
  359.     volInx = item = 0;
  360.     pBlock.volumeParam.ioNamePtr = volName;
  361.     while (true) {
  362.         pBlock.volumeParam.ioVolIndex = ++volInx;
  363.         pBlock.volumeParam.ioVRefNum = 0;
  364.         rCode = PBHGetVInfo(&pBlock, false);
  365.         if (rCode) break;
  366.         if (pBlock.volumeParam.ioVDrvInfo) {
  367.             AppendMenu(theMenu, "\p ");
  368.             if (*(volName+1) == '-') {
  369.                 /* vol name starts with '-': prepend a blank to the beginning
  370.                     of the name to avoid having the menu manager display it as
  371.                     a separator line. */
  372.                 for (p = volName + *volName; p > volName; p--) *(p+1) = *p;
  373.                 *(volName+1) = ' ';
  374.                 (*volName)++;
  375.             }
  376.             SetItem(theMenu, ++item, volName);
  377.             if (volInx == CurVol) 
  378.                 CheckItem(theMenu, checkedItem = item, true);
  379.         }
  380.     }
  381.         
  382.     /* Insert menu into menu bar. */
  383.     
  384.     InsertMenu(theMenu, -1);
  385.     
  386.     /* Pop it up.  Extract the item number selected.  Make the selected item
  387.         the current volume. */
  388.     
  389.     SetPt(&whereMenu, NameRect->left, NameRect->top);
  390.     LocalToGlobal(&whereMenu);
  391.     if (IconRect) {
  392.         invertRect = *IconRect;
  393.         invertRect.left--;
  394.         invertRect.right = NameRect->left;
  395.         InvertRect(&invertRect);
  396.     }
  397.     theItem = PopUpMenuSelect(theMenu, whereMenu.v, whereMenu.h, 
  398.         checkedItem);
  399.     if (IconRect) InvertRect(&invertRect);
  400.     if ((theItem >> 16) & 0xffff) {
  401.         item = theItem & 0xffff;
  402.         volInx = 0;
  403.         pBlock.volumeParam.ioNamePtr = nil;
  404.         while (true) {
  405.             pBlock.volumeParam.ioVolIndex = ++volInx;
  406.             pBlock.volumeParam.ioVRefNum = 0;
  407.             rCode = PBHGetVInfo(&pBlock, false);
  408.             if (rCode) break;
  409.             if (pBlock.volumeParam.ioVDrvInfo) {
  410.                 if (!(--item)) {
  411.                     CurVol = volInx;
  412.                     break;
  413.                 }
  414.             }
  415.         }
  416.         if (rCode = HiliteEject()) return rCode;
  417.         Inval();
  418.     }
  419.     
  420.     /* Delete and dispose of the menu and return. */
  421.     
  422.     DeleteMenu(menuID);
  423.     DisposeMenu(theMenu);
  424.     return noErr;
  425. }
  426.  
  427. /*______________________________________________________________________
  428.  
  429.     vol_DoEject - Process eject Button Hit.
  430.                     
  431.     Exit:        function result = error code.
  432.     
  433.     This routine must be called whenever there's a hit in the eject
  434.     button.  It ejects the currently selected volume, and unmounts it
  435.     if the unmount option was selected and the volume is not the
  436.     startup volume or the one containing the current application.  It 
  437.     then advances to the next on-line volume, hilites the Drive and 
  438.     eject buttons appropriately, and invalidates the volume name and 
  439.     icon rectangles.
  440.     
  441.     Don't forget to do a SetPort to the window before calling this routine.
  442. _____________________________________________________________________*/
  443.  
  444. OSErr vol_DoEject (void)
  445.  
  446. {
  447.     HParamBlockRec    pBlock;                /* vol info param block */
  448.     OSErr                rCode;                /* result code */
  449.     short                volRefNum;            /* vol ref num of current vol */
  450.     
  451.     /* eject the current volume. */
  452.     
  453.     pBlock.volumeParam.ioNamePtr = nil;
  454.     pBlock.volumeParam.ioVolIndex = CurVol;
  455.     pBlock.volumeParam.ioVRefNum = 0;
  456.     if (rCode = PBHGetVInfo(&pBlock, false)) return rCode;
  457.     volRefNum = pBlock.volumeParam.ioVRefNum;
  458.     if (rCode = Eject(nil, volRefNum)) return rCode;
  459.     
  460.     /* If UnmountFlag is true, and the volume is not the system or
  461.         application volume, then unmount it. */
  462.         
  463.     if (UnmountFlag && volRefNum != SysVol && volRefNum != ApplVol) {
  464.         if (rCode = UnmountVol(nil, volRefNum)) return rCode;
  465.         CurVol = 0;
  466.     }
  467.     
  468.     /* Advance to next volume, hilite the buttons, and invalidate the 
  469.     rectangles. */
  470.         
  471.     if(rCode = NextVol()) return rCode;
  472.     HiliteDrive();
  473.     if (rCode = HiliteEject()) return rCode;
  474.     Inval();
  475.     return noErr;
  476. }
  477.  
  478. /*______________________________________________________________________
  479.  
  480.     vol_DoInsert - Process Disk Insertion Evect.
  481.     
  482.     Entry:    message = message field from event record.
  483.                     
  484.     Exit:        function result = error code.
  485.     
  486.     This routine must be called whenever there's a disk insertion event.
  487.     It makes the inserted volume the current volume, hilites the
  488.     Drive and eject buttons appropriately, and invalidates the volume
  489.     name and icon rectangles.
  490.     
  491.     Don't forget to do a SetPort to the window before calling this routine.
  492. _____________________________________________________________________*/
  493.  
  494. OSErr vol_DoInsert (long message)
  495.  
  496. {
  497.     OSErr                rCode;                /* result code */
  498.     short                vRefNum;                /* vol ref num of inserted disk */
  499.  
  500.     /* Process the disk insertion event, and get the vol ref num */
  501.     
  502.     if (rCode = utl_DoDiskInsert(message, &vRefNum)) return rCode;
  503.     
  504.     /* Make the new disk the current volume. */
  505.     
  506.     if (rCode = vol_SetSel(vRefNum, true)) return rCode;
  507. }
  508.  
  509. /*______________________________________________________________________
  510.  
  511.     vol_DoUpdate - Process Update Event.
  512.                     
  513.     Exit:        function result = error code.
  514.     
  515.     This routine must be called whenever an update event occurs.  It
  516.     draws the volume name using the font attributes.  It also draws 
  517.     the proper small icon.
  518.     
  519.     If the current system supports popup menus, the volume name is also 
  520.     framed, with a drop shadow.
  521.     
  522.     Don't forget to do a SetPort to the window, call BeginUpdate, and
  523.     set your desired font and size before calling this routine.
  524. _____________________________________________________________________*/
  525.  
  526. OSErr vol_DoUpdate (void)
  527.  
  528. {
  529.     HParamBlockRec    pBlock;                /* vol info param block */
  530.     Str255            volName;                /* vol name */
  531.     OSErr                rCode;                /* result code */
  532.     Rect                textRect;            /* rectangle for TextBox */
  533.     short                nameWidth;            /* width of vol name */
  534.     short                vRefNum;                /* vol ref num of cur vol */
  535.     short                slop;                    /* extra pixels needed in name width */
  536.     PolyHandle        triangle;            /* handle to triangle polygon */
  537.     
  538.     /* Return if there is no current volume. */
  539.     
  540.     if (!CurVol) return noErr;
  541.     
  542.     /* Get the volume name. */
  543.     
  544.     pBlock.volumeParam.ioNamePtr = volName;
  545.     pBlock.volumeParam.ioVolIndex = CurVol;
  546.     pBlock.volumeParam.ioVRefNum = 0;
  547.     if (rCode = PBHGetVInfo(&pBlock, false)) return rCode;
  548.     
  549.     /* If the name is too long truncate it and append the ellipsis char "…" */
  550.     
  551.     slop = HavePopUp ? 20 : 9;
  552.     while (true) {
  553.         nameWidth = StringWidth(volName);
  554.         if (NameRect->left + nameWidth + slop <= NameRect->right) break;
  555.         (*volName)--;
  556.         *(volName + *volName) = '…';
  557.     }
  558.  
  559.     /* Draw the volume name and icon. */
  560.     
  561.     textRect = *NameRect;
  562.     textRect.left += 4;
  563.     TextBox(volName+1, *volName, &textRect, teJustLeft);
  564.     if (IconRect) {
  565.         if (rCode = vol_GetSel(&vRefNum)) return rCode;
  566.         utl_PlotSmallIcon (IconRect, utl_Ejectable(vRefNum) ? FloppyH : HardH);
  567.     }
  568.         
  569.     /* Frame the volume name, with a drop shadow, and draw the triangle. */
  570.         
  571.     if (HavePopUp) {
  572.         AdjNameRect = *NameRect;
  573.         AdjNameRect.right = AdjNameRect.left + nameWidth + slop;
  574.         InsetRect(&AdjNameRect, -1, -1);
  575.         FrameRect(&AdjNameRect);
  576.         MoveTo(AdjNameRect.right, AdjNameRect.top+2);
  577.         LineTo(AdjNameRect.right, AdjNameRect.bottom);
  578.         LineTo(AdjNameRect.left+2, AdjNameRect.bottom);
  579.         triangle = OpenPoly();
  580.         MoveTo(AdjNameRect.right - 14, 
  581.             (AdjNameRect.top + AdjNameRect.bottom - 5)>>1);
  582.         Line(10, 0);
  583.         Line(-5, 5);
  584.         Line(-5, -5);
  585.         ClosePoly();
  586.         PaintPoly(triangle);
  587.         KillPoly(triangle);
  588.     }
  589.     return noErr;
  590. }
  591.  
  592. /*______________________________________________________________________
  593.  
  594.     vol_Verify - Verify and Adjust Selected Volume.
  595.     
  596.     Exit:        function result = error code.
  597.     
  598.     This routine should be called after any call to the standard file
  599.     package or any other activity which might have caused the volume
  600.     list to change state. 
  601.     
  602.     vol_Verify checks to make sure that the current volume still exists and 
  603.     is online.  If it isn't, it finds some other volume that is and makes it 
  604.     the current one.  
  605.  
  606.     The volume name and icon rectangles are invalidated, and the Drive and 
  607.     Eject buttons are rehilited appropriately.
  608.     _____________________________________________________________________*/
  609.  
  610. OSErr vol_Verify (void)
  611.  
  612. {
  613.     HParamBlockRec    pBlock;            /* vol info param block */
  614.     OSErr                rCode;            /* reslut code */
  615.     
  616.     if (!CurVol) {
  617.         rCode = NextVol();
  618.     } else {
  619.         pBlock.volumeParam.ioNamePtr = nil;
  620.         pBlock.volumeParam.ioVolIndex = CurVol;
  621.         pBlock.volumeParam.ioVRefNum = 0;
  622.         rCode = PBHGetVInfo(&pBlock, false);
  623.         if ((rCode == nsvErr) || !pBlock.volumeParam.ioVDrvInfo) {
  624.             CurVol = 0;
  625.             rCode = NextVol();
  626.         }
  627.     }
  628.     if (rCode) return rCode;
  629.     HiliteDrive();
  630.     if (rCode = HiliteEject()) return rCode;
  631.     Inval();
  632. }
  633.  
  634. /*______________________________________________________________________
  635.  
  636.     vol_GetSel - Get Volume Reference Number of Selected Volume.
  637.     
  638.     Exit:        *vRefNum = volume reference number.
  639.                 function result = error code (= nsvErr if no current vol).
  640. _____________________________________________________________________*/
  641.  
  642. OSErr vol_GetSel (short *vRefNum)
  643.  
  644. {
  645.     HParamBlockRec    pBlock;                /* vol info param block */
  646.     OSErr                rCode;                /* result code */
  647.     
  648.     if (!CurVol) return nsvErr;
  649.     pBlock.volumeParam.ioNamePtr = nil;
  650.     pBlock.volumeParam.ioVolIndex = CurVol;
  651.     pBlock.volumeParam.ioVRefNum = 0;
  652.     if (rCode = PBHGetVInfo(&pBlock, false)) return rCode;
  653.     *vRefNum = pBlock.volumeParam.ioVRefNum;
  654.     return noErr;
  655. }
  656.  
  657. /*______________________________________________________________________
  658.  
  659.     vol_SetSel - Set Volume Reference Number of Selected Volume.
  660.     
  661.     Entry:    vRefNum = volume reference number.
  662.                 doButtons = true to hilite Drive and Eject buttons.
  663.     
  664.     Exit:        function result = error code.
  665. _____________________________________________________________________*/
  666.  
  667. OSErr vol_SetSel (short vRefNum, Boolean doButtons)
  668.  
  669. {
  670.     HParamBlockRec    pBlock;                /* vol info param block */
  671.     OSErr                rCode;                /* result code */
  672.     
  673.     CurVol = 0;
  674.     pBlock.volumeParam.ioNamePtr = nil;
  675.     do {
  676.         pBlock.volumeParam.ioVolIndex = ++CurVol;
  677.         pBlock.volumeParam.ioVRefNum = 0;
  678.         rCode = PBHGetVInfo(&pBlock, false);
  679.     } while (!rCode && pBlock.volumeParam.ioVRefNum != vRefNum);
  680.     if (rCode) return rCode;
  681.     if (doButtons) {
  682.         HiliteDrive();
  683.         if (rCode = HiliteEject()) return rCode;
  684.     }
  685.     Inval();
  686.     return noErr;
  687. }
  688.  
  689. /*______________________________________________________________________
  690.  
  691.     vol_GetName - Get Name of Selected Volume.
  692.     
  693.     Exit:        vName = volume name.
  694.                 function result = error code (= nsvErr if no current vol).
  695. _____________________________________________________________________*/
  696.  
  697. OSErr vol_GetName (Str255 vName)
  698.  
  699. {
  700.     HParamBlockRec    pBlock;                /* vol info param block */
  701.     OSErr                rCode;                /* result code */
  702.     
  703.     if (!CurVol) return nsvErr;
  704.     
  705.     /* Get the volume name. */
  706.     
  707.     pBlock.volumeParam.ioNamePtr = vName;
  708.     pBlock.volumeParam.ioVolIndex = CurVol;
  709.     pBlock.volumeParam.ioVRefNum = 0;
  710.     if (rCode = PBHGetVInfo(&pBlock, false)) return rCode;
  711.     return noErr;
  712. }