DLLs: An Overview A dynamic-link library (DLL) is an executable file that acts as a shared library of functions. Dynamic linking provides a way for a process to call a function that is not part of its executable code. The executable code for the function is located in a DLL, which contains one or more functions that are compiled, linked, and stored separately from the processes that use them. DLLs also facilitate the sharing of data and resources. Multiple applications can simultaneously access the contents of a single copy of a DLL in memory. This code can be called from a PowerBuilder program even though it is written in another language such as C/C++, Pascal or in any other language that supports the pascal, WINAPI macro calling sequence for 16-bit and the standard calling sequence for 32-bit. Dynamic linking differs from static linking in that it allows an executable module (either a .DLL or .EXE file) to include only the information needed at run time to locate the executable code for a DLL function. In static linking, the linker gets all the referenced functions from the static link library and places it with your code into your executable. Using DLLs instead of static link libraries makes the size of the executable file smaller. If several applications use the same DLL, this can be a big savings in disk space and memory. A .DLL file has a layout very similar to an .EXE file, with one important difference - a DLL file contains an exports table. The exports table contains the name of every function that the DLL exports to other executables. These functions are the entry points into the DLL; only the functions in the exports table can be accessed by other executables. Any other functions in the DLL are private to the DLL. You can export functions from a DLL with two methods: 1) Create a module definition (.DEF) file and use the .DEF file when building the DLL. 2) Use the keyword __declspec(dllexport) in the function's definition. When exporting functions with either method, make sure to use the __stdcall calling convention. The __stdcall calling convention is used to call Win32 API functions. __stdcall pushes parameters on the stack, in reverse order (right to left) Functions that use this calling convention require a function prototype. The following list shows the implementation of this calling convention. Element Implementation Argument-passing order Right to left. Argument-passing convention By value, unless a pointer or reference type is passed. Stack-maintenance responsibility Called function pops its own arguments from the stack. Name-decoration convention An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list. Therefore, the function declared as int func( int a, double b ) is decorated as follows: _func@12 Case-translation convention None Example In the following example, use of __stdcall results in all WINAPI function types being handled as a standard call: // Example of the __stdcall keyword #define WINAPI __stdcall Export from a DLL Using .DEF Files The most common methods for exporting a definition: 1.The __declspec(dllexport) keyword in the source code 2.An EXPORTS statement in a .DEF file You can export data, functions, classes, or class member functions from a DLL by using the __declspec(dllexport) keyword. If you use __declspec(dllexport), you do not need a .DEF file for exports. To export functions, the __declspec(dllexport) keyword must appear to the left of the calling-convention keyword, if a keyword is specified. For example: void __declspec(dllexport) __cdecl Function1(void); To export all the public data members and member functions in a class, the keyword must appear to the left of the class name as follows: class __declspec(dllexport) CExampleExport : public CObject { ... class definition ... }; When building your DLL, you typically create a header file that contains the function prototypes and/or classes you are exporting, and add the __declspec(dllexport) to the declarations in the header file. To make your code more readable, define a macro for __declspec(dllexport) and then use the macro with each symbol you are exporting: #define DllExport __declspec( dllexport ) Pros and Cons of Using __declspec(dllexport) Using __declspec(dllexport) is convenient because you do not have to worry about maintaining a .DEF file and obtaining the decorated names of the exported functions. However, you do not have control over the export ordinals that the compiler generates. This method is suitable if, for example, you are designing a DLL for use with an application that you control; if you rebuild the DLL with new exports, you will also have to rebuild the application. Exporting functions using .DEF file A module-definition (.DEF) file is a text file containing one or more module statements that describe various attributes of a DLL. If you are not using the __declspec(dllexport) keyword to export the DLL's functions, then the DLL requires a .DEF file. A minimal .DEF file must contain the following module-definition statements: The first statement in the file must be the LIBRARY statement. This statement identifies the .DEF file as belonging to a DLL. The LIBRARY statement is followed by the name of the DLL. The linker places this name in the DLL's import library. The EXPORTS statement lists the names and, optionally, the ordinal values of the functions exported by the DLL. You assign the function an ordinal value by following the function's name with an at sign (@) and a number. When you specify ordinal values, they must be in the range 1 through N, where N is the number of functions exported by the DLL. Although not required, typically a .DEF file also contains a DESCRIPTION statement that describes the purpose of the DLL. For example, a DLL that contains the code to implement a binary search tree might look like the following: LIBRARY BTREE DESCRIPTION "Implements a binary tree." EXPORTS Insert @1 Delete @2 Member @3 Min @4 If you are exporting functions in a C++ file, you will have to either place the decorated names in the .DEF file or define your exported functions with standard C linkage by using extern "C". If you need to place the decorated names in the .DEF file, you can obtain them by using the tool DUMPBIN or by using the linker switch /MAP. Note that the decorated names produced by the compiler are compiler specific. If you place the decorated names produced by the Visual C++ compiler into a .DEF file, applications that link to your DLL must also be built using the same version of Visual C++ so that the decorated names in the calling application match the exported names in the DLL's .DEF file. When building the DLL, the linker uses the .DEF file to create an export (.EXP) file and an import library (.LIB) file. The linker then uses the export file to build the .DLL file. Executables that implicitly link to the DLL link to the import library when they are built. Note : When porting DLL source code from Win16 to Win32, replace each instance of __export with __declspec(dllexport). Pros and Cons of Using .DEF Files Exporting functions in a .DEF file gives you control over what the export ordinals are. When you add additional exported functions to your DLL, you can assign them higher ordinal values (higher than any other exported function). When you do this, applications using implicit linking do not have to relink with the new import library that contains the new functions. This is very important, for example, if you are designing a third-party DLL for use by many applications. You can continue to enhance your DLL by adding additional functionality while at the same time ensuring that existing applications will continue to work properly with the new DLL. Another advantage to using a .DEF file is that you can export functions using the NONAME attribute, which places only the ordinal in the exports table in the DLL. For DLLs with a large number of exported functions, using the NONAME attribute can reduce the size of the DLL file. The major disadvantage of using .a DEF file is that if you are exporting functions in a C++ file, you will either have to place the decorated names in the .DEF file or define your exported functions with standard C linkage by using extern "C" to avoid the name decoration done by the compiler. If you need to place the decorated names in the .DEF file, you can obtain them by using the tool DUMPBIN or by using the link switch /MAP. Note that the decorated names produced by the compiler are compiler specific. To determine which method to use to export functions (a .DEF file or the __declspec(dllexport) keyword), answer the following questions: 1/ Will you be continuing to add additional exported functions? 2/ Who is using your DLL? For example, is it a third party DLL used by many executables that you cannot rebuild, or is the DLL used only by applications that you can easily rebuild? Writing a source code .C or .CPP file #include <windows.h> #include "first.h" long __declspec(dllexport) __stdcall foo3(long mylong1, long mylong2,long mylong3) { long calc; calc = (mylong1 + mylong2 + mylong3); return(calc); }; short __declspec(dllexport) __stdcall foo4(long arg1, long arg2) { short rtn; if (arg1 > arg2) rtn = 1; else rtn = 0; if (arg1 == arg2) rtn = 2; return(rtn); }; void __declspec(dllexport) __stdcall foo5(void * p_structure) { strFromPB * pb_struct; pb_struct = (strFromPB *) p_structure; pb_struct->val1 = pb_struct->val1 - 1; pb_struct->val2 = pb_struct->val2 + 1; } Header File //Includes functions declarations, variables and structures declaration and //initialization. long __declspec(dllexport) __stdcall foo3(long mylong1, long mylong2,long mylong3); short __declspec(dllexport) __stdcall foo4(long arg1, long arg2); void __declspec(dllexport) __stdcall foo5(void * strFromPB); typedef struct mystruct{ long val1; long val2; } strFromPB; .Def file //"Undecorates " functions names decorated by __stdcall LIBRARY first.dll EXPORTS foo3 = _foo3@12 EXPORTS foo4 = _foo4@8 EXPORTS foo5 = _foo5@4 In PowerBuilder Note: the name of the function used in the declaration section should be the same as exported function name. If the .DEF file was not included within the .DLL, the function will be exported decorated and has to be prototyped decorated as well. If you are using some third party DLLs and rae not sure how the function you are calling is exported, you can use Exported Function section of Quick View. //Prototype function call in Local or Global External Functions Declaration section: FUNCTION Int foo4( long arg1, long arg2) Library"d:/API CALLS/first.dll" FUNCTION Long foo3( long arg1, long arg2, long arg3)Library"d:/API CALLS/first.dll" SUBROUTINE foo5(ref mystruct struct2)LIBRARY"d:/API CALLS/first.dll" // Calling function foo4() Integer li_rtn Long ll_arg1, ll_arg2 ll_arg1 = Long(sle_arg1.text) ll_arg2 = Long(sle_arg2.text) li_rtn = foo4(ll_arg1, ll_arg2) st_result.text = String(li_rtn) //Calling function foo3() Long ll_arg1, ll_arg2, ll_arg3, ll_rtn ll_arg1 = Long(sle_arg1.text) ll_arg2 = Long(sle_arg2.text) ll_arg3 = Long(sle_arg3.text) ll_rtn = foo3(ll_arg1, ll_arg2, ll_arg3) st_result.text = String(ll_rtn) To call subroutine foo5(), which takes a structure by reference as a parameter, create a structure: mystruct val1 long val2 long //Calling subrutine foo5 from PowerBuilder mystruct pb_struct //Instanciate mystruct pb_struct.val1 = long(sle_3.text) pb_struct.val2 = long(sle_4.text) foo5(pb_struct) //Display results of subroutine calculations sle_3.text = string(pb_struct.val1) sle_4.text = string(pb_struct.val2) Setting the Byte Alignment on MSVC++ Microsoft compilers provides two methods to specify structure packing: a command-line option (/Zp) and a pragma (pack). When the compiler packs a structure, it aligns the elements of the structure on a 1-, 2-, or 4-byte boundary in memory. An application can use packing for indexing purposes or to decrease processor access time. Unless an application specifies a different value, the default structure packing value is two. The field size and packing value determine the amount of padding required before a field appears in the structure. The padding can change the offset of a particular member of the structure. The compiler calculates each offset of a structure member relative to zero (0). The compiler compares the size of each member to the packing value (which is also known as the alignment value). The compiler aligns the element on the boundary of the smaller of the field size and the packing value. Finally, the compiler can pad the entire structure to properly align arrays of structures. The compiler usually pads all structures to a multiple of the packing size. However, if the specified packing size is four, but the structure does not contain any element larger than 2 bytes, the structure is padded to a multiple of two. The structures are not packed to a multiple of the packing size whenever the structure does not contain any elements (or elements of arrays)that are equal to or greater than the packing size. For example, structs of just chars or arrays of chars are never padded. Powerbuilder favores when dlla are compiled with 1-byte alignment.
- Select the desired target from MSVC
- Right mouse click and select Settings
- Select the C/C++ tabpage
- Select Code Generation from the Category dropdown list
- Select desired byte alignment from the Struct Member Alignment dropdown list.
Glossary: Stack is a region of reserved memory, organized as a stack, in which programs temporarily store status data such as procedure and function call return addresses, passed parameters, and local variables. stack frame - or frame allocation. An area of memory set up whenever a function is called that temporarily holds the arguments to the function as well as any variables that are defined local to the function. There are two key characteristics of frame allocations. First, when a local variable is defined, enough space is allocated on the stack frame to hold the entire variable, even if it is a large array or data structure. Second, frame variables are automatically deleted when they go out of scope References: Technical Document 44474: External Function Calls; Technical Document 44538: Passing a 32-bit PowerBuilder structure to a 32-bit C DLL Created in Power++; |