Advanced Features of Delphi DLLs
http://www.delphisources.ru/pages/faq/master-delphi-7/content/LiB0104.html
Beside this introductory example, you can do a few extra things with dynamic libraries in Delphi. You can use some new compiler directives to affect the name of the library, you can call a DLL at run time, and you can place entire Delphi forms inside a dynamic library. These are the topics of the following sections.
Changing Project and Library Names
For a library, as for a standard application, you end up with a library name matching a Delphi project filename. Following a technique similar to that introduced in Kylix for compatibility with standard Linux naming conventions for shared object libraries (the Linux equivalent of Windows DLLs), Delphi 6 introduced special compiler directives you can use in libraries to determine their executable filename. Some of these directives make more sense in the Linux world than on Windows, but they've all been added anyway:
$LIBPREFIX is used to add something in front of the library name. Paralleling the Linux technique of adding lib in front of library names, this directive is used by Kylix to add bpl at the beginning of package names. It is necessary because Linux uses a single extension (.SO) for libraries, whereas in Windows you can have different library extensions, something Borland uses for packages (.BPL).
$LIBSUFFIX is used to add text after the library name and before the extension. This text can be used to specify versioning information or other variations on the library name and can be quite useful on Windows.
$LIBVERSION is used to add a version number after the extension—something very common in Linux, but that you should generally avoid on Windows.
These directives can be set in the IDE from the Application page of the Project Options dialog box, as you can see in Figure 10.3. As an example, consider the following directives, which generate a library calledMarcoNameTest60.dll:
library NameTest;
{$LIBPREFIX 'Marco'}
{$LIBSUFFIX '60'}
Calling a DLL Function at Run Time
Up to now, you've referenced in your code the functions exported by the libraries, so the DLLs were loaded along with the program. I mentioned earlier that you can also delay the loading of a DLL until the moment it is needed, so you can use the rest of the program in case the DLL is not available.
Dynamic loading of a DLL in Windows is accomplished by calling the LoadLibrary API function, which searches for the DLL in the program folder, in the folders on the path, and in some system folders. If the DLL is not found, Windows will show an error message, something you can skip by calling Delphi'sSafeLoadLibrary function. This function has the same effect as the API it encapsulates, but it suppresses the standard Windows error message and should be the preferred way to load libraries dynamically in Delphi.
If the library is found and loaded (something you know by checking the return value of LoadLibrary orSafeLoadLibrary), a program can call the GetProcAddress API function, which searches the DLL's exports table, looking for the name of the function passed as a parameter. If GetProcAddress finds a match, it returns a pointer to the requested procedure. Now you can cast this function pointer to the proper data type and call it.
Whichever loading functions you've used, don't forget to call FreeLibrary at the end, so that the DLL can be properly released from memory. In fact, the system uses a reference-counting technique for libraries, releasing them when each loading request has been followed by a freeing request.
The example I've built to show dynamic DLL loading is named DynaCall. It uses the FirstDLL library built earlier in this chapter (to make the program work, you have to copy the DLL from its source folder into the folder as the DynaCall example). Instead of declaring the Double and Triple functions and using them directly, this example obtains the same effect with somewhat more complex code. The advantage, however, is that the program will run even without the DLL. Also, if new compatible functions are added to the DLL, you won't have to revise the program's source code and recompile it to access those new functions. Here is the core code of the program:
type
TIntFunction = function (I: Integer): Integer; stdcall; const
DllName = 'Firstdll.dll'; procedure TForm1.Button1Click(Sender: TObject);
var
HInst: THandle;
FPointer: TFarProc;
MyFunct: TIntFunction;
begin
HInst := SafeLoadLibrary (DllName);
if HInst > then
try
FPointer := GetProcAddress (HInst,
PChar (Edit1.Text));
if FPointer <> nil then
begin
MyFunct := TIntFunction (FPointer);
SpinEdit1.Value := MyFunct (SpinEdit1.Value);
end
else
ShowMessage (Edit1.Text + ' DLL function not found');
finally
FreeLibrary (HInst);
end
else
ShowMes
As the library uses the Borland memory manager, the program dynamically loading it must do the same. So you need to add the ShareMem unit in the project of the DynaCall example. Oddly enough, this was not so with past versions of Delphi, in case the library didn't effectively use strings. Be warned that if you omit this inclusion, you'll get a harsh system error, which can even stall the debugger on the FreeLIrbary call.
How do you call a procedure in Delphi, once you have a pointer to it? One solution is to convert the pointer to a procedural type and then call the procedure using the procedural-type variable, as in the previous listing. Notice that the procedural type you define must be compatible with the definition of the procedure in the DLL. This is the Achilles' heel of this method—there is no actual check of the parameter types.
What is the advantage of this approach? In theory, you can use it to access any function of any DLL at any time. In practice, it is useful when you have different DLLs with compatible functions or a single DLL with several compatible functions, as in this case. You can call the Double and Triple methods by entering their names in the edit box. Now, if someone gives you a DLL with a new function receiving an integer as a parameter and returning an integer, you can call it by entering its name in the edit box. You don't even need to recompile the application.
With this code, the compiler and the linker ignore the existence of the DLL. When the program is loaded, the DLL is not loaded immediately. You might make the program even more flexible and let the user enter the name of the DLL to use. In some cases, this is a great advantage. A program may switch DLLs at run time, something the direct approach does not allow. Note that this approach to loading DLL functions is common in macro languages and is used by many visual programming environments.
Only a system based on a compiler and a linker, such as Delphi, can use the direct approach, which is generally more reliable and also a little faster. In my opinion, the indirect loading approach of the DynaCall example is useful only in special cases, but it can be extremely powerful. On the other hand, I see a lot of value in using dynamic loading for packages including forms, as you'll see toward the end of this chapter.
Placing Delphi Forms in a Library
Besides writing a library with functions and procedures, you can place a complete form built with Delphi into a dynamic library. This can be a dialog box or any other kind of form, and it can be used not only by other Delphi programs, but also by other development environments or macro languages with the ability to use dynamic link libraries. Once you've created a new library project, all you need to do is add one or more forms to the project and then write exported functions that will create and use those forms.
For example, a function activating a modal dialog box to select a color could be written like this:
function GetColor (Col: LongInt): LongInt; cdecl;
var
FormScroll: TFormScroll;
begin
// default value
Result := Col;
try
FormScroll := TFormScroll.Create (Application);
try
// initialize the data
FormScroll.SelectedColor := Col;
// show the form
if FormScroll.ShowModal = mrOK then
Result := FormScroll.SelectedColor;
finally
FormScroll.Free;
end;
except
on E: Exception do
MessageDlg ('Error in library: ' + E.Message, mtError, [mbOK], );
end;
end;
What makes this different from the code you generally write in a program is the use of exception handling:
A try/except block protects the whole function.
Any exception generated by the function will be trapped, and an appropriate message will be displayed.
You handle every possible exception because the calling application might be written in any language—
in particular, one that doesn't know how to handle exceptions.
Even when the caller is a Delphi program, it is sometimes helpful to use the same protective approach.A try/finally block protects the operations on the form,
ensuring that the form object will be properly destroyed even when an exception is raised.
By checking the return value of the ShowModal method, the program determines the result of the function.
I've set the default value before entering the try block to ensure that it will always be executed
(and also to avoid the compiler warning indicating that the result of the function might be undefined).
You can find this code snippet in the FormDLL and UseCol projects, available in the FormDLL folder.
(There's also a WORDCALL.TXT file showing how to call the routine from a Word macro.).
The example also shows that you can add a modeless form to the DLL, but doing so causes far too much trouble.
The modeless form and the main form are not synchronized,
because the DLL has its own global Application object in its own copy of the VCL.
This situation can be partially fixed by copying the Handle of the application's Application object
to the Handle of the library's Application object.
Not all of the problems are solved with the code that you can find in the example.
A better solution might be to compile the program and the library to use Delphi packages,
so that the VCL code and data won't be duplicated.
But this approach still causes a few troubles:
it's generally advised that you don't use Delphi DLLs and packages together.
So what is the best suggestion I can give you?
For making the forms of a library available to other Delphi programs, use packages instead of plain DLLs!
Advanced Features of Delphi DLLs的更多相关文章
- Language and Compiler Features Since Delphi 7
from: http://edn.embarcadero.com/cn/article/34324 Language and Compiler Features Since Delphi 7 In ...
- [Angular] Angular Advanced Features - ng-template , ng-container, ngTemplateOutlet
Previously we have tab-panel template defined like this: <ul class="tab-panel-buttons" ...
- [Python] Advanced features
Slicing 12345 L[:10:2] # [0, 2, 4, 6, 8]L[::5] # 所有数,每5个取一个# [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, ...
- Massive Collection Of Design Patterns, Frameworks, Components, And Language Features For Delphi
Developer beNative over on GitHub has a project called Concepts which is a massive collection of Del ...
- [转]Advanced Oracle SQL Developer Features
本文转自:http://www.oracle.com/technetwork/cn/server-storage/linux/sqldev-adv-otn-092384.html Advanced O ...
- 在delphi中嵌入脚本语言--(译)RemObjects Pascal Script使用说明(1)(译)
翻譯這篇文章源於我的一個通用工資計算平台的想法,在工資的計算中,不可避免的需要使用到自定義公式,然而對於自定義公式的實現,我自己想了一些,也在網上搜索了很多,解決辦法大致有以下幾種: 1. 自己寫代碼 ...
- Delphi XE5教程3:实例程序
内容源自Delphi XE5 UPDATE 2官方帮助<Delphi Reference>,本人水平有限,欢迎各位高人修正相关错误! 也欢迎各位加入到Delphi学习资料汉化中来,有兴趣者 ...
- delphi中DLL编程详解
10.1 Windows的动态链接库原理 动态链接库(DLLs)是从C语言函数库和Pascal库单元的概念发展而来的.所有的C语言标准库函数都存放在某一函数库中,同时用户也可以用LIB程序创建自己的函 ...
- File Input Features
文件输入功能 1.该插件将将一个简单的 HTML 文件输入转换为高级文件选取器控件.将有助于对不支持 JQuery 或 Javascript 的浏览器的正常 HTML 文件输入进行回退. 2.文件输入 ...
随机推荐
- 在ubuntu上安装Chrome
1.下载谷歌浏览器源文件.链接有很多,以下是64位版本的下载地址 https://dl.google.com/linux/direct/google-chrome-stable_current_amd ...
- python RSA加密解密及模拟登录cnblog
1.公开密钥加密 又称非对称加密,需要一对密钥,一个是私人密钥,另一个则是公开密钥.公钥加密的只能私钥解密,用于加密客户上传数据.私钥加密的数据,公钥可以解密,主要用于数字签名.详细介绍可参见维基百科 ...
- acm专题---最短路
spfa的时间复杂度是0(e) 题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1874 Problem Description 某省自从实行了很多年的畅 ...
- 最全Pycharm教程(26)——Pycharm搜索导航之文件名、符号名搜索(转)
1.准备一个工程 向你的工程中添加一个Python文件,并输入一些源码,例如: 2.转到对应文件.类.符号 Pycharm提供的一个很强力的功能就是能够根据名称跳转到任何文件.类.符号所在定义位置. ...
- SilverLight 浏览器出现滚动条
照网上说的很多解决方案要不得,最后想了下,直接在body上面加 style="overflow:hidden"解决问题,真觉得微软管理混乱,很多它自己的东西都不支持了.
- 5.rabbitmq 主题
1.生产者 #!/usr/bin/env python import pika import sys connection = pika.BlockingConnection(pika.Connect ...
- Linux 硬盘挂载方法
linux 硬盘分区,分区,删除分区,格式化,挂载,卸载笔记 硬盘挂载操作工作步骤: 1.先查看目前机器上有几块硬盘,查看命令有两种: 命令1:# fdisk –l 命令2:# dmesg | gre ...
- 四、ansible主机组定义
1.打开hosts文件 vim /etc/ansible/hosts 2.定义一个主机组 [web-server] 192.168.1.1 3.定义多个组(继承) [web:children] web ...
- kNN算法笔记
kNN算法笔记 标签(空格分隔): 机器学习 kNN是什么 kNN算法是k-NearestNeighbor算法,也就是k邻近算法.是监督学习的一种.所谓监督学习就是有训练数据,训练数据有label标好 ...
- 微信小程序-textarea中的文本读取以及换行问题
今天客户那边要求textarea中输入的问题可以按回车键换行,而我使用的是bindinput获取值,但是呢bindinput 处理函数的返回值并不会反映到 textarea 上,按回车键导致点击换行符 ...