Microsoft KB Archive/201685

{|
 * width="100%"|

HOWTO: Programmatically Retrieve a VxD's Version Information

 * }

Q201685

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), included with:
 * Microsoft Windows NT Server version 4.0
 * Microsoft Windows NT Workstation version 4.0

-

SUMMARY
On Windows 95/98, the GetFileVersionInfo and GetFileVersionInfoSize APIs can be used to retrieve 32-bit version information from a virtual device driver (VxD). However, on Windows NT these functions fail when called for a VxD. GetLastError returns zero. This behavior is by design, because VxDs are specific to the Windows 95/98 operating systems.

It is sometimes necessary for a replication server running on Windows NT to update files on Windows 95/98. When doing so, it may need to retrieve the current version of a VxD to ensure that it doesn't overwrite a newer file with an older one. The sample code in this article contains the necessary functions to retrieve the version information from a VxD. These new functions can be used on both Windows NT and Windows 95/98.

MORE INFORMATION
A virtual device driver (VxD) is a 32-bit, protected-mode driver that manages a system resource so that more than one application can use the resource at the same time. VxDs are specific to the Windows 95/98 operating systems.

"VxD" refers to a general virtual device driver. The x may sometimes represent the type of device. For example, a virtual device driver for a display device may be called a VDD, a virtual device driver for a timer device may be called a VTD, a virtual device driver for a printer device may be called a VPD, and so on.

The sample code below demonstrates how to retrieve the version information from a VxD. The code implements two useful functions called GetVxdVersionInfo and GetVxdVersionInfoSize. These functions are analogous to the GetFileVersionInfo and GetFileVersionInfoSize APIs. These VxD functions work successfully on both Windows NT and Windows 95/98.

VxD images are stored in the Windows Linear Executable (LE) file format, which is a derivative of the OS/2 LE format. The LE format is outdated and undocumented for the most part. The LE header structure, IMAGE_VXD_HEADER, is defined in Winnt.h. Using this definition, it is possible to locate the version resource within a VxD.

The version resource itself is a 32-bit Windows Version Resource as compiled by the Microsoft 32-bit Resource Compiler (RC.exe). Because the raw version data within the executable is in the VS_VERSION_INFO format, the retrieved data can be passed to the VerQueryValue API to extract meaningful version information.

The following steps outline how the version information is retrieved from a VxD:


 * 1) The file image is mapped into memory.
 * 2) A pointer to the DOS executable header is retrieved.
 * 3) A pointer to the LE header is retrieved from the DOS header.
 * 4) A pointer to the version resource is retrieved from the LE header.
 * 5) A pointer to the raw version data is retrieved from the version resource.
 * 6) The raw version data is copied into a supplied buffer.

For a more precise explanation of how the version information is retrieved, refer to the code itself.

NOTE: Only ANSI versions of these functions are provided in this sample. The textual resource information in VxDs is stored as ANSI characters because Windows 95/98 is an ANSI operating system. It is probably best to work with these resources as ANSI, rather than UNICODE, even on Windows NT.

SAMPLE CODE
  //********************************************************************** //   //  This program retrieves the version resource from a VxD. //   //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF   //  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A   //  PARTICULAR PURPOSE. //   //  Copyright (C) 1998 Microsoft Corporation. All rights reserved. // Author: Jonathan Russ (jruss) //   //**********************************************************************

#include   #include 

#define SWAPWORDS(X) ( (X<<16) | (X>>16) )

// the following structure must be byte-aligned. #pragma pack( push, pre_vxd_ver, 1 ) typedef struct _VXD_VERSION_RESOURCE { char cType; WORD wID; char cName; WORD wOrdinal; WORD wFlags; DWORD dwResSize; BYTE bVerData; } VXD_VERSION_RESOURCE, *PVXD_VERSION_RESOURCE; #pragma pack( pop, pre_vxd_ver )

//**********************************************************************  //    //  FUNCTION:     GetVxdVersion - This function retrieves the version //               information from a VxD. It is analagous to the //               GetFileVersionInfo API. //   //  PARAMETERS:   szFile  - null-terminated string indicating the VxD //                         file name. //   //                lpdwLen - pointer to DWORD containing the size of the //                         buffer. //   //                lpData  - pointer to buffer to receive the version //                         resource //   //  RETURN VALUE: TRUE if successful. Otherwise, FALSE and //               GetLastError will return one of the following values //               indicating why the function failed: //   //                ERROR_BAD_FORMAT - the file is not a valid VxD. //   //                ERROR_RESOURCE_DATA_NOT_FOUND - the VxD does not //               contain a version resource. //   //                ERROR_INSUFFICIENT_BUFFER - the specified buffer size //               was too small. After the function fails with this //               error code, the value pointed to by lpdwSize will be   //                the required buffer size. //   //**********************************************************************

BOOL GetVxdVersion( LPSTR szFile, LPDWORD lpdwLen, LPVOID lpData ) {

HANDLE hFile       = NULL; HANDLE hFileMapping = NULL; void * pView       = NULL; DWORD dwSize       = 0; BOOL  bResult      = FALSE; DWORD dwError      = 0;

PIMAGE_DOS_HEADER      pDosExeHdr = NULL; PIMAGE_NT_HEADERS      pNtExeHdr  = NULL; PIMAGE_VXD_HEADER      pLEHdr     = NULL; PVXD_VERSION_RESOURCE  pVerRes    = NULL; LPVOID                 pRawRes    = NULL;

// Wrap in a try..finally block to ensure resources are freed. __try {

// Open the file for shared read access. hFile = CreateFile( szFile, GENERIC_READ, FILE_SHARE_READ,              NULL, OPEN_EXISTING, 0, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) __leave;

// Create a read-only file mapping object for the file. hFileMapping = CreateFileMapping( hFile, NULL,              PAGE_READONLY, 0, 0, NULL); if ( !hFileMapping ) __leave;

// Map a view of the the file. pView = MapViewOfFile( hFileMapping, FILE_MAP_READ, 0, 0, 0 ); if ( !pView ) __leave;

// The DOS header begins at byte 0. pDosExeHdr = (PIMAGE_DOS_HEADER) pView;

// Check to make sure the file has a DOS EXE header. if ( pDosExeHdr->e_magic != IMAGE_DOS_SIGNATURE ) { SetLastError( ERROR_BAD_FORMAT ); __leave; }

// Find the beginning of the NT header at offset e_lfanew. pNtExeHdr = (PIMAGE_NT_HEADERS) ( (DWORD) pView              + (DWORD) pDosExeHdr->e_lfanew );

// Check to make sure the file is a VxD. if ( (DWORD) pNtExeHdr->Signature != IMAGE_VXD_SIGNATURE ) { SetLastError( ERROR_BAD_FORMAT ); __leave; }

// The LE header begins at the same place as the NT header. pLEHdr = (PIMAGE_VXD_HEADER) pNtExeHdr;

// e32_winreslen contains the size of the VxD's version resource. if ( pLEHdr->e32_winreslen == 0 ) { *lpdwLen = 0; SetLastError( ERROR_RESOURCE_DATA_NOT_FOUND ); __leave; }

// e32_winresoff contains the offset of the resource in the VxD. pVerRes = (VXD_VERSION_RESOURCE *) ( (DWORD) pView              + (DWORD) pLEHdr->e32_winresoff ); dwSize = pVerRes->dwResSize; pRawRes = &(pVerRes->bVerData);

// Make sure the supplied buffer is large enough for the resource. if ( ( lpData == NULL ) || ( *lpdwLen < dwSize ) ) { *lpdwLen = dwSize; SetLastError( ERROR_INSUFFICIENT_BUFFER ); __leave; }

// Zero the passed buffer and copy the resource into it. ZeroMemory( lpData, *lpdwLen ); CopyMemory( lpData, pRawRes, dwSize ); *lpdwLen = dwSize; SetLastError(0); bResult = TRUE;

} __finally {

// Save the last error, in case the clean up code modifies it. dwError = GetLastError;

// Clean up resources. if ( pView ) UnmapViewOfFile( pView );

if ( hFileMapping ) CloseHandle( hFileMapping );

if ( hFile != INVALID_HANDLE_VALUE ) CloseHandle( hFile );

// Reset the last error to the saved value. SetLastError( dwError ); }

return bResult; }

//**********************************************************************  //    //  FUNCTION:     GetVxdVersionInfoSize - This function is analagous to   //                the GetFileVersionInfoSize API. //   //  PARAMETERS:   szFile  - null-terminated string indicating the VxD //                         file name. //   //  RETURN VALUE: If successful, this function returns the size in bytes //               of the resource information for the VxD. Otherwise, //               the function returns zero and GetLastError will //               indicate why the function failed. If the function //               fails with ERROR_BAD_FORMAT, then the file was not a   //                valid VxD. //   //**********************************************************************

DWORD GetVxdVersionInfoSize( LPSTR szFile ) {

DWORD dwResult = 0;

// Call GetVxdVersion with NULL for the pointer to the buffer. if ( !GetVxdVersion( szFile, &dwResult, NULL ) ) {

DWORD dwError = GetLastError;

// GetVxdVersion will fail with ERROR_INSUFFICIENT_BUFFER and // the required buffer size will be returned in dwResult. if ( GetLastError == ERROR_INSUFFICIENT_BUFFER ) { SetLastError( 0 ); return dwResult; }     }

// The following line is never executed. return 0; }

//**********************************************************************  //    //  FUNCTION:     GetVxdVersionInfo - This function is analagous to the //               GetFileVersionInfo API. It is basically a  //                pass-through to GetVxDVersion, except that the dwLen //               parameter is passed by reference. //   //  PARAMETERS:   szFile  - null-terminated string indicating the VxD //                         file name. //   //                dwLen   - DWORD containing the size of the buffer. //   //                lpData  - pointer to buffer to receive the version //                         resource. //   //  RETURN VALUE: TRUE if successful. Otherwise, FALSE and //               GetLastError will indicate why the function failed. //   //**********************************************************************

BOOL GetVxdVersionInfo( LPSTR szFile, DWORD dwLen, LPVOID lpData ) {

return GetVxdVersion( szFile, &dwLen, lpData ); }

//**********************************************************************  //    //  FUNCTION:     main - This is the entry point for the program. This //               function contains some sample code demonstrating how //               to use the VxD version functions above. //   //  PARAMETERS:   argc - the number of command-line arguments. //   //                argv - an array of null-terminated strings containing //                      the command-line arguments. //   //  RETURN VALUE: none //   //**********************************************************************

void main( int argc, char *argv[] ) {

void *  lpData; DWORD   dwResSize; BOOL    bSuccess; UINT    uFfiLen; char    szLangCp[9]; LPDWORD lpdwLangCp; UINT    uTranLen; char *  szVer; UINT    uVerLen; int     iIndex; int     iString; char    szSfi[255]; VS_FIXEDFILEINFO *pFfi;

char *VerStrings[] = { "CompanyName", "FileDescription", "FileVersion", "InternalName", "LegalCopyright", "OriginalFilename", "ProductName", "ProductVersion", "Comments", "LegalTrademarks", "PrivateBuild", "SpecialBuild" };

if ( argc < 2 ) { printf( "usage: VxdVer " ); return; }

dwResSize = GetVxdVersionInfoSize( argv[1] ); if ( !dwResSize ) { printf( "GetVxdVersionInfoSize failed with error %d.\n",              GetLastError ); return; }

lpData = VirtualAlloc( NULL, dwResSize, MEM_RESERVE | MEM_COMMIT,           PAGE_READWRITE );

if ( lpData ) {

__try {

bSuccess = GetVxdVersionInfo( argv[1], dwResSize, lpData ); if ( !bSuccess ) { printf( "GetVxdVersionInfo failed with error %d.\n",                    GetLastError ); __leave; }

bSuccess = VerQueryValue( lpData, "\\", (void **) &pFfi,                 &uFfiLen ); if ( !bSuccess ) { printf( "VerQueryValue failed with error %d.\n",                    GetLastError ); __leave; }

printf("VS_FIXEDFILEINFO Structure\n"); printf("--\n"); printf("dwSignature = %lu\n", pFfi->dwSignature); printf("dwStrucVersion = %lu\n", pFfi->dwStrucVersion); printf("dwFileVersionMS = %lu\n", pFfi->dwFileVersionMS); printf("dwFileVersionLS = %lu\n", pFfi->dwFileVersionLS); printf("dwProductVersionMS = %lu\n", pFfi->dwProductVersionMS); printf("dwProductVersionLS = %lu\n", pFfi->dwProductVersionLS); printf("dwFileFlagsMask = %lu\n", pFfi->dwFileFlagsMask); printf("dwFileFlags = %lu\n", pFfi->dwFileFlags); printf("dwFileOS = %lu\n", pFfi->dwFileOS); printf("dwFileType = %lu\n", pFfi->dwFileType); printf("dwFileSubtype = %lu\n", pFfi->dwFileSubtype); printf("dwFileDateMS = %lu\n", pFfi->dwFileDateMS); printf("dwFileDateLS = %lu\n", pFfi->dwFileDateLS);

bSuccess = VerQueryValue( lpData, "\\VarFileInfo\\Translation",                 (void **) &lpdwLangCp, &uTranLen ); if ( !bSuccess ) { printf( "VerQueryValue failed with error %d.\n",                    GetLastError ); __leave; }

for ( iIndex = 0; iIndex < (int)( uTranLen / sizeof(void*) );                 iIndex++ ) {

int iItems = sizeof(VerStrings)/sizeof(char *);

// Flip the words to display lang first. wsprintf( szLangCp, "%08X",                    SWAPWORDS( *(lpdwLangCp + iIndex) ) ); printf( "\nlang-codepage = %s\n", szLangCp ); printf( "\n" );

// Cycle through possible string values. for ( iString = 0; iString < iItems; iString++ ) { wsprintf( szSfi, "\\StringFileInfo\\%s\\%s", szLangCp,                       VerStrings[iString] ); bSuccess = VerQueryValue( lpData, szSfi,                       (void **) &szVer, &uVerLen ); if ( bSuccess ) printf( "%s = %s\n", VerStrings[iString], szVer ); }           }

} __finally { VirtualFree( lpData, dwResSize, MEM_RELEASE ); }     }   } Additional query words: vd v x d

Keywords : kbDDK kbResource

Issue type : kbhowto

Technology : kbAudDeveloper kbWin32sSearch kbWin32API