TRichEdit Descendant


In this section, you learn how to create a TRichEdit descendant that can load rich text documents from resource-only DLLs. But before learning how to create the TRichEdit descendant, let's see how to create resource-only DLLs (without using the IDE).

Creating the Resource-Only DLL

Since we're going to create and compile the DLL without using the IDE, you should first create a new project directory and two subdirectories called Data and Bin. The Data subdirectory will be used to store rich text documents, and Bin will be used as the destination directory for the compiled resource file and the DLL. These additional subdirectories are by no means a necessity, but they can help you keep data, code, and binary files separated and more manageable.

Now that the directories are done, create a rich text document (see Figure 25-6) in WordPad (or any other application that can save .rtf documents) and save the document to the Data subdirectory under the name image from book SampleDoc.rtf.

image from book
Figure 25-6: The sample rich text document

Now we have to create the .rc file in order to compile the rich text document into a .res file that can be linked into the DLL. Open Notepad (or any other application that saves plain text files) and write the following:

SAMPLE_DOCUMENT RCDATA "Data\SampleDoc.rtf"

The above line defines a custom resource called SAMPLE_DOCUMENT. The RCDATA statement is used to add any type of data to a resource file. The last part tells the resource compiler to use the image from book SampleDoc.rtf file from the Data subdirectory. Since you're telling the resource compiler that the image from book SampleDoc.rtf document is in the Data subdirectory, you must save this text document in the project's root directory. Save the text document as image from book Data.rc.

Now, let's create the main project file for the DLL. Again, open Notepad and then write the following:

library ResLib; {$R Data.res} begin end.

The above code is actually the entire DLL! The reason this DLL is called a resource-only DLL is now obvious: There's no code in it.

Before creating the batch file that will compile both the resource file and the DLL, you have to save the DLL to the root directory of the project under image from book ResLib.dpr.

The only thing left to do is create the batch file that will compile the resource file and the DLL. Open Notepad one last time, write the statements that follow, and save the file in the project's root directory under image from book Compile.bat:

@brcc32 -foBin\Data.res Data.rc @dcc32 ResLib.dpr -RBin -EBin @PAUSE

The first line in the image from book Compile.bat file calls the resource compiler. The -fo option is used to tell the resource compiler where to put the output file and how to name it. In this case, the resource compiler is told to create the image from book Data.res file in the Bin subdirectory. The image from book Data.rc part tells the compiler that the image from book Data.rc file contains the statements that specify which resources should be compiled into the image from book Data.res file.

The second line calls the Delphi for Win32 compiler (dcc32.exe). The first part of the line after @dcc32 identifies which project file should be compiled. The -RBin option tells the compiler that the project's resources reside in the Bin directory (the image from book Data.res file compiled by the previous line). The -EBin option tells the compiler to place the final EXE or DLL in the Bin directory.

Finally, the @PAUSE statement, which is a standard batch file statement, is used to keep the console window visible until we close it manually (see Figure 25-7). You shouldn't remove this line because it enables you to view compilation errors, if any occur.

image from book
Figure 25-7: Running Compile.bat

Creating the TResRichEdit Component

To create the TResRichEdit component, go back to the Delphi IDE and then do the following:

  1. Open the package you created in the last chapter (or create a new one, whichever suits you better).

  2. Select Component ® New VCL Component to display the New VCL Component dialog box.

  3. Select TRichEdit as the ancestor component.

  4. Save the TResRichEdit component in the package's directory under image from book ResRichEdit.pas.

  5. Proceed to the final step and add the new component to the opened package.

To enable the TResRichEdit component to load rich text documents from any DLL we create, we have to create a public method that accepts two constant string parameters: the name of the DLL and the name of the resource we want to load.

procedure LoadLibrary(const LibraryName, ResourceName: string);

The best way to load a resource-only DLL is by using the LoadLibraryEx API function. To use this function, you must add the Windows unit to the component's uses list.

Here's the declaration of the LoadLibraryEx function:

function LoadLibraryEx(lpLibFileName: PChar;    hFile: THandle; dwFlags: DWORD): HMODULE; stdcall;

When you pass the LOAD_LIBRARY_AS_DATAFILE constant as the dwFlags parameter, the LoadLibraryEx function simply sucks the DLL into memory, without executing additional code that usually gets executed for normal DLLs.

DLLs loaded with the LoadLibraryEx function must be released from memory with a call to FreeLibrary, like DLLs loaded using the LoadLibrary function.

After we load the resource-only DLL into memory, we have to load the resource into the TRichEdit component. Since there's no way the TRichEdit component can load a rich text document stored as a resource in a dynamic link library, we have to extract the rich text resource from the DLL into something the TRichEdit component can use — a memory stream.

Delphi has a specialized stream class that can be used to load resources into memory: the TResourceStream class. The constructor of the TResourceStream class is all that we have to call:

constructor Create(Instance: THandle; const ResName: string; ResType: PChar);

To load resources from the DLL, pass the DLL's handle (returned by the LoadLibraryEx function) as the Instance parameter. ResName is obviously the name of the resource we wish to load. Finally, we must pass the resource type as the ResType parameter. The Windows unit contains several RT_ constants that can be passed, but since we're using rich text documents, which are custom RCDATA resources, we have to use the RT_RCDATA constant.

After the TResourceStream loads the rich text document from the DLL into memory, the TRichEdit component can load the data from the stream using the LoadFromStream method. The following listing shows the entire LoadLibrary method.

Listing 25-2: The LoadLibrary method for loading rich text documents from a DLL

image from book
procedure TResRichEdit.LoadLibrary(const LibraryName, ResourceName: string); var   LibraryHandle: THandle;   ResourceStream: TResourceStream; begin   LibraryHandle := LoadLibraryEx(Pointer(LibraryName),     0, LOAD_LIBRARY_AS_DATAFILE);   try     ResourceStream := TResourceStream.Create(LibraryHandle,       ResourceName, RT_RCDATA);     try       Lines.LoadFromStream(ResourceStream);     finally       ResourceStream.Free;     end;         // try..finally   finally     FreeLibrary(LibraryHandle);   end;          // try..finally end;
image from book

To test the new component, make sure the component is registered by right-clicking the package and selecting Install. Then add a new VCL Forms application project to the project group and drop the TResRichEdit component and a button on the Designer Surface.

image from book
Figure 25-8: The TResRichEdit component

To load the sample document from the DLL we created earlier, you need to do two things:

  1. Copy image from book ResLib.dll from the Bin subdirectory to the root directory of this test application (to avoid having to specify a path or use the TOpenDialog component to locate the DLL).

  2. Call the LoadLibrary method of the component to load the SAMPLE_DOCUMENT resource from the image from book ResLib.dll.

Here's the code that you have to write to make things work:

procedure TForm1.Button1Click(Sender: TObject); begin   ResRichEdit1.LoadLibrary('ResLib.dll', 'SAMPLE_DOCUMENT'); end;

The result of using the LoadLibrary method to load a rich text document into the component is displayed in Figure 25-9.

image from book
Figure 25-9: Loading the sample document from the DLL

The last thing left to do is to create a second method that enables us to export documents from the DLL. This method is painfully similar to the LoadLibrary method. The only difference is that instead of calling TRichEdit.LoadFrom- Stream, we call the SaveToFile method of the TResourceStream class to write the contents of the memory stream to the disk. You can see the entire ExportResource method in the following listing.

Listing 25-3: The ExportResource method for exporting individual resources from the DLL to the disk

image from book
 procedure TResRichEdit.ExportResource(const LibraryName,   ResourceName, DestFileName: string); var   LibraryHandle: THandle;   ResourceStream: TResourceStream; begin   LibraryHandle := LoadLibraryEx(Pointer(LibraryName),     0, LOAD_LIBRARY_AS_DATAFILE);   try     ResourceStream := TResourceStream.Create(LibraryHandle,       ResourceName, RT_RCDATA);     try       ResourceStream.SaveToFile(DestFileName);     finally       ResourceStream.Free;     end;   finally     FreeLibrary(LibraryHandle);   end; end;
image from book



Inside Delphi 2006
Inside Delphi 2006 (Wordware Delphi Developers Library)
ISBN: 1598220039
EAN: 2147483647
Year: 2004
Pages: 212
Authors: Ivan Hladni

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net