[comp.os.msdos.programmer] Windows & PC-NFS: Solution

TOMIII@MTUS5.BITNET (Thomas Dwyer III) (09/21/90)

Well, I think I finally found a way to run Windows and PC-NFS together
without having the window manager choke and die on all the drive letters
that do not have disks mounted on them.  You don't need the undocumented
"/d" option in the config sys either (which nukes the ability to see spool
files on the T: U: and V: drives).  Clearing the upper 2 bits of offset 0x43
in the current directury structure for a given drive makes the drive
"invalid" as far as DOS is concerned.  All one needs to do is scan through
all the drives through LASTDRIVE and "nuke" any drive letter that has no
disk mounted to it.  I use IOCTL (int 0x21, function 0x44, subfunction 9)
to determine if the drive is "remote" (a drive IS mounted) or "local" (a
drive IS NOT mounted) to determine this.  Once all the unused drive letters
are gone, fire up Windows and poof - no more errors accessing phantom disks.

Now there is one small disadvantage in doing this.  If, after you've nuked
all your excess drive letters, you mount or unmount a drive (yes, NET USE
still works) the new drive will still be invalid, and the dropped drive
will still exist (as far as DOS is concerned).  My solution is to first
mark every drive letter as valid, then check each drive and mark the
invalid ones.  After any NET USE command, simply repeat this process to
reflect the change.

Here is my code.  Please feel free to make suggestions, comments, etc.

----- Cut Here -----

/***********************************************************************\
*                                                                       *
*       REFRESH                                                         *
*                                                                       *
*       This program scans the array of current directory structures    *
*       looking for PC-NFS drives.  If it finds a device letter that    *
*       is reserved by PCNFS.SYS it checks to see if an NFS drive is    *
*       actually mounted on that letter.  If not, the device letter     *
*       is marked as "invalid".                                         *
*                                                                       *
*       Compiled with Turbo C version 1.5                               *
*                                                                       *
*       Written by Thomas Dwyer III                     09/19/90        *
*       Copyright Michigan Technological University     09/19/90        *
*                                                                       *
\***********************************************************************/

#include        <dos.h>

#define         DOS3_OFFSET             0x12
#define         DOS4_OFFSET             0x13
#define         DOS4_CDS_ARRAY_SIZE     0x58
#define         DOS3_CDS_ARRAY_SIZE     0x51
#define         STATUS_BYTE_OFFSET      0x44
#define         PCNFS_SIGNATURE_OFFSET  0x2B


/***********************************************************************\
*                                                                       *
*       GET_DOS_VERSION - returns the major DOS version number          *
*                                                                       *
\***********************************************************************/
int get_dos_version()
{
        union REGS regs;

        regs.h.ah = 0x30;
        intdos(&regs, &regs);
        return(regs.h.al);
}


/***********************************************************************\
*                                                                       *
*       IS_PCNFS -      returns TRUE if "ptr" points to the PCNFS.SYS   *
*                       device driver header, FALSE if not.             *
*                                                                       *
\***********************************************************************/
int is_pcnfs(ptr)
unsigned char far *ptr;
{
        static char array[] = "PC-NFS";
        char *pcnfs_ptr = array;

        ptr += PCNFS_SIGNATURE_OFFSET;
        while (*pcnfs_ptr)
                if (*ptr++ != *pcnfs_ptr++)
                        return(0);
        return(1);
}


/***********************************************************************\
*                                                                       *
*       RESTORE DRIVE - sets the "physical drive" bit in the CDS        *
*                       pointed to by "ptr".                            *
*                                                                       *
\***********************************************************************/
void restore_drive(ptr)
unsigned char far *ptr;
{
        *(ptr+STATUS_BYTE_OFFSET) |= 0x40;
        return;
}


/***********************************************************************\
*                                                                       *
*       CHECK_DRIVE -   tests for a mounted drive, and clears both      *
*                       the "physical drive" and the "network drive"    *
*                       bits in the CDS.                                *
*                                                                       *
\***********************************************************************/
void check_drive(ptr, drive)
unsigned char far *ptr;
int drive;
{
        union REGS regs;
        struct SREGS sregs;
        unsigned long far *device_header;

        if (drive > 2) {        /* A=0, B=1, etc.  We want to start at D: */
                regs.h.ah = 0x32;
                regs.h.dl = drive+1;
                intdosx(&regs, &regs, &sregs);
                if (get_dos_version() == 4)
                        device_header = MK_FP(sregs.ds, regs.x.bx+DOS4_OFFSET);
                else
                        device_header = MK_FP(sregs.ds, regs.x.bx+DOS3_OFFSET);

                if (is_pcnfs(*device_header)) {
                        regs.x.ax = 0x4409;
                        regs.h.bl = drive+1;
                        intdos(&regs, &regs);
                        if (regs.x.dx & 0x1000)
                                printf("\t%c:\n", drive+'A');
                        else
                                *(ptr+STATUS_BYTE_OFFSET) &= !0xC0;
                }
        }
        return;
}


main()
{
        union REGS regs;
        struct SREGS sregs;
        int i, num_drives;
        unsigned char far *ptr;
        unsigned long far *addr_ptr;

        regs.h.ah = 0x52;
        intdosx(&regs, &regs, &sregs);
        ptr = MK_FP(sregs.es, regs.x.bx);
        addr_ptr = MK_FP(sregs.es, regs.x.bx+0x16);
        num_drives = *(ptr+0x20);

        ptr = (unsigned char far *) *addr_ptr;

        printf("%d drives reserved starting at %Fp\n", num_drives, ptr);
        printf("The following are valid PC-NFS drives:\n", num_drives);

        for (i=0; i<num_drives; i++) {
                restore_drive(ptr);
                check_drive(ptr, i);
                if (get_dos_version() == 4)
                        ptr += DOS4_CDS_ARRAY_SIZE;
                else
                        ptr += DOS3_CDS_ARRAY_SIZE;
        }
}