Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




Using a DLL

visual c en


Using a DLL

To use our newly developed DLL we just plug-in the older test program we had done for our static library. The interface is the same; nothing has changed from the user code of our library. The only thing that we must do differently is the link step, since now we do not need to add the resource file to our program.

Wedit leaves our DLL in the lcc directory under the project main directory. We just recompile our testdialog.c program that we had before. Here is the code for testdialog.c again:



extern int APIENTRY GetString(char *prompt,char *buffer,int len);

int main(int argc,char *argv[])

else printf("User cancelled\n");

return 0;

We compile this in the directory of the project, without bothering to create a project. Suppose that our project is in

h:\lcc\projects\dialog

and the dll is in

h:\lcc\projects\dialog\lcc

We compile with the command:

lcc testdialog.c

then we link with the command:

lcclnk testdialog.obj lcc\dialog.lib

Perfect! We now type the name of the program to test our dll.

testdialog

but instead of the execution of the program we see a dialog box like this:

The system tells us that it can't find the dll.

Well, if you reflect about this, this is quite normal. A DLL must be linked when the execution of the program starts. The system will search in the start directory of the program, and in all directories contained in the PATH environment variable. If it doesn't find a "dialog.dll" anywhere it will tell the user that it can't execute the program because a missing DLL, that's all.

The solution is to copy the DLL into the current directory, or copy the DLL in one of the directories in your PATH variable. Another solution of course is to go to the directory where the DLL is, and start execution of the program there.

This dependency on the DLL is quite disturbing. All programs that use the DLL in this fashion would need to have the DLL in their startup directory to be able to work at all.

A way to get rid of this is to avoid linking with the DLL import library. Yes you will say, but how will we use the DLL?

DLLs can be loaded into the program's address space with the API LoadLibrary. This API will do what the program loader does when loading a program that contains a reference to a DLL. If the load succeeds, the API will return us a handle to the library, if not, it will return us an INVALID_HANDLE as defined in windows.h.

After loading the DLL, we can get the address of any exported function within that DLL just by calling another windows API: GetProcAddress. This API receives a valid DLL handle, and a character string containing the name of the function to find, and will return an address that we can store in a function pointer.

Let's do this.

#include <windows.h>    (1)

#include <stdio.h>    (2)

int (APIENTRY *pfnGetString)(char *,char *,int); (3)

int main(int argc,char *argv[])

pfnGetString = (int (APIENTRY *)(char *,char *,int))

GetProcAddress(dllHandle,"_GetString@12"); (6)

if (pfnGetString == NULL)

if (pfnGetString(

"Enter a string",buffer,sizeof(buffer)))

else printf("User cancelled\n");

return 0;

We go step by step:

We need to include windows.h for getting the prototypes of LoadLibrary, and GetProcAddress, besides some constants like INVALID_HANDLE_VALUE.

stdio.h is necessary too, since we use fprintf

This is a function pointer called pfnGetString, that points to a function that returns an int and takes a char *, another char * and an int as arguments. If you do not like this syntax please bear with me. Even Dennis Ritchie says this syntax isn't really the best one.

We store in our dllHandle, the result of calling LoadLibrary with an absolute path so it will always work, at least in this machine. Note that the backslashes must be repeated within a character string.

We test if the handle received is a correct one. If not we put up some message and we exit the program.

We are now ready to assign our function pointer. We must cast the return value of GetProcAddress to a function like the one we want. The first part of the statement is just a cast, using the same construction that the declaration of the function pointer before, with the exception that we do not include the identifier of course, since this is a cast. But the arguments to GetProcAddress are weird. We do not pass really the name of the function GetString, but a name _GetString@12. Where does this name come from?

The rest of the program stays the same.

To understand where this weird name comes from, we have to keep in mind the following facts:

lcc-win32 like many other C compilers, adds always an underscore to the names it generates for the linker.

Since our function is declared as _stdcall, windows conventions require that we add to the name of the function the character '@' followed by the size of the function arguments. Since our function takes a char pointer (size 4) another char pointer, and an integer (size 4 too), we have 12 bytes of procedure arguments, hence the 12. Note that all types smaller than an integer will be automatically be promoted to integers when passing them to a function to keep the stack always aligned, so that we shouldn't just take the size of the arguments to make the addition. All of this can become really complicated if we have structures that are pushed by value into the stack, or other goodies.

The best thing would be that our DLL would export _GetString@12 as GetString. PERIOD.

Well, this is exactly where our dialog.def file comes handy. Here is a dialog.def that will solve our problem.

LIBRARY dialog

EXPORTS

_GetString@12=GetString

We have in the first line just the name of the DLL in a LIBRARY statement, and in the second line two names. The first one is the name as exported by the compiler, and the second one is the name as it should be visible from outside. By default, both are the same, but now we can separate them. With these instructions, the linker will put in the export table of the DLL the character string "GetString", instead of the compiler-generated name.

Once this technical problems solved, we see that our interface is much more flexible now. We could just return FALSE from our interface function if the DLL wasn't there, and thus disable some parts of the software, but we wouldn't be tied to any DLL. If the DLL isn't found, the functionality it should fulfill can't be present but nothing more, no catastrophes.



You can change this by pressing the corresponding button in the linker configuration tab, or by giving the argument -nounderscores to the linker, when building the DLL.

In the documentation of windows, you will find out that in the .def file you can write other kinds of statements. None of them are supported by lcc-win32 and are silently ignored since they are redundant with the command line arguments passed to the linker. Do not write anything else in the .def file besides the names of the exports.


Document Info


Accesari: 932
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2024 )