Most win32 binaries, like executables (exe), dynamic link libraries (dll) and automation controls (ocx) contain a version information structure. The data in this version information structure is used by setup programs to decide if it's ok to overwrite the file.
The version information can also be useful for support engineers for determining why a feature doesn't work as expected. Especially when used in a list of all modules loaded by the current Progress process, see ListModules.
Typically a file contains both a productversion and fileversion. The version info structure may also contain strings describing the file or its publisher, but this textual information is kind of difficult to read because they are grouped together in codepage blocks. Productversion and fileversion are not language specific so these are easier to read.
DEFINE VARIABLE vProductVersion AS CHARACTER NO-UNDO. DEFINE VARIABLE vFileVersion AS CHARACTER NO-UNDO. RUN GetProductVersion ( 'c:\windows\system\mfc42.dll', OUTPUT vProductVersion, OUTPUT vFileVersion). MESSAGE vProductVersion SKIP vFileVersion VIEW-AS ALERT-BOX. /* shows 6.0.1.0 6.0.8267.0 on my system. This indicates someone or something installed the runtime modules for MS Visual Studio 6 */
PROCEDURE GetProductVersion : DEFINE INPUT PARAMETER pFilename AS CHARACTER NO-UNDO. DEFINE OUTPUT PARAMETER pProductVersion AS CHARACTER NO-UNDO. DEFINE OUTPUT PARAMETER pFileVersion AS CHARACTER NO-UNDO. DEFINE VARIABLE dummy AS INTEGER NO-UNDO. DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO. DEFINE VARIABLE lpVersionInfo AS MEMPTR NO-UNDO. /* VS_VERSION_INFO structure */ DEFINE VARIABLE lpFixedFileInfo AS MEMPTR NO-UNDO. /* VS_FIXEDFILEINFO structure */ DEFINE VARIABLE versize AS INTEGER NO-UNDO. /* size of lpVersionInfo */ DEFINE VARIABLE ptrInfo AS INTEGER NO-UNDO. /* address of lpFixedFileInfo */ DEFINE VARIABLE cInfo AS INTEGER NO-UNDO. /* size of lpFixedFileInfo */ RUN GetFileVersionInfoSizeA (pFileName, OUTPUT dummy, OUTPUT versize). IF versize = 0 THEN RETURN. SET-SIZE(lpVersionInfo) = 0. SET-SIZE(lpVersionInfo) = versize. RUN GetFileVersionInfoA ( pFileName, 0, INPUT versize, INPUT GET-POINTER-VALUE(lpVersionInfo), OUTPUT returnvalue). IF returnvalue = 0 THEN DO: SET-SIZE(lpVersionInfo) = 0. RETURN. END. RUN VerQueryValueA (GET-POINTER-VALUE(lpVersionInfo), "\":U, OUTPUT ptrInfo, OUTPUT cInfo, OUTPUT returnvalue). IF NOT (returnvalue=0 OR cInfo=0) THEN DO: SET-SIZE(lpFixedFileInfo) = cInfo. SET-POINTER-VALUE(lpFixedFileInfo) = ptrInfo. pProductVersion = STRING(GET-SHORT (lpFixedFileInfo,19)) + '.' + STRING(GET-SHORT (lpFixedFileInfo,17)) + '.' + STRING(GET-SHORT (lpFixedFileInfo,23)) + '.' + STRING(GET-SHORT (lpFixedFileInfo,21)). pFileVersion = STRING(GET-SHORT (lpFixedFileInfo,11)) + '.' + STRING(GET-SHORT (lpFixedFileInfo, 9)) + '.' + STRING(GET-SHORT (lpFixedFileInfo,15)) + '.' + STRING(GET-SHORT (lpFixedFileInfo,13)). END. SET-SIZE (lpVersionInfo) = 0. /* ------ DON'T DO THIS: -------- SET-SIZE (lpFixedFileInfo) = 0. */ END PROCEDURE.
Definitions used in this procedure:
PROCEDURE GetFileVersionInfoSizeA EXTERNAL "version.dll" : DEFINE INPUT PARAMETER lptstrFilename AS CHARACTER. DEFINE OUTPUT PARAMETER lpdwHandle AS LONG. DEFINE RETURN PARAMETER VersionInfoSize AS LONG. END PROCEDURE. PROCEDURE GetFileVersionInfoA EXTERNAL "version.dll" : DEFINE INPUT PARAMETER lptstrFilename AS CHARACTER. DEFINE INPUT PARAMETER dwHandle AS LONG. DEFINE INPUT PARAMETER dwLen AS LONG. DEFINE INPUT PARAMETER lpData AS LONG. DEFINE RETURN PARAMETER ReturnValue AS LONG. END PROCEDURE. PROCEDURE VerQueryValueA EXTERNAL "version.dll" : DEFINE INPUT PARAMETER lpBlock AS LONG. DEFINE INPUT PARAMETER lpSubBlock AS CHARACTER. DEFINE OUTPUT PARAMETER lplpBuffer AS LONG. DEFINE OUTPUT PARAMETER puLen AS LONG. DEFINE RETURN PARAMETER ReturnValue AS LONG. END PROCEDURE.