BUG: GetVolumeInformation Doesn't Return Volume Serial Number of Remote Drives on Windows 95/98

ID: Q234741


The information in this article applies to:


SYMPTOMS

Win32 programs use GetVolumeInformation() to retrieve information about local and remote volumes. On Windows 95 and Windows 98, GetVolumeInformation() does not retrieve the actual serial number of remote volumes, but always returns zero for the volume serial number.


RESOLUTION

To obtain the volume serial number of a remote volume, open a file on the remote volume and use GetFileInformationByHandle(). Part of the returned information is the serial number of the volume on which the file is located. This strategy works as long as there is a file on the remote volume that can be opened. The following sample code demonstrates how to do this:


#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <stdio.h>

BOOL GetVolumeSerialNumber (LPCSTR pszRootPathName, DWORD *pdwSerialNum);

void main (int argc, char **argv)
{
   BOOL fResult;
   char *pszDriveName;

   // volume information we want to collect
   char  szVolName[MAX_PATH];
   char  szFileSysName[80];
   DWORD dwSerialNumber;
   DWORD dwMaxComponentLen;
   DWORD dwFileSysFlags;


   // Validate command-line arguments.
   if (argc != 2)
   {
      printf("usage: %s drive\n\tdrive = C:\\, \\\\svr\\share\\\n",
             argv[0]);
      printf("\tnote:  the trailing backslash is needed\n");
      return;
   }

   pszDriveName = argv[1];

   fResult = GetVolumeInformation(pszDriveName, szVolName, MAX_PATH,
                                  &dwSerialNumber, &dwMaxComponentLen,
                                  &dwFileSysFlags, szFileSysName, 80);
   if (fResult)
   {
      // If the serial number wasn't returned, try to get it a
      // different way.
      if (dwSerialNumber == 0)
         GetVolumeSerialNumber (pszDriveName, &dwSerialNumber);

      printf("volume name   = %s\n",   szVolName);
      printf("serial number = %#lx\n", dwSerialNumber);
   }
   else
      printf("could not get info for %s, error = %lu\n",
             pszDriveName, GetLastError());
}


/*
GetVolumeSerialNumber( pszRootPathName, pdwSerialNum )

Retrieves the serial number of a local or remote volume.

Parameters
   pszRootPathName
      The volume to get the serial number of.  Must be specified as
      one of:
         A drive letter, colon and trailing backslash.  C:\ 
         A UNC name with trailing backslash.            \\svr\share\ 

   pdwSerialNum
      A pointer to a DWORD that will contain the serial number when
      the function returns. Note: the caller must allocate the memory
      for this parameter.

Return value
   Returns TRUE if it successfully retrieves a volume serial number, or
   FALSE if it can't.
*/ 
BOOL GetVolumeSerialNumber (LPCSTR pszRootPathName, DWORD *pdwSerialNum)
{
   BOOL bReturn = FALSE;  // Assume that we haven't get the serial number,
                          // then set it to true if we do get it.

   HANDLE                     hFile;
   BY_HANDLE_FILE_INFORMATION bhFileInfo;

   HANDLE          hFileFind;
   WIN32_FIND_DATA wfdFileData;
   char            szFindFileName[MAX_PATH];


   /*
      Search for any file that we can open and retrieve information about.
      That information will include the serial number of the volume on
      which the file resides.
   */ 
   lstrcpy (szFindFileName, pszRootPathName);
   lstrcat (szFindFileName, "*");

   hFileFind = FindFirstFile (szFindFileName, &wfdFileData);
   if (INVALID_HANDLE_VALUE == hFileFind)
      goto EXIT_DONE;

   do
   {
      /* Make sure that we've found a file and not a directory */ 
      if (!(wfdFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
      {
         /*
            Found a file.  Now, use the full path to open the file and get
            information about it. This information includes the serial
            number of the volume on which the file resides.  If we do get
            the info, we can bail out because we're done.

            If we can't open this file, look for another one we can open.
         */ 
         lstrcpy (szFindFileName+lstrlen(pszRootPathName),
                  wfdFileData.cFileName);

         hFile = CreateFile (szFindFileName,
                             0,    // don't need to open for read or write
                             FILE_SHARE_READ|FILE_SHARE_WRITE,
                             NULL, OPEN_EXISTING, 0, NULL);
         if (INVALID_HANDLE_VALUE != hFile)
         {
            bReturn = GetFileInformationByHandle(hFile, &bhFileInfo);
            CloseHandle(hFile);

            if (bReturn)
               break;
         }
      }
   }
   while (FindNextFile(hFileFind, &wfdFileData));
   CloseHandle (hFileFind);  /* don't need the find handle anymore */ 

   /* If we have the serial number, return it to the caller */ 
   if (bReturn )
   {
      __try
      {
         *pdwSerialNum = bhFileInfo.dwVolumeSerialNumber;
      }
      __except (EXCEPTION_EXECUTE_HANDLER)
      {
         SetLastError (ERROR_INVALID_PARAMETER);
         bReturn = FALSE;
      }
   }

EXIT_DONE:
   return (bReturn);
} 


STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article.

Additional query words: remote network drive serial number obtain


Keywords          : kbAPI kbFileIO kbKernBase 
Version           : winnt:
Platform          : winnt 
Issue type        : kbbug 

Last Reviewed: June 16, 1999