📄 user_guide.html
字号:
<p>See Appendix 1 for a description of all the predefined resource types. </p>
<p class="gototop"><a href="#Top">Back to top</a></p>
<h3><a name="Examples"></a>Examples</h3>
<h4><a name="eg1"></a>Example 1: Loading a resource file</h4>
<p>In this first example we demonstrate how to create a resource file object and
how to load a file into it. The following code fragment shows how this is done.
</p>
<pre><span class="pascal-kw">var</span>
ResFile: TPJResourceFile;
...
<span class="pascal-kw">begin</span>
ResFile := TPJResourceFile.Create;
<span class="pascal-kw">try</span>
ResFile.LoadFromFile('MyResFile.res');
...
<span class="pascal-comment">// Do something with resource file object</span>
...
<span class="pascal-kw">finally</span>
ResFile.Free;
<span class="pascal-kw">end</span>;
<span class="pascal-kw">end</span>;</pre>
<p>First we create a <em>TPJResourceFile</em> object and then use its <em>LoadFromFile</em>
method read a file from disk. We then process the file in some way and once
we are finished we free the resource file object. That's all there is to it.
Note that if the given file does not contain a valid 32 bit resource file an
exception will be raised.</p>
<p>We can also read resource data from a stream rather than loading from file
by using the <em>LoadFromStream</em> method of <em>TPJResourceFile</em> in place
of <em>LoadFromFile</em>. </p>
<p class="gototop"><a href="#Top">Back to top</a></p>
<h4><a name="eg2"></a>Example 2: Accessing all resources in a file</h4>
<p>In our next example we show how to scan through all the resources in a file
and how to list some information about each one. The following example assumes
we have created a resource files object <em>ResFile</em> and have loaded a resource
file into it (as in example 1). We also assume that the form contains a memo
named <em>Memo1</em>. Here is the code: </p>
<pre><span class="pascal-kw">var</span>
ResFile: TPJResourceFile;
ResEntry: TPJResourceEntry;
EntryIdx: Integer;
<span class="pascal-kw">begin</span>
...
<span class="pascal-comment">// Assume ResFile contains a loaded resource file</span>
...
Memo1.Clear;
<span class="pascal-kw">for</span> EntryIdx := 0 <span class="pascal-kw">to</span> Pred(ResFile.EntryCount) <span class="pascal-kw">do</span>
<span class="pascal-kw">begin</span>
ResEntry := ResFile.Entries[EntryIdx];
Memo1.Lines.Add(
Format(
'Type: "%s" Name: "%s" LanguageID: %0.4X',
[ResIDToStr(ResEntry.ResType), ResIDToStr(ResEntry.ResName),
ResEntry.LanguageID]
)
);
<span class="pascal-kw">end</span>;
...
<span class="pascal-comment">// Don't forget to free ResFile at some stage.</span>
<span class="pascal-kw">end</span>;</pre>
<p>This code uses both <em>TPJResourceFile</em> and <em>TPJResourceEntry</em>
objects. The resource file's <em>EntryCount</em> property tells us how many
resources there are in the file. Each resource is represented by a <em>TPJResourceEntry</em>
object made available from the integer indexed <em>Entries[]</em> array property.
So we loop through all the valid indexes in <em>Entries[]</em> and store a reference
to each resource entry in turn. Having got the resource entry object we now
access its <em>ResType</em>, <em>ResName</em> and <em>LanguageID</em> properties
to get the information we want to display.</p>
<p>The details of each entry are formatted by Delphi's <em>Format</em> function
and added to <em>Memo1</em>. Note that we use the <em>ResIDToStr</em> helper
function to get a string representation of the resource type and name. We display
the language ID as a four digit hex number since the value is a Word.</p>
<p>You may have noticed that we have not freed any of the resource entry objects.
This is not necessary since they are all freed automatically when the resource
files object is freed (as shown in example 1). </p>
<p class="gototop"><a href="#Top">Back to top</a></p>
<h4><a name="eg3"></a>Example 3: Finding a resource </h4>
<p>To find a resource we use either the <em>FindEntry</em> or <em>FindEntryIndex</em>
methods. The difference is that <em>FindEntry</em> returns the <em>TPJResourceEntry</em>
object for the entry (or nil if not found) while <em>FindEntryIndex</em> returns
the index of the entry in the <em>Entries[]</em> property.</p>
<p>Let's assume a resource file is loaded into the <em>TPJResourceFile</em> variable
<em>ResFile</em>. We want to find a <code>RT_HTML</code> resource named <code>INDEX_HTML</code>.
The following code checks if such a resource exists and displays its data size
in a message box, or a message saying the reosurce doesn't exist. This first
version of the code uses <em>FindEntry</em>:</p>
<pre><span class="pascal-comment">// Version using FindEntry</span>
<span class="pascal-kw">var</span>
ResFile: TPJResourceFile;
Entry: TPJResourceEntry;
<span class="pascal-kw">begin</span>
...
<span class="pascal-comment">// Assume ResFile contains a loaded resource file</span>
...
Entry := ResFile.FindEntry(RT_HTML, 'INDEX_HTML', $0809);
<span class="pascal-kw">if</span> Assigned(Entry) <span class="pascal-kw">then</span>
ShowMessageFmt(
'Data size for INDEX_HTML is %d',
[Entry.DataSize]
)
<span class="pascal-kw">else</span>
ShowMessage('Can''t find resource');
...
<span class="pascal-comment">// Don't forget to free ResFile at some stage.</span>
<span class="pascal-kw">end</span>;</pre>
<p> This second version of the code shows how the same result is obtained with
<em>FindEntryIndex</em>:</p>
<pre><span class="pascal-comment">// Version using FindEntryIdex</span>
<span class="pascal-kw">var</span>
ResFile: TPJResourceFile;
Entry: TPJResourceEntry;
Idx: Integer;
<span class="pascal-kw">begin</span>
...
Idx := fResFile.FindEntryIndex(RT_HTML, 'INDEX_HTML');
<span class="pascal-kw">if</span> Idx >= 0 <span class="pascal-kw">then</span>
<span class="pascal-kw">begin</span>
Entry := fResFile.Entries[Idx];
ShowMessageFmt(
'Data size for INDEX_HTML is %d', [Entry.DataSize]
);
<span class="pascal-kw">end</span>
...
<span class="pascal-kw">end</span>;</pre>
<p>Note that we have used the "short form" of the <em>FindEntry</em>
and <em>FindEntryIndex</em> methods above: they find the first resource with
the given type and name, irrespective of language. The long version of the methods
finds a specific resource type, name and language. For example the following
code finds a <code>RT_HTML</code> resource named <code>INDEX_HTML</code> with
language $0809:</p>
<pre><span class="pascal-comment">// "Full" version of FindEntry</span>
<span class="pascal-kw">var</span>
ResFile: TPJResourceFile;
Entry: TPJResourceEntry;
<span class="pascal-kw">begin</span>
...
Entry := ResFile.FindEntryIndex(
RT_HTML, 'HTMLRES_HTML', $0809
);
<span class="pascal-kw">if</span> Assigned(Entry) <span class="pascal-kw">then</span>
... etc ...
<span class="pascal-kw">end</span>;</pre>
<p class="gototop"><a href="#Top">Back to top</a></p>
<h4><a name="eg4"></a>Example 4: Listing specific resources from a file </h4>
<p>We can use the <em>IsMatching</em> method of <em>TPJResourceEntry</em> to check
if a specific resource matches given criteria. <em>IsMatching</em> can match
just a resource type, and resource type and name or can uniquely identify a
resource in a file by matching its type, name and language. Like <em>TPJResourceFile.FindEntry</em>,
the language ID parameter is optional. The resource name parameter can be nil
if we don't want to specify the name in the match.</p>
<p>Given the above description of <em>IsMatching</em>, we can list all the <code>RT_HTML</code>
resources in a resource file in a <em>TMemo</em> with this code:</p>
<pre><span class="pascal-kw">var</span>
ResFile: TPJResourceFile;
Entry: TPJResourceEntry;
Idx: Integer;
<span class="pascal-kw">begin</span>
...
<span class="pascal-comment">// Assume ResFile contains a loaded resource file</span>
...
<span class="pascal-kw">for</span> Idx := 0 to Pred(ResFile.EntryCount) <span class="pascal-kw">do</span>
<span class="pascal-kw">begin</span>
Entry := ResFile.Entries[Idx];
<span class="pascal-kw">if</span> Entry.IsMatching(RT_HTML, <span class="pascal-kw">nil</span>) <span class="pascal-kw">then</span>
Memo1.Lines.Add(
Format('%s', [ResIDToStr(Entry.ResName)])
);
<span class="pascal-kw">end</span>;
...
<span class="pascal-kw">end</span>;</pre>
<p>To list only all the different language versions of the <code>RT_HTML</code>
resource named <code>INDEX_HTML</code> we simply change the <em>IsMatching</em>
method call in the for loop to:</p>
<pre>Entry.IsMatching(RT_HTML, 'INDEX_HTML')</pre>
<p class="gototop"><a href="#Top">Back to top</a></p>
<h4><a name="eg5"></a>Example 5: Adding or modifying a resource's data</h4>
<p>While the code in this unit does not understand the various resource data formats
it does assist in reading, adding, updating and deleting the raw resource data.
The <em>TPJResourceEntry</em> class's <em>Data</em> object exposes the resource
data as a <em>TStream</em> which means that we can use normal stream handling
techniques to access the data.</p>
<h5>Reading the data</h5>
<p>The following code fragment shows how to read all the data from the resource
to a buffer.</p>
<pre><span class="pascal-kw">var</span>
Entry: TPJResourceEntry;
Buf: PByte;
<span class="pascal-kw">begin</span>
...
<span class="pascal-comment">// Make sure Entry references a resource object</span>
...
<span class="pascal-comment">// Create buffer of required size</span>
GetMem(Buf, Entry.DataSize);
<span class="pascal-kw">try</span>
<span class="pascal-comment">// Make sure resource data stream at start</span>
Entry.Data.Position := 0;
<span class="pascal-comment">// Read all resource data into buffer</span>
Entry.Data.ReadBuffer(Buf^, Entry.DataSize);
<span class="pascal-comment">// Rewind data stream again</span>
Entry.Data.Position := 0;
...
<span class="pascal-comment">// Do something with Buf</span>
...
<span class="pascal-kw">finally</span>
<span class="pascal-comment">// Release buffer</span>
FreeMem(Buf);
<span class="pascal-kw">end</span>;
<span class="pascal-kw">end</span>;</pre>
<p>We first set the buffer to the required size using <em>TPJResourceEntry</em>'s
<em>DataSize</em> property (The <em>Data</em> property's own <em>Size</em> property
also gives this information). We now ensure the data stream is positioned at
the start (you can't assume this!) and then read al the data into the buffer
using <em>TStream</em>'s <em>ReadBuffer</em> method, and finally reposition
the stream again ready for the next use. Having processed the data in the buffer
in some way we finally free the buffer.</p>
<p>It may be more convenient to copy the data stream to another stream. The next
example illustrates this by storing the resource data in a file named 'ResEntry.dat':</p>
<pre><span class="pascal-kw">var</span>
Entry: TPJResourceEntry;
FS: TFileStream;
<span class="pascal-kw">begin</span>
...
<span class="pascal-comment">// Make sure Entry references a resource object</span>
...
<span class="pascal-comment">// Open stream onto new file</span>
FS := TFileStream.Create('ResEntry.dat', fmCreate);
<span class="pascal-kw">try</span>
<span class="pascal-comment">// Copy resource data to file</span>
FS.CopyFrom(Entry.Data, 0);
Entry.Data.Position := 0;
<span class="pascal-kw">finally</span>
<span class="pascal-comment">// Close the file</span>
FS.Free;
<span class="pascal-kw">end</span>;
<span class="pascal-kw">end</span>;</pre>
<p>Here we first open a stream onto a new file. We then use <em>TStream</em>'s
<em>CopyFrom</em> method to copy the whole of the resource data to the file
stream. Note by specifying a size of 0 to the <em>CopyFrom</em> method, <em>TStream</em>
automatically positions the resource data stream to the start and copies the
whole stream, so we don't need to position it first. Once again we reset the
resource data stream once we are done.</p>
<h5>Deleting data</h5>
<p>It is very easy to delete all the data in a resource: simply set the data stream's
size to 0 as follows.</p>
<pre><span class="pascal-kw">var</span>
Entry: TPJResourceEntry;
<span class="pascal-kw">begin</span>
...
<span class="pascal-comment">// Make sure Entry references a resource object</span>
...
Entry.Data.Size := 0;
...
<span class="pascal-kw">end</span>;</pre>
<p>Note that you must set the <em>Size</em> property of the entry's <em>Data</em>
property here: you can't set the <em>DataSize</em> property since it is read
only.</p>
<h5>Writing data</h5>
<p>We can add data to an exisiting resource simply. Let's first look at how to
overwrite the existing data and then show how to append data to an existing
resource. For the purposes of this example, assume we have a user defined resource
that stores some plain text. Again, Entry is a <em>TPJResourceEntry</em> object
that references our resource. We will replace any existing data with the text
"Hello World".</p>
<pre><span class="pascal-kw">var</span>
Entry: TPJResourceEntry;
Text: string;
<span class="pascal-kw">begin</span>
...
<span class="pascal-comment">// Make sure Entry references a resource object</span>
...
<span class="pascal-comment">// Delete any existing data</span>
Entry.Data.Size := 0;
<span class="pascal-comment">// Write the required text</span>
Text := 'Hello World';
Entry.Data.WriteBuffer(Text[1], Length(Text));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -