Hyderabad Jobs Book Website FREE PowerBuilder Training I Love Hyderabad Hyderabad Colleges
Home Business Emails Hyderabad Classifieds Contact Us
7 Wonders of Hyderabad Web Hosting Yellow Pages Our Network

 
Webpowerbuilder.hyderabad-colleges.com

Advanced PowerBuilder

HomePrevious Lesson: Linking Libraries
Next Lesson: PowerBuilder and C++ Data Types

The Contents of a DLL

A DLL is an executable file. It contains the following functions: Entry, LibMain and Exit.

The Entry Function

Once the Windows loader has loaded a DLL into memory, it transfers execution to the DLL's entry-point function, which performs whatever initialization is necessary for the DLL to function properly. When you're developing a C++ class in PowerBuilder, Watcom C/C++ provides a DLL entry function called LibEntry, which is located at C:\Watc\Lib286\Win\LibEntry.obj.
The name of LibEntry.Obj will, of course, change depending on how you install PowerBuilder and the platform it's installed on.

LibEntry's most important task is to initialize the DLL's local heap if it has one. Without a local heap, the DLL can't use any of Windows' local memory management APIs. Once it has initialized the DLL's local heap, LibEntry usually calls a programmer-specified function to perform any additional initialization required by the DLL.

You may wonder why we call a programmer-specified function when we could just perform all initialization in LibEntry. The reason for this is that, for performance purposes, LibEntry is written in Assembly language. This means that any changes or additions to the LibEntry.obj have to be made in Assembly language and, as you are no doubt aware, it's easier to program in a high level language, such as C or C++, than in Assembly language.

So it's just easier to write the minimum code necessary in LibEntry using Assembly language and then call a function that can be written in a high-level language. Anyway, PowerBuilder releases you from all these tasks by providing the LibEntry.obj file which takes care of every thing related to initialization. LibEntry.obj is a run-time object file that is linked by the built-in C++ compiler at build time.

If this function fails, Windows unloads the DLL from memory. If all goes well, it calls LibMain.

The LibMain Function

LibMain is a programmer-supplied initialization function called by LibEntry. Since LibEntry performs initializations that are common to all DLLs, you can write your DLL-specific initialization in LibMain. And, as this is a separate function from LibEntry, you can write it in a high-level language instead of writing in Assembly language.

When writing C++ classes in PowerBuilder, Watcom C/C++ creates a file lmain.cpp. This file contains two functions: LibMain and WEP. You shouldn't modify these files unless you have a good understanding of C++ (really you shouldn't modify them at all).

 

/* This file is generated by PowerBuilder.
* You may modify it in any way you wish but do not remove
* Libmain and WEP. Without them you will be unable to link your DLL.
*/

#include <windows.h>
#include "pbdll.h"
int PB_EXPORT LibMain( HANDLE hmod, WORD dataseg, WORD heap, LPSTR cmdline)

{
 hmod = hmod; // these assignments generate no code
 dataseg = dataseg; // but prevent compiler warnings about
 heap = heap; // unreferenced variables
 cmdline = cmdline;
 return( 1 );
}

If LibMain returns false, Windows unloads the DLL from memory.
You should note that you can't have multiple instances of the same DLL in memory and that LibEntry and LibMain are only called once, no matter how many applications are sharing the same DLL. If you want to do additional initialization for each instance of your application, you should provide an exported function and call that function instead.

You might want to use LibMain to load resources such as bitmaps or icons, or else to create data structures that the DLL manages. Note, though, that you shouldn't write code in LibMain that depends on other DLLs having being loaded previously. This is because, when several DLLs need to be loaded at one time, Windows does not load them in any guaranteed order.

The Exit Function

WEP (Windows Exit procedure) is the last function of a DLL to be called before Windows unloads the DLL from memory. The purpose of WEP is to perform any cleanup that a DLL needs to do before it's unloaded. Each DLL's WEP is called only once. When a DLL's usage count drops to zero, the Windows loader calls the DLL's WEP and then unloads the DLL. The usage count for an implicitly loaded DLL will be zero when all instances of all applications that are currently using it exit. The following code lists the WEP code that is generated by Watcom C/C++ while you create a C++ class user object from PowerBuilder.
int PB_EXPORT WEP( int res )
{
  res = res;
  return( 1 );
}
In Windows 3.0 this function is required for all DLLs, but it's optional in Windows 3.1 and upwards.

Programmer-defined Functions

These are the functions in which you can actually implement the functionality you want-they're the real workhorses of the DLL.

When declaring functions within a DLL, you should follow certain conventions, as specified in the Windows SDK. For example, you need to use the ANSI keywords: _far, _pascal and _export.

The _FAR declaration helps Windows change the code segment of any program as required by the memory manager.

Note that the references to specific key words such as _FAR or _NEAR are not applicable in a 32-bit environment.

_PASCAL function calls are more efficient than C function calls as they leave the responsibility of managing parameters and the cleaning up of the stack to the called procedure. Under C function calls, the calling procedure has to take care of this. Thus, _PASCAL function calls eliminate any duplication of code, since there can be multiple instances of one procedure calling a single instance of another procedure. The _PASCAL calling convention stores each parameter on the stack in the order in which they are coded in the function call. The C convention places the parameters in the exact opposite order. The reason for the C convention difference, is that it allows for a variable number of parameters by ensuring that the first parameter is always at a fixed positive offset from the stack pointer (SP). The _PASCAL convention makes no such assurance, so if a parameter isn't passed, the addresses computed for those that are passed will be erroneous. In the case of PowerBuilder, your DLL must use the same convention as PowerBuilder itself in order for parameter data to be passed from the PowerBuilder program to your DLL. PowerBuilder requires that you use the _PASCAL calling convention due to the manner that this convention stores parameters on the stack.

The _EXPORT keyword tells the compiler which functions in the DLL should be made visible and accessible to the world outside. PowerBuilder's class library code generator provides the PB_EXPORT definition. This provides the correct calling sequence and keywords for all functions accessed by PowerBuilder.

There are two varieties of programmer-defined function that implement the functionality of DLLs: exported and non-exported.

Exported Functions

Exported functions define the programming interface of a DLL and are meant to be called by applications and other DLLs. They usually represent the highest abstraction level a DLL provides to its callers. To implement these high-level services, exported functions often call non-exported functions that perform the necessary operations to support their functionality.

You must declare exported functions as _far because they don't reside in the segments from which they are called. However, they may use any naming and parameter passing conventions that pass parameters on the stack. Two popular conventions are _pascal and _cdecl. You can't use conventions that pass parameters in the CPU's registers because prolog code uses the CPU's registers when the function is called. PowerBuilder uses the _pascal calling convention, since this convention avoids passing parameters in the CPU registers. Also note that exported functions that return floating-point values, or structures and objects larger than four bytes, must use the _pascal calling convention.

The header file pbdll.h consists of a macro as shown below:

#define PB_EXPORT __pascal __export

If you look at the LibMain listing that we gave earlier, you'll see that LibMain is declared as an exported function by placing PB_EXPORT before it. Similarly, when you declare a function in PowerBuilder for use in a C++ class, PowerBuilder includes pbdll.h in the #include section in the generated code and also places PB_EXPORT in the function declaration.

Non-exported (Internal) Functions

Internal functions can only be called by other functions within the same DLL; applications and other DLLs can't call them and don't need to be aware that they even exist.

Internal functions in DLLs can use any naming and parameter-passing conventions supported by your compiler. You declare these functions in the C++ code, not in the PowerScript.

Memory Models

Memory models limit the size of the program and data by describing the number of bytes used to address data and call functions in the program. A memory model consists of a code model and a data model. The PowerBuilder C++ class builder creates DLLs based on the large model, which means that it makes use of far pointers for code as well as data. It also means that all data and code segments include explicit segment and offset values. This model allows for code size up to the amount of available memory, but limits any single data item to the 64K barrier. As PowerBuilder uses the large memory model, any DLL that requires a reference to a value in the PowerBuilder heap must also be of this model.
HomePrevious Lesson: Linking Libraries
Next Lesson: PowerBuilder and C++ Data Types

Copyright © 1996 - 2006 HamaraShehar.com Pvt. Ltd. All Rights Reserved.
Domain Registration, Website Design, Website Hosting by HamaraShehar.com