PDA

View Full Version : help with dll stuff



tylerbingham
December 3rd, 2002, 08:13
I am coding a .dll. and I know how to use 1 .dll( you call a pragma commment(lib,"main.dll"), but I was wondering how to use 2 .dll's in a project...................sample code problem::

// dlluser.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "main.h"

char str[255];

int main(int nNumberofArgs, char* pszArgs[])
{

cout<<"which .dll do you want to load( 1 or 2 )"<< endl << endl;
cin>>str;

if(0 == strcmp ("2",str))
{
// #pragma comment(lib,"dll2.lib")
printMessage();
}

if(0 == strcmp ("1",str))
{
// #pragma comment(lib,"dll1.lib")
printMessage();
}

return 0;
}

this does NOT WORK!!!!, I want a way to pick which .dll loads.
Any help would be much appreciated.

p.s. I know you can't use the pragma directive this way, but I am all out of ideas!!

Doomulation
December 3rd, 2002, 11:15
You can use loadlibrary. It works perfecly with 2 or more dlls... :ermm: I never heard of this "pragma" thingie...you're using c++, right?


pLib = LoadLibrary("library.dll");

Azimer
December 3rd, 2002, 15:53
You are better off using LoadLibrary. Using #pragma is run at the preprocessor level. You can not change use a compile-time conditional with it.

Cyberman
December 3rd, 2002, 22:51
for loading multiple DLL's using LoadLibrary is the way. HOWEVER you need to include function pointers to the DLL resources in the DLL's.

use GetProcAddress() to get pointers to the functions in the DLL.
GetProcAddress returns a pointer to a type void..
You will need to type cast the pointer returned to your function pointers then you can use them as functions.

A few tips do not pass objects or such things to a DLL this is a sure fire path to disaster. Especially if you are using a different compilor than the what the DLL was made with.

Passing char pointers works great though.

Another thing. GetProcAddress() looks for the function specified only. I discovered microsoft does not adhere to it's own @#$#@#$ standards when I made a DLL with BCB. What does this mean? It means you have to be careful, for example

char *Get_GameList(void);
in BCB becomes _Get_GameList as a name but with VC++ it becomes Get_GameList although the BCB name is correct it doesn't work with any emulators because... they are expecting Get_GameList. What I did was wrap the GetProcAddress with a function that looks for both variations.

The best thing to do when using multiple libraries is have classes that wrap each DLL's set of functions and acess them via the classes. That seemed to be the easiest way to do it for me.

Cyb

tylerbingham
December 4th, 2002, 02:55
#include <iostream>
#include <windows.h>

#include "main.h"
#include "dlls\\main.h"
//#pragma comment(lib,"dll1.lib")
//#pragma comment(lib,"dll2.lib")

char str[255];
HINSTANCE lib;

typedef void ( * lpFunc1)(void);

lpFunc1 Func1;

int main(int nNumberofArgs, char* pszArgs[])
{

cout<<"which .dll do you want to load( 1 or 2 )"<< endl << endl;
cin>>str;

if(0 == strcmp ("1",str))
{
lib = LoadLibrary("dlls\\dll1.dll");
if(lib == NULL)
{
cout<<"failed to load .dll"<< endl<< endl;
}

if(lib != NULL)
{
cout<<"loaded .dll"<< endl<< endl;
}

Func1 = (lpFunc1) GetProcAddress(lib, "printMessage");
if (Func1 != NULL)
{
cout<<"loaded procedure :printMessage()";
}
else cout << "Error in procedure address call" << endl<< endl;

//printMessage();
}

if(0 == strcmp ("2",str))
{
//
}

return 0;
}
still not working..........maybe I built the .dll wrong??

Cyberman
December 4th, 2002, 04:00
Run IMPDEF <DLL NAME> <DLL NAME> on the DLL file and examine the contents of the resulting file.

You must also call FreeLibrary after you are done using the DLL.

Check to be sure the function names are in the DLL you just dumped and you are using the right name for the functions. See my comments about MS versus STANDARD function names :p

Cyb

tylerbingham
December 4th, 2002, 04:41
I got the 2 .dll's to load like I wanted, but I have to use a .def file to do it. Any ideas around that?? I am looking to load a .dll the way the emus hosted here do.

Cyberman
December 4th, 2002, 16:22
Originally posted by tylerbingham
I got the 2 .dll's to load like I wanted, but I have to use a .def file to do it. Any ideas around that?? I am looking to load a .dll the way the emus hosted here do.
Hmmm the Def file is just to find out what is in the DLL's and if there function names are exported properly etc.

My Code for DLL dealing:


//---------------------------------------------------------------------------
char *(*Game)(void);
char *(*Name)(void);
char *(*Author)(void);
void (*About)(void);
void (*Edit)(char *);
//---------------------------------------------------------------------------
int DLL_Count(void)
{
FncCalls[0]++;
return DLLCount;
}
//---------------------------------------------------------------------------
void *GetFnc(char *Fname)
{
void * Temp;
char Buff[256];

Temp = GetProcAddress(LibRef, Fname);
if (Temp == NULL)
{
strcpy(Buff, "_");
strcat(Buff, Fname);
Temp = GetProcAddress(LibRef, Buff);
}
return Temp;
}
//---------------------------------------------------------------------------
bool LoadFncs(void)
{
bool Return;
if (LibRef != NULL)
{
Game = (char * (*)(void)) GetFnc("MemEdit_Game");
Return = (Game != NULL);
if (Return)
{
Name = (char * (*)(void)) GetFnc("MemEdit_Name");
Return = (Name != NULL);
if (Return)
{
Author = (char * (*)(void)) GetFnc("MemEdit_Author");
Return = (Author != NULL);
if (Return)
{
About = (void (*)(void)) GetFnc("MemEdit_About");
Return = (About != NULL);
if (Return)
{
Edit = (void (*)(char *)) GetFnc("MemEdit_CardEdit");
Return = (Edit != NULL);
}
}
}
}
}
return Return;
}
//---------------------------------------------------------------------------
bool LoadLib(int GID)
{
if (LibRef != NULL)
{
// unload the prior library
FreeLibrary(LibRef);
// null it
LibRef = NULL;
}
if ((GID > 0) && (GID <= GameCount))
{
LibRef = LoadLibrary(DllPath[GameIDs[GID - 1].PathDX]);
}
if (LibRef != NULL)
{
if (!LoadFncs())
{
FreeLibrary(LibRef);
LibRef = NULL;
}
}
return (LibRef != NULL);
}


Granted it's fairly complicated however it has adequate error recovery etc.

I enumerate DLL's this way...



//---------------------------------------------------------------------------
void Game_Init(void)
{
char Path[300];
char Dir[256];
char Fname[64];
char Ext[8];
char Where[256];
char Plugin[300];
ffblk FFBLK;
int Length;
HINSTANCE LibRef;
char * (*GameID )(void);
char *PathPtr, *GID;

FncCalls[7]++;
for (DLLCount = 0; DLLCount < MAX_DLL; DLLCount++)
{
DllPath[DLLCount] = NULL;
}
for (DLLCount = 0; DLLCount < MAX_GAMES; DLLCount++)
{
GameIDs[DLLCount].ID = NULL;
GameIDs[DLLCount].PathDX = -1;
}
LibRef = NULL;
DLLCount = 0;
GameCount = 0;
Length = GetModuleFileName(NULL, Path, sizeof(Path));
if (Length)
{
_splitpath(Path, Where, Dir, Fname, Ext);
strcat(Where, Dir);
strcat(Where, "Plugins\\");
strcpy(Plugin, Where);
strcat(Plugin, "*.dll");
if (findfirst(Plugin, &FFBLK, 0) == 0)//FA_ARCH | FA_RDONLY) == 0)
{
PathPtr = DllPathD;
GID = GameIDD;
*PathPtr = 0;
*GID = 0;
do
{
strcpy(Plugin, Where);
strcat(Plugin, FFBLK.ff_name);
LibRef = LoadLibrary(Plugin);
if (LibRef != NULL)
{
GameID = (char *(*)(void))
GetFnc("MemEdit_Game");
if (GameID != NULL)
{
strcpy(PathPtr, Plugin);
DllPath[DLLCount] = PathPtr;
PathPtr += strlen(PathPtr) + 1;
strcpy(GID, GameID());
GameIDs[GameCount].ID = GID;
GameIDs[GameCount].PathDX = DLLCount;
GID += strlen(GID) + 1;
DLLCount ++;
GameCount ++;
}
FreeLibrary(LibRef);
}
}
while(
(findnext(&FFBLK) == 0) &&
(DLLCount < MAX_DLL)
);
}
}
// OK status
Status = 0;
// no game selected
GameSelected = -1;
}


You have to be rather therough and take into account things going wrong and errors that can happen. A common problem I have is the DLL doesn't load properly (sigh) and causes a memory fault.

Cyb

tylerbingham
December 6th, 2002, 04:14
hey, I finally got it last night!!! I was not exporting the .dll functions correctly. I got my .dll to load and do what it was supposed to do finally after a few hours of hacking through the msdn docs. I have just one more tiny question.....

You know how we use GetProcAddress to get the procedure(i.e. function address)?? is there a way to just search a .dll and find out all of the Procedures it can do without knowing what it's specific function names are?

Doomulation
December 6th, 2002, 12:14
Don't think there is...
Isn't that what the .def files are for...?
Correct me if i'm wrong.

Cyberman
December 6th, 2002, 21:50
Originally posted by tylerbingham
hey, I finally got it last night!!! I was not exporting the .dll functions correctly. I got my .dll to load and do what it was supposed to do finally after a few hours of hacking through the msdn docs. I have just one more tiny question.....

You know how we use GetProcAddress to get the procedure(i.e. function address)?? is there a way to just search a .dll and find out all of the Procedures it can do without knowing what it's specific function names are?
Where there must be a way to do it, however I am not sure how one would do that to be honest. IMPDEF would not be able to give you a list of exported functions otherwise (hmmm). I believe the way to do this might be knowing the format of MS's DLL files and just read through it, I don't think the WinApi supports searching for exported functions in a DLL without an actual name.

Another way to do this would be to call IMPDEF in a shell and directing the output to a file you read after IMPED is done executing.

Cyb

N-Rage
December 6th, 2002, 23:34
theres not much sense in enumerating functions from within a programm, you need information how to call those functions too( arguments and calling conventions ), and that aint stored within a DLL, it simply causes stack corruption if you assume it wrong.
What are you gonna do with functions You dont know anyway? :holiday:

You can however get functionpointers by ordinal numbers, ie get first, second, third, etc exported function of a dll, also by using GetProcAddress(), not using the function name as argument but a special construct( easy using a MACRO ).. cant remember how exactly, but everything is described in the PlatformSDK. You could simply get functionpointers aslong GetProcAddress() aint returning NULL.

Cyberman
December 6th, 2002, 23:50
Originally posted by N-Rage
theres not much sense in enumerating functions from within a programm, you need information how to call those functions too( arguments and calling conventions ), and that aint stored within a DLL, it simply causes stack corruption if you assume it wrong.
What are you gonna do with functions You dont know anyway? :holiday:

You can however get functionpointers by ordinal numbers, ie get first, second, third, etc exported function of a dll, also by using GetProcAddress(), not using the function name as argument but a special construct( easy using a MACRO ).. cant remember how exactly, but everything is described in the PlatformSDK. You could simply get functionpointers aslong GetProcAddress() aint returning NULL.

Actually you just do


Index = 0;
do
{
Ptr = GetProceAddress((char *)Index);
Index++;
}
while (Ptr != NULL);


unfortunately that doesn't get you the function NAMES :p

Cyb

N-Rage
December 7th, 2002, 16:03
Originally posted by Cyberman
Actually you just do


Index = 0;
do
{
Ptr = GetProceAddress((char *)Index);
Index++;
}
while (Ptr != NULL);


unfortunately that doesn't get you the function NAMES :p

Cyb

Theres no way to do that in runtime without RAW-parsing the dll... I dont think thats what he wanted anyway... actually i aint having a clue what he wants to do :)
if you have the MS-Compiler you can run dumpbin <dllname> /exports for a list of exported functions.