Delphi allows not only to create applications but also DLL files. A DLL file (short for dynamic link library) is a special kind of executable that cannot be started by itself, but exports procedures and functions (called "Entry Points") for other executables to call.
how to use dll file in delphi
Delphi has got a special kind of project for a DLL file. To create one you use the File -> New -> Other menu entry to open a dialog where you can select the project type you want to create. There is one called "DLL Wizard"; that's the one we need here.
Now, this is getting rather technical and confusing: Programming languages have evolved over the years to pass parameters and return values from and to function calls in different ways. Originally that was only inside one language and using only one compiler so the programmer just wrote the code and the compiler took care of how the functions were called. Then came DLL files and all of a sudden code written in one language using one compiler could be called from other code written in a different language or maybe in the same language but using a different compiler. It turned out that this didn't work, so the compiler makers came up with the notion of calling conventions. We will use one called StdCall here since it allows for most other languages and compilers to call our DLL file.(One particular example is Visual Basic (from before .NET), which supports only the StdCall calling convention.)
Now, a DLL file is a binary file and if you e.g. load it into an editor, you will see lots of gibberish. But there are tools that can extract some more information about it, like Dependency Walker or the PE-Information Wizard in GExperts. If you open your DLL file with this wizard, it will tell you the following:
Usually you don't care much about memory management in your applications. That's what the compiler and runtime libraries are for, right? But in the case of DLL files you are interfacing potentially with other compilers and runtime libraries, so you have to think about it.
For example, Delphi automatically allocates and frees the memory for storing your strings, it knows when they are no longer needed, etc. The same applies for e.g. Visual Basic, but both do it in different ways. So, if you were to pass a string that was allocated by Visual Basic to a DLL file written in Delphi you would end up in big trouble, because both would now try to manage the string and would get into each other's hair.
So, in order to allow strings to be passed between an application and a DLL you must take extra care. Actually, the easiest way is just to not allow it at all! Now I can hear you thinking: "WTF is this guy talking about? Of course I want to pass strings from my application to the DLL file!"
I hope you also noticed that we declared our new function as StdCall again. You should never forget to explicitly add a calling convention. If you run into access violations when calling a DLL function, that's the first thing to check: Do your program and your DLL file both use the same calling conventions? If not, you found the problem.
In Delphi you are probably used to returning all sorts of data types as function results, e.g. strings or classes. When using DLL files, you should not do that. Only ever return simple data types like integer, double or single, otherwise you will most likely end up with a DLL file that you can only use from a Delphi application (and even that will be a major pain in the lower back to get to work). Again, this is a matter of memory management and different compilers / runtime libraries.
Array and Record alignments are another annoyance when passing parameters over DLL file boundaries. For performance reasons modern compilers arrange all data types to word- double-word- or even quad-word addresses. But if you don't know what the compilers on both sides actually use, you may get very peculiar effects. Delphi allows you to declare arrays and records as packed, meaning that no alignment takes place, but other programming languages or compilers may not have that concept. Delphi also allows you to force some alignment using the $A or $Align compiler directive, again, other programming languages or compilers may not give you that option. It's sometimes up to trial and error to find out how a structure is being passed to your program. Your best bet is usually to use data types on both sides that are multiples of 4 bytes long.
Just going back to the longish comment that Delphi automatically places into a new DLL file project. If your DLL file and your main program will both be Delphi programs (but are you sure that will always be the case?), you can take that advice and include the unit ShareMem as the first unit in the uses clause of both, the program and the DLL file. If you do that you can happily pass strings and other automatically memory managed data types between the program and the DLL file. But never ever should you pass objects! The reason is that even though you might use the same class declaration in both, the program and the DLL file, these objects are not the the same and they might divert from each other as your code evolves.
A recommendation for advanced users is to use a third-party memory manager called FastMM. It's good enough that Borland actually use it as the primary memory manager in Delphi 2006 and onwards. If you're using a version before that, then you can download it for free and use it on a project by project basis. A big benefit for DLL files is that when you're using FastMM, you can use standard String variables in your exported procedures and functions without needing to worry about ShareMem, or distributing anything else with your project or DLL files.
Writing DLL files in Delphi is simple and also powerful. If you are going to call these DLL files only from other Delphi applications, you might want to look into packages first. If you want to call Delphi code from other programming languages, you may want to look into COM servers (but be warned: While using COM servers from e.g. Visual Basic is very simple, it can be complex from other languages and can be a pain to have to register them every time before being able to call them).
Data files with the same file format as a DLL, but with different file extensions and possibly containing only resource sections, can be called resource DLLs. Examples of such DLLs include icon libraries, sometimes having the extension ICL, and font files, having the extensions FON and FOT.[1]
In a conventional non-shared static library, sections of code are simply added to the calling program when its executable is built at the "linking" phase; if two programs call the same routine, the routine is included in both the programs during the linking stage of the two. With dynamic linking, shared code is placed into a single, separate file. The programs that call this file are connected to it at run time, with the operating system (or, in the case of early versions of Windows, the OS-extension), performing the binding.
In Windows API, DLL files are organized into sections. Each section has its own set of attributes, such as being writable or read-only, executable (for code) or non-executable (for data), and so on.
The code in a DLL is usually shared among all the processes that use the DLL; that is, they occupy a single place in physical memory, and do not take up space in the page file. Windows does not use position-independent code for its DLLs; instead, the code undergoes relocation as it is loaded, fixing addresses for all its entry points at locations which are free in the memory space of the first process to load the DLL. In older versions of Windows, in which all running processes occupied a single common address space, a single copy of the DLL's code would always be sufficient for all the processes. However, in newer versions of Windows which use separate address spaces for each program, it is only possible to use the same relocated copy of the DLL in multiple programs if each program has the same virtual addresses free to accommodate the DLL's code. If some programs (or their combination of already-loaded DLLs) do not have those addresses free, then an additional physical copy of the DLL's code will need to be created, using a different set of relocated entry points. If the physical memory occupied by a code section is to be reclaimed, its contents are discarded, and later reloaded directly from the DLL file as necessary.
Like static libraries, import libraries for DLLs are noted by the .lib file extension. For example, kernel32.dll, the primary dynamic library for Windows's base functions such as file creation and memory management, is linked via kernel32.lib. The usual way to tell an import library from a proper static library is by size: the import library is much smaller as it only contains symbols referring to the actual DLL, to be processed at link-time. Both nevertheless are Unix ar format files.
Linking to dynamic libraries is usually handled by linking to an import library when building or linking to create an executable file. The created executable then contains an import address table (IAT) by which all DLL function calls are referenced (each referenced DLL function contains its own entry in the IAT). At run-time, the IAT is filled with appropriate addresses that point directly to a function in the separately loaded DLL.[3]
In Cygwin/MSYS and MinGW, import libraries are conventionally given the suffix .dll.a, combining both the Windows DLL suffix and the Unix ar suffix. The file format is similar, but the symbols used to mark the imports are different (_head_foo_dll vs __IMPORT_DESCRIPTOR_foo).[4] Although its GNU Binutils toolchain can generate import libraries and link to them, it is faster to link to the DLL directly.[5] An experimental tool in MinGW called genlib can be used to generate import libs with MSVC-style symbols.
Bound executables load somewhat faster if they are run in the same environment that they were compiled for, and exactly the same time if they are run in a different environment, so there is no drawback for binding the imports. For example, all the standard Windows applications are bound to the system DLLs of their respective Windows release. A good opportunity to bind an application's imports to its target environment is during the application's installation. This keeps the libraries "bound" until the next OS update. It does, however, change the checksum of the executable, so it is not something that can be done with signed programs, or programs that are managed by a configuration management tool that uses checksums (such as MD5 checksums) to manage file versions. As more recent Windows versions have moved away from having fixed addresses for every loaded library (for security reasons), the opportunity and value of binding an executable is decreasing. 2ff7e9595c
Comments