Subversion Repositories spacemission

Compare Revisions

Problem with comparison.

Regard whitespace Rev HEAD → Rev 1

/VCL_PJVERSIONINFO/PJVersionInfo.htm
0,0 → 1,282
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
 
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>PJSoft Info Sheet: TPJVersionInfo Component (32 bit)</TITLE>
<BASE target="_blank">
</HEAD>
 
<BODY>
<h1>TPJVersionInfo Component (32 bit)</h1>
<p></P>
 
<P>
<HR noshade>
<p></P>
 
<H2>Contents</H2>
 
<UL>
<LI><A HREF="#Description" target="_self">Description</A>
<LI><A HREF="#Compatibility" target="_self">Compatibility</A>
<LI><A HREF="#Installation" target="_self">Installation</A>
<LI><A HREF="#Issues" target="_self">Known Issues</A>
<LI><A HREF="#Update" target="_self">Update History</A>
<LI><A HREF="#License" target="_self">License and Disclaimer</A>
<LI><A HREF="#Author" target="_self">About the Author</A>
</UL>
 
<P>
<HR noshade>
<p></P>
 
<H2><A NAME="Description"></A>Description</H2>
 
<P>This is a 32 bit non-visual component for Delphi 2 to 6 that encapsulates file
version resource information contained in a file.</P>
 
<P>The component reads information from the file's VERSIONINFO resource. If the
file has no such resource then this component returns no information. The HaveInfo
property informs whether the component has been able to get version information
from the file. The 32 bit version of TPJVersionInfo can access variable file
information for each language provided in the resource.</P>
 
<P>The file from which resource information is gleaned is determined by the FileName
property. Setting the file name property to the empty string makes the component
read information from the executable file in which it embedded. Apart from the
usual Name and Tag properties the FileName property is the only design-time
property of the component. With the exception of the property that selects the
language for which variable file information is to be returned, all other properties
are read only. These properties present the information from the VERSIONINFO
resource to the user. See the help file for further information.</P>
<P>The component introduces no new methods and it has no events.</P>
 
<H3>Limitations</H3>
 
<P>This version of the component makes calls to the 32 bit Windows API. It is
not suitable for compilation using the 16 bit Delphi 1 compiler.</P>
 
<H3>Further information</H3>
 
<P>For detailed information about file version information refer to the Win32
SDK.</P>
 
<P>
<HR noshade>
<p></P>
 
<H2><A NAME="Compatibility"></A>Compatibility</H2>
 
<P>This version of the component works only with 32 bit versions of Delphi. It
has been tested with Delphi versions 2, 3, 4 and 6. It is assumed to work correctly
with Delphi 5. A separate version of the component is available for 16 bit Delphi
1.</P>
 
<P>The unit name has changed to <code>PJVersionInfo</code> in this release of
the code - this means that programs using earlier versions will need to be modified
(or to have an alias set in Delphi's Project Options) before being recompiled
using the new version.</P>
<P>This component is backward compatible with previous 32 bit releases. In previous
releases the help file was designed for integration with the Delphi 2 IDE but
was not compatible with the OpenHelp system used from Delphi 3 onwards. From
this release the help file has been updated to integrate with the Delphi 3 and
later IDE. It is no longer compatible with the Delphi 2 IDE, although can be
used separately.</P>
 
<P>
<HR noshade>
<p></P>
 
<H2><A NAME="Installation"></A>Installation</H2>
 
<P>In these instructions <CODE><STRONG>$(DELPHI)</STRONG></CODE> is to be taken to represent the path where your 32 bit version of Delphi was installed. For example, if you have Delphi 4 installed on the path <CODE>C:\Program&nbsp;Files\Borland\Delphi4</CODE> then <CODE>$(DELPHI)</CODE> represents that path.</P>
 
<H3>Installation with Delphi 2</H3>
 
<p>Note that although the provided help file gives information about using the
component it cannot be linked into the Delphi 2 environment.</p>
<OL>
<LI>Unzip the component's <code>.zip</code> file into a folder, preserving the
directory structure.
<li>Copy the files <CODE>PJVersionInfo.pas</CODE> and <CODE>PJVersionInfo.dcr</CODE>
to the folder from where you wish to install the component into the Delphi
Component Palette. This will probably be an existing folder where you keep
the library components - say the default <CODE>$(DELPHI)\lib</CODE> folder.
</li>
<li>Start Delphi. Select the <EM>Options | Install Components</EM> menu option.
Click the <EM>Add</EM> button, then the <EM>Browse</EM> button and navigate
to the <CODE>PJVersionInfo.pas</CODE> file in the folder where you placed
it. Click <EM>OK</EM> to recompile the components library. </li>
<LI>You can now delete <code>PJVersionInfo.pas</code> from the place where you
copied it if you wish. The component will appear on a palette called <EM>PJ
Stuff</EM>. You can move the component to a different palette as required,
or hack the source code (before installing the component) by finding the <CODE>Register</CODE>
procedure at the end of the code and changing the string <CODE>'PJ stuff'</CODE>
to the name of the required palette.
</OL>
 
<H3>Installation with Delphi 3 and later</H3>
 
<OL>
<LI>Unzip the component's <code>.zip</code> file into a folder, preserving the
directory structure.
<li>Copy the files <CODE>PJVersionInfo.pas</CODE> and <CODE>PJVersionInfo.dcr</CODE>
to the folder from where you wish to install the component into the Delphi
Component Palette. This will probably be a sub-folder of the <CODE>$(DELPHI)\lib</CODE>
folder. </li>
<LI>Install the component into the palette by choosing the <EM>Component | Install
Component</EM> menu option. The following instructions assume you are installing
into the default "users components" package:
<UL>
<LI>Select the "Into existing package" page of the <EM>Install Components</EM>
dialogue box.
<LI>Browse to the folder where you saved <CODE>PJVersionInfo.pas</CODE>
and select the file.
<LI>Ensure that the "Package file name" edit box contains <CODE>$(DELPHI)\lib\dclusrX0.dpk</CODE>
(where X is the version number of Delphi).
<LI>Accept that the package will be rebuilt.
<LI>A dialogue box should be displayed saying that <em>TPJVersionInfo</em>
has been added to the component palette.
</UL>
<LI>You can now delete <CODE>PJVersionInfo.pas</CODE> from the place where you
copied it if you wish. The component will appear on a palette called <EM>PJ
Stuff</EM>. You can move the component to a different palette as required,
or hack the source code (before installing the program) by finding the <CODE>Register</CODE>
procedure at the end of the code and changing the string <CODE>'PJ stuff'</CODE>
to the name of the required palette.
<li>The simplest way to install the help file is to use the <em>PJSoft Component
Help Installer Expert,</em> available from my website. To install manually,
proceed as follows (replace X is your version of Delphi): </li>
<ul>
<li>Copy <code>PJVersionInfo.hlp</code> to whichever folder you wish to install
it to. </li>
<li>Create a text file named <code>PJVersionInfo.cfg</code> in your Delphi
Help folder. Enter the following two lines:<code><br>
&nbsp;&nbsp;&nbsp;:Index PJSoft Version Info Component=PJVersionInfo.hlp<br>
&nbsp;&nbsp;&nbsp;:Link PJVersionInfo.hlp</code><br>
</li>
<li>Edit the <code>DelphiX.cnt</code> file (where is is your Delphi version)
and add the line:<br>
<code>&nbsp;&nbsp;&nbsp;:Include PJVersionInfo.cfg </code></li>
<li>Using RegEdit open the key <code>HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Help</code>
and add a new string value named <code>PJVersionInfo.hlp</code> whose value
is the path where you copied the help file (probably <code>($DELPHI)\Help</code>).
</li>
</ul>
</OL>
<P>
<HR noshade>
<p></P>
 
<H2><A NAME="Issues"></A>Known Issues</H2>
 
<UL>
<LI>None known.
</UL>
 
<P>
<HR noshade>
<p></P>
 
<H2><A NAME="Update"></A>Update History</H2>
 
<P><STRONG>Unreleased</STRONG><BR>
<EM>VerInfo v1.0 of 26/04/1998</EM></P>
<UL>
<LI>Original version - 16 bit only.
</UL>
 
<P><STRONG>Unreleased</STRONG><BR>
<EM>VerInfo v2.0 of 06/12/1998</EM></P>
<UL>
<LI>Revised for use with Win32. Not compatible with v1.0 which continued to
be used with 16 bit Delphi (see <CODE>vinfo16.htm</CODE> for continued update
history of v1).
</UL>
 
<P><STRONG>Release 2.0.1 of 08/07/1999</STRONG><BR>
<EM>VerInfo v2.0.1 of 09/04/1999</EM> <BR>
(This release also included Release 1.0 of 16 bit VerInfo v1.0.1 - see <CODE>vinfo16.htm</CODE> for details).</P>
<UL>
<LI>Changed palette where component installs to "PJ Stuff" from "Own".
<LI>Added HTML documentation (shared documentation with Release 1.0.1).
</UL>
 
<P><STRONG>Release 2.1 of 28/11/1999</STRONG><BR><EM>VInfo v2.1 of 28/11/1999</EM>
<BR>(Separated 16 bit and 32 bits versions into separate releases).</P>
<UL>
<LI>Changed unit name from VerInfo to VInfo to allow component to install under Delphi 3 &amp; 4
(VerInfo clashes with an existing unit in these versions).
<LI>Removed superfluous conditional compilation directives.
<LI>Updated HTML documentation to separate 16 bit from 32 bit version, to to include
installation notes for Delphi 3/4 and to include update history.
</UL>
 
<P><strong>Release 3.0 of 17/02/2002</strong><br>
<em>PJVersionInfo v3.0 of 17/02/2002</em>
<ul>
<li>Added ability to access all "translations" stored in a file's version information,
rather than just first one. This has been done so that code using earlier
versions of this component should continue to work unchanged.
<li>Added new property to expose fixed file information record.
<li>Added new "string array" property to give access to string information by
name: this property can access any custom string information if the name is
known.
<li>Added properties to return number of "translations" and to select index
of "translation" to be used.
<li>Added properties to return language and character set codes in addition
to descriptive strings.
<li>All string info, language and character set properties now return values
from the currently selected translation (which defaults to the first translation
maintaining backward compatibilty).
<li>Empty FileName property now accesses name of host application per command
line rather than using Application.ExeName.
<li>CharSet property now returns '' for unknown value rather than 'Unknown'.
<li>Renamed TVersionNumber record to TPJVersionNumber.
<li>Replaced Tvs_FixedFileInfo record with use of Windows unit defined type
TVSFixedFileInfo
<li>Renamed unit to PJVersionInfo.
<li>Changed component palette from PJ Stuff to PJSoft.
</ul>
<p>
<P>
<HR noshade>
<p></P>
 
<H2><A NAME="License"></A>License &amp; Disclaimer</H2>
 
<P>This component is copyright &copy; P.D.Johnson, 1998-2002.</P>
 
<P>The source code and help files can be freely distributed on a not-for-profit basis providing that:</P>
 
<OL>
<LI>the source code is not altered.
<LI>this readme file is distributed with it unchanged
</OL>
 
<P>By not-for-profit I mean that you may recover out of pocket expenses incurred in distributing the code, but should not make a profit from this.</P>
 
<P>If you discover any bugs in this implementation, or if you have any update suggestions, please contact me on <A HREF="mailto:peter.johnson@openlink.org">peter.johnson@openlink.org</A>.</P>
 
<P>Please do modify the code for you own use. I'd like to see any changes you make - I could incorporate them into future versions. Please notify me of changes on at the above e-mail address.</P>
 
<P>This software is provided as is - no warranty is given as to its suitability for any purposes to which you may wish to put it.</P>
 
<P>
<HR noshade>
<p></P>
 
<H2><A NAME="Author"></A>About the Author</H2>
 
<P>I'm Peter Johnson - a hobbyist programmer living in Ceredigion in West Wales,
UK, writing mainly in Delphi. My programs are available for download on my
website: <a href="http://www.pjsoft.contactbox.co.uk/">http://www.pjsoft.contactbox.co.uk/</a>.</P>
 
<P>I can be contacted by e-mail on <A HREF="mailto:peter.johnson@openlink.org">peter.johnson@openlink.org</A>.
 
</BODY>
 
</HTML>
 
 
/VCL_PJVERSIONINFO/PJVersionInfo.dcu
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/VCL_PJVERSIONINFO/PJVersionInfo.pas
0,0 → 1,582
{ ##
@FILE PJVersionInfo.pas
@COMMENTS Version Information Component (32 bit) source code
(development split from 16 bit version after v1.0).
@PROJECT_NAME Version Information Component
@PROJECT_DESC Component that reads version information from files.
@OTHER_NAMES + Original unit name was VerInfo.pas
+ Changed to VInfo.pas at v2.1
+ Changed to PJVersionInfo.pas at v3.0
@AUTHOR Peter Johnson, LLANARTH, Ceredigion, Wales, UK
@EMAIL peter.johnson@openlink.org
@WEBSITE http://www.pjsoft.contactbox.co.uk/
@COPYRIGHT © 1998-2002, Peter D Johnson.
@LEGAL_NOTICE This component is placed in the public domain. It
may be freely copied and circulated on a not for
profit basis providing that the code is unmodified
and this notice and information about the author and
his copyright remains attached to the source code.
@CREDITS In producing this component some techniques were
used which were learned from FVersion by PJ Veger,
Best, The Netherlands (Feb/96). In particular the
method of accessing language and char-set tables was
taken from PJ Veger's code.
@HISTORY(
@REVISION(
@VERSION 1.0
@DATE 25/04/1998
@COMMENTS Original version - 16 bit only.
)
@REVISION(
@VERSION 2.0
@DATE 06/12/1998
@COMMENTS Revised for use with 32 bit Windows. Not compatible
with v1.
)
@REVISION(
@VERSION 2.0.1
@DATE 09/04/1999
@COMMENTS Changed installation palette from "Own" to "PJ
Stuff".
)
@REVISION(
@VERSION 2.1
@DATE 28/11/1999
@COMMENTS + Changed unit name to VInfo from VerInfo to allow
component to install under Delphi 3 & 4 (VerInfo
clashes with an existing unit in these versions).
+ Removed superfluous conditional compilation
directives.
)
@REVISION(
@VERSION 3.0
@DATE 17/02/2002
@COMMENTS Major update:
+ Added ability to access all "translations" stored
in a file's version information, rather than just
first one. This has been done so that code using
earlier versions of this component should continue
to work unchanged.
+ Added new property to expose fixed file
information record.
+ Added new "string array" property to give access
to string information by name: this property can
access any custom string information if the name
is known.
+ Added properties to return number of
"translations" and to select index of
"translation" to be used.
+ Added properites to return language and character
set codes in addition to descriptive strings.
+ All string info, language and character set
properties now return values from the currently
selected translation (which defaults to the first
translation maintaining backward compatibilty).
+ Empty file name string now accesses name of host
application per command line rather than using
Application.ExeName. This enables this code to
work correctly even if user changes name of
executable file.
+ CharSet property now returns '' for unknown value
rather than 'Unknown'
+ Renamed unit to PJVersionInfo from VInfo.
+ Renamed TVersionNumber record to TPJVersionNumber
+ Replaced Tvs_FixedFileInfo record with use of
Windows unit defined type TVSFixedFileInfo.
+ Changed component palette from PJ Stuff to PJSoft
)
)
}
 
 
unit PJVersionInfo;
 
interface
 
uses
// Delphi
Windows, Classes;
 
type
 
{
TPJVersionNumber:
Record holding version numbers.
}
TPJVersionNumber = record
V1, V2, V3, V4: WORD;
end;
 
{
TPJVersionInfo:
Component that exposes the version information embedded in an executable
file and exposed the detail as properties.
}
TPJVersionInfo = class(TComponent)
private // properties
fFileName: string;
fHaveInfo: Boolean;
fNumTranslations: Integer;
fCurrentTranslation: Integer;
fFixedFileInfo: TVSFixedFileInfo;
procedure SetFileName(AName: string);
function GetProductVersionNumber: TPJVersionNumber;
function GetFileVersionNumber: TPJVersionNumber;
function GetLanguage: string;
function GetCharSet: string;
function GetCharSetCode: WORD;
function GetLanguageCode: WORD;
function GetCurrentTranslation: Integer;
procedure SetCurrentTranslation(const Value: Integer);
function GetStringFileInfo(const Name: string): string;
function GetStringFileInfoByIdx(Index: Integer): string;
private
fPInfoBuffer: PChar;
{Pointer to info buffer}
fPTransBuffer: Pointer;
{Pointer to translation buffer}
procedure GetInfoBuffer(Len: DWORD);
{Creates an info buffer of required size}
procedure GetTransBuffer(Len: UINT);
{Creates a translation table buffer of required size}
function GetTransStr: string;
{Translation info encoded in string: takes into account current
translation}
protected
procedure ClearProperties; virtual;
{Forces properties to return cleared values}
procedure ReadVersionInfo; virtual;
{Reads version info from file}
public
constructor Create(AOwner: TComponent); override;
{Class constructor: sets default values}
destructor Destroy; override;
{Class destructor: frees allocated memory}
{Properties}
property HaveInfo: Boolean
read fHaveInfo;
{Property true if file version info for the file per FileName property has
been successfully read}
property FixedFileInfo: TVSFixedFileInfo
read fFixedFileInfo;
{Exposes the whole fixed file info record: following properties expose
the various fields of it}
property FileVersionNumber: TPJVersionNumber read
GetFileVersionNumber;
{Version number of file, in numeric format, from fixed file info}
property ProductVersionNumber: TPJVersionNumber
read GetProductVersionNumber;
{Version number of product, in numeric format, from fixed file info}
property FileOS: DWORD
read fFixedFileInfo.dwFileOS;
{Code describing operating system to be used by file}
property FileType: DWORD
read fFixedFileInfo.dwFileType;
{Code descibing type of file}
property FileSubType: DWORD
read fFixedFileInfo.dwFileSubType;
{Code describing sub-type of file - only used for certain values of
FileType property}
property FileFlagsMask: DWORD
read fFixedFileInfo.dwFileFlagsMask;
{Code describing which FileFlags are valid}
property FileFlags: DWORD
read fFixedFileInfo.dwFileFlags;
{Flags describing file state}
property Comments: string index 0
read GetStringFileInfoByIdx;
{String file info property giving user defined comments for current
translation}
property CompanyName: string index 1
read GetStringFileInfoByIdx;
{String file info property giving name of company for current translation}
property FileDescription: string index 2
read GetStringFileInfoByIdx;
{String file info property giving description of file for current
translation}
property FileVersion: string index 3
read GetStringFileInfoByIdx;
{String file info property giving version number of file in string format
for current translation}
property InternalName: string index 4
read GetStringFileInfoByIdx;
{String file info property giving internal name of file for current
translation}
property LegalCopyright: string index 5
read GetStringFileInfoByIdx;
{String file info property giving copyright message for current
translation}
property LegalTrademarks: string index 6
read GetStringFileInfoByIdx;
{String file info property giving trademark info for current translation}
property OriginalFileName: string index 7
read GetStringFileInfoByIdx;
{String file info property giving original name of file for current
translation}
property PrivateBuild: string index 8
read GetStringFileInfoByIdx;
{String file info property giving information about a private build of
file for current translation}
property ProductName: string index 9
read GetStringFileInfoByIdx;
{String file info property giving name of product for current translation}
property ProductVersion: string index 10
read GetStringFileInfoByIdx;
{String file info property giving version number of product in string
format for current translation}
property SpecialBuild: string index 11
read GetStringFileInfoByIdx;
{String file info property giving information about a special build of
file for current translation}
property StringFileInfo[const Name: string]: string
read GetStringFileInfo;
{Returns the value for string file info with given name for current
translation. This property can return both standard and custom string
info}
property Language: string
read GetLanguage;
{Name of language in use in current translation}
property CharSet: string
read GetCharSet;
{Name of character set in use in current translation}
property LanguageCode: WORD
read GetLanguageCode;
{Code of laguage in use in current translation}
property CharSetCode: WORD
read GetCharSetCode;
{Character set code in use in current translation}
property NumTranslations: Integer
read fNumTranslations;
{The number of difference translations (ie languages and char sets) in
the version information}
property CurrentTranslation: Integer
read GetCurrentTranslation write SetCurrentTranslation;
{Zero-based index of the current translation: this is 0 when a file is
first accessed. Set to a value in range 0..NumTranslations-1 to access
other translations. All string info, language and char set properties
return information for the current translation}
published
property FileName: string read fFileName write SetFileName;
{Name of file to which version information relates}
end;
 
procedure Register;
{Register this component}
 
implementation
 
uses
// Delphi
SysUtils;
 
{ Component registration routine }
 
procedure Register;
{Register this component}
begin
RegisterComponents('PJSoft', [TPJVersionInfo]);
end;
 
{ TPJVersionInfo }
 
type
{
TTransRec:
Record of language code and char set codes that are returned from version
information.
}
TTransRec = packed record // record to hold translation information
Lang, CharSet: Word;
end;
{
TTransRecs:
Type used to type cast translation data into an array of translation
records.
}
TTransRecs = array[0..1000] of TTransRec;
{
PTransRecs:
Pointer to an array of translation records.
}
PTransRecs = ^TTransRecs;
 
procedure TPJVersionInfo.ClearProperties;
{Forces properties to return cleared values}
begin
// Record that we haven't read ver info: this effectively clears properties
// since each property read access method checks this flag before returning
// result
fHaveInfo := False;
end;
 
constructor TPJVersionInfo.Create(AOwner: TComponent);
{Class constructor: sets default values}
begin
inherited Create(AOwner);
// Default is no file name - refers to executable file for application
FileName := '';
end;
 
destructor TPJVersionInfo.Destroy;
{Class destructor: frees allocated memory}
begin
// Ensure that info buffer is freed if allocated
if fPInfoBuffer <> nil then
StrDispose(fPInfoBuffer);
// Ensure that translation buffer is free if allocated
if fPTransBuffer <> nil then
FreeMem(fPTransBuffer);
inherited Destroy;
end;
 
function TPJVersionInfo.GetCharSet: string;
{Read access method for CharSet property: return string describing character
set if we have some version info and empty string if we haven't}
const
// Map code numbers to char-set names
cCharSets: array[0..11] of record
Code: Word; // char set code
Str: string; // associated name of char set
end = (
( Code: 0; Str: '7-bit ASCII' ),
( Code: 932; Str: 'Windows, Japan (Shift - JIS X-0208)'),
( Code: 949; Str: 'Windows, Korea (Shift - KSC 5601)' ),
( Code: 950; Str: 'Windows, Taiwan (GB5)' ),
( Code: 1200; Str: 'Unicode' ),
( Code: 1250; Str: 'Windows, Latin-2 (Eastern European)'),
( Code: 1251; Str: 'Windows, Cyrillic' ),
( Code: 1252; Str: 'Windows, Multilingual' ),
( Code: 1253; Str: 'Windows, Greek' ),
( Code: 1254; Str: 'Windows, Turkish' ),
( Code: 1255; Str: 'Windows, Hebrew' ),
( Code: 1256; Str: 'Windows, Arabic' )
);
var
I: Integer; // loop control
begin
Result := '';
if fHaveInfo then
begin
// We've have ver info: scan table of codes looking for required entry
for I := Low(cCharSets) to High(cCharSets) do
if GetCharSetCode = cCharSets[I].Code then
begin
// found one - record its name
Result := cCharSets[I].Str;
Exit;
end;
end;
end;
 
function TPJVersionInfo.GetCharSetCode: WORD;
{Read access for CharSetCode property: returns char set code for current
translation or 0 if there is no translation or we have no version info}
begin
if fHaveInfo and (GetCurrentTranslation >= 0) then
Result := PTransRecs(fPTransBuffer)^[GetCurrentTranslation].CharSet
else
Result := 0;
end;
 
function TPJVersionInfo.GetCurrentTranslation: Integer;
{Read access method for CurrentTranslation property: returns index to current
translation if we have version info or -1 if no version info}
begin
if fHaveInfo then
Result := fCurrentTranslation
else
Result := -1;
end;
 
function TPJVersionInfo.GetFileVersionNumber: TPJVersionNumber;
{Read access method for FileVersionNumber property: fill version info
structure and return it - if there's no version info all values will be zero}
begin
Result.V1 := HiWord(fFixedFileInfo.dwFileVersionMS);
Result.V2 := LoWord(fFixedFileInfo.dwFileVersionMS);
Result.V3 := HiWord(fFixedFileInfo.dwFileVersionLS);
Result.V4 := LoWord(fFixedFileInfo.dwFileVersionLS);
end;
 
procedure TPJVersionInfo.GetInfoBuffer(Len: DWORD);
{Creates an info buffer of required size}
begin
// Clear any existing buffer
if fPInfoBuffer <> nil then
StrDispose(fPInfoBuffer);
// Create the new one
fPInfoBuffer := StrAlloc(Len);
end;
 
function TPJVersionInfo.GetLanguage: string;
{Read access method for Language property: return string describing language
if we have some version info and empty string if we haven't}
var
Buf: array[0..255] of char; // stores langauge string from API call
begin
// Assume failure
Result := '';
// Try to get language name from Win API if we have ver info
if fHaveInfo and (VerLanguageName(GetLanguageCode, Buf, 255) > 0) then
Result := Buf;
end;
 
function TPJVersionInfo.GetLanguageCode: WORD;
{Read access for LanguageCode property: returns language code for current
translation or 0 if there is no translation or we have no version info}
begin
if fHaveInfo and (GetCurrentTranslation >= 0) then
Result := PTransRecs(fPTransBuffer)^[GetCurrentTranslation].Lang
else
Result := 0;
end;
 
function TPJVersionInfo.GetProductVersionNumber: TPJVersionNumber;
{Read access method for ProductVersionNumber property: fill version info
structure and return it - if there's no version info all values will be zero}
begin
Result.V1 := HiWord(fFixedFileInfo.dwProductVersionMS);
Result.V2 := LoWord(fFixedFileInfo.dwProductVersionMS);
Result.V3 := HiWord(fFixedFileInfo.dwProductVersionLS);
Result.V4 := LoWord(fFixedFileInfo.dwProductVersionLS);
end;
 
function TPJVersionInfo.GetStringFileInfo(const Name: string): string;
{Read access method for StringFileInfo array property: returns string
associated with given name or empty string if we have no version info}
var
CommandBuf: array[0..255] of char; // buffer to build API call command str
Ptr: Pointer; // pointer to result of API call
Len: UINT; // length of structure returned from API
begin
// Set default failure result to empty string
Result := '';
// Check if we have valid information recorded in info buffer - exit if not
if fHaveInfo then
begin
// Build API call command string for reading string file info:
// this uses info string + language and character set
StrPCopy(CommandBuf, '\StringFileInfo\' + GetTransStr + '\' + Name);
// Call API to get required string and return it if successful
if VerQueryValue(fPInfoBuffer, CommandBuf, Ptr, Len) then
Result := PChar(Ptr);
end;
end;
 
function TPJVersionInfo.GetStringFileInfoByIdx(Index: Integer): string;
{Read access method for all string file info properties: returns appropriate
string for the given property or empty string if we have no version info}
const
cNames: array[0..11] of string =
('Comments', 'CompanyName', 'FileDescription', 'FileVersion',
'InternalName', 'LegalCopyright', 'LegalTrademarks', 'OriginalFileName',
'PrivateBuild', 'ProductName', 'ProductVersion', 'SpecialBuild');
{names of predefined string file info strings}
begin
Result := GetStringFileInfo(cNames[Index]);
end;
 
procedure TPJVersionInfo.GetTransBuffer(Len: UINT);
{Creates a translation table buffer of required size}
begin
// Clear any existing buffer
if fPTransBuffer <> nil then
FreeMem(fPTransBuffer);
// Create the new one
GetMem(fPTransBuffer, Len);
end;
 
function TPJVersionInfo.GetTransStr: string;
{Translation info encoded in string: takes into account current translation}
var
TransRec: TTransRec; // translation record in array of translations
begin
if GetCurrentTranslation >= 0 then
begin
// There is a valid current translation: return hex string related to it
TransRec := PTransRecs(fPTransBuffer)^[GetCurrentTranslation];
Result := Format('%4.4x%4.4x', [TransRec.Lang, TransRec.CharSet]);
end
else
// No valid translation string: return empty string
Result := '';
end;
 
procedure TPJVersionInfo.ReadVersionInfo;
{Reads version info from file}
var
Len: UINT; // length of structs returned from API calls
Ptr: Pointer; // points to version info structures
InfoSize: DWORD; // size of info buffer
Dummy: DWORD; // stores 0 in call to GetFileVersionInfoSize
begin
// Record default value of HaveInfo property - no info read
fHaveInfo := False;
// Store zeros in fixed file info structure: this is used when no info
FillChar(fFixedFileInfo, SizeOf(fFixedFileInfo), 0);
// Set NumTranslations property to 0: this is value if no info
fNumTranslations := 0;
// Record required size of version info buffer
InfoSize := GetFileVersionInfoSize(PChar(fFileName), Dummy);
// Check that there was no error
if InfoSize > 0 then
begin
// Found info size OK
// Ensure we have a sufficiently large buffer allocated
GetInfoBuffer(InfoSize);
// Read file version info into storage and check success
if GetFileVersionInfo(PChar(fFileName), Dummy, InfoSize, fPInfoBuffer) then
begin
// Success: we've read file version info to storage OK
fHaveInfo := True;
// Get fixed file info & copy to own storage
VerQueryValue(fPInfoBuffer, '\', Ptr, Len);
fFixedFileInfo := PVSFixedFileInfo(Ptr)^;
// Get first translation table info from API
VerQueryValue(fPInfoBuffer, '\VarFileInfo\Translation', Ptr, Len);
// Ptr is to block of translation records each of size Len:
// work out number of translations
fNumTranslations := Len div SizeOf(TTransRec);
// store translation array in a buffer
GetTransBuffer(Len);
Move(Ptr^, fPTransBuffer^, Len);
// make first translation in block current one (-1 if no translations)
SetCurrentTranslation(0); // adjusts value to -1 if no translations
end;
end;
end;
 
procedure TPJVersionInfo.SetCurrentTranslation(const Value: Integer);
{Write accees method for CurrentTranslation property: if value is out of
translation range then it is set to -1 to indicate no translation}
begin
if (Value >= 0) and (Value < NumTranslations) then
fCurrentTranslation := Value
else
fCurrentTranslation := -1
end;
 
procedure TPJVersionInfo.SetFileName(AName: string);
{Write access method for FileName property: action at design time is different
to run time. At design time we simply record value while at run time we store
value - using actual name of program for '' string - and read the version
information}
begin
if csDesigning in ComponentState then
// We are designing, simply record the required name
fFileName := AName
else
begin
// It's run-time
// use Application exec file name if name is ''
if AName = '' then
fFileName := ParamStr(0)
else
fFileName := AName;
// clear all properties and read file version info for new file
ClearProperties;
ReadVersionInfo;
end;
end;
 
end.