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.文件输入 ...
随机推荐
- 简约而不简单的Django
本文面向:有python基础,刚接触web框架的初学者. 环境:windows7 python3.5.1 pycharm专业版 Django 1.10版 pip3 一.Django简介 百度百 ...
- C# String.Format用法和格式说明
1.格式化货币(跟系统的环境有关,中文系统默认格式化人民币,英文系统格式化美元) string.Format("{0:C}",0.2) 结果为:¥0.20 (英文操作系统结果:$0 ...
- shell视频
本帖最后由 Shell_HAT 于 2014-04-18 16:51 编辑 尚观全套RHCE视频http://pan.baidu.com/s/1pJvzVR1 马哥网络班-中级视频内容http://p ...
- log优化
isLoggable(Level level) 包含计算的日志记录用isLoggable判断下. debug info warn error ,一般记录error, 但是其他里面的计算还是 ...
- HDU 2112 Today(Dijkstra+map)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2112 题目大意: 经过锦囊相助,海东集团终于度过了危机,从此,HDU的发展就一直顺风顺水,到了2050 ...
- CMS(Concurrent Mark-Sweep)垃圾回收器
http://www.iteye.com/topic/1119491 1.总体介绍: CMS(Concurrent Mark-Sweep)是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器.对于要 ...
- hexdump related.
hexdump format strings Tue 13 December 2005 In tips. Ian Wienand More from the "things you'd le ...
- iOS客户端学习之AES加密
数据加密在解密在软件开发过程中举足轻重的作用,可能有的公司在加密的时候有自己公司内部一套设计的算法,而在这方面不想浪费太大精力就可以去考虑使用第三方提供的加密算法,如AES加密算法,本篇内容介绍开源中 ...
- 【PAT】1009. 说反话 (20)
1009. 说反话 (20) 给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出. 输入格式:测试输入包含一个测试用例,在一行内给出总长度不超过80的字符串.字符串由若干单词和若干空格组成,其 ...
- HTML canvas fillText()与measureText()方法
HTML5 canvas fillText() 方法 实例 使用 fillText(),在画布上写文本 "你好!word!" 和 "我是w3c": JavaSc ...