Link to home
Start Free TrialLog in
Avatar of newton-allan
newton-allan

asked on

HowTo: LoadLibrary and GetProcAddress?

I'm trying to use up to 3 dll's in an vc6 application. On the end-user's system, not all the dll's will necessarily be installed. I'm using LoadLibrary so the program can proceed as long as at least one .dll is loaded.

My problem is that the project(s) seems setup such that I get a runtime error message if all three .dll's aren't available. Also, the _ASSERTE statement below for GetProcAddress is failing.

Here is a "stub" of the vc6 main.cpp

#include "FirstDll.h"
#include "SecondDll.h"
#include "ThirdDll.h"

void main(void)
{
   const char* pBuf;
   HINSTANCE hLibrary = ::LoadLibrary("FirstDll.dll");
   if (hLibrary == NULL) {
      printf("Unable to load FirstDll\n");
   }
   else {
      pBuf = FirstGetBuf(1);
      printf([%s]\n", pBuf);
      ::FreeLibrary(hLibrary);
   }
   hLibrary = ::LoadLibrary("SecondDll.dll");
   if (hLibrary == NULL) {
      printf("Unable to load SecondDll\n");
   }
   else {
      pBuf = SecondGetBuf(1);
      printf([%s]\n", pBuf);
      ::FreeLibrary(hLibrary);
   }
   hLibrary = ::LoadLibrary("ThirdDll.dll");
   if (hLibrary == NULL) {
      printf("Unable to load ThirdDll\n");
   }
   else {
      pBuf = ThirdGetBuf(1);
      printf([%s]\n", pBuf);
      ::FreeLibrary(hLibrary);
   }
/*
   typedef const char* const (CALLBACK* GET_PROC)(USHORT);
   GET_PROC pGetBuf;
   pGetBuf  = (GET_PROC)GetProcAddress(hLibrary, "ThirdGetBuf");
   _ASSERTE(pGetBuf != NULL);
   pBuf = pGetBuf((USHORT)1);
*/  
}

Note that the commented out statements don't work ... the _ASSERTE is raised because GetProcAddress isn't resolving the function FirstGetBuf.

Here is a stub of FirstDll.h as generated by the Vc6 wizard for Win32 Dynamic Link Library:
#ifdef FIRSTINDLL_EXPORTS
#define FIRSTINDLL_API __declspec(dllexport)
#else
#define FIRSTINDLL_API __declspec(dllimport)
#endif

// Exported function.
FIRSTINDLL_API const char* const FirstGetBuf(USHORT Num);

If SecondDll.dll isn't installed at run-time, I get the message:

"This application has failed to start because SecondDll.dll was not found. Re-installing the application may fix this problem."

What am I doing wrong? Do I have the main.dsp project and/or *Dll.dsp projects incorrectly setup to insist that the *Dll.dll files exists? Do I need to have .def files? Does having the statement:
  pBuf = FirstGetBuf(1);
cause the linker to insist on having FirstDll.dll be present? How to I get the GetProcAddress call to work?

Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

I think you have specified that the app is dependant on the three projects (one for each dll) when you built it.
Remove the dependancies before building.
Where your DLL files are located ??

Try to Copy the required DLL to your project folder and check..

-MAHESH
Avatar of newton-allan
newton-allan

ASKER

There are four independent projects. There are no subprojects.

I've got the main app dependent on FirstDll.h, FirstDll.lib, SecondDll.h, SecondDll.lib, ThirdDll.lib, and ThirdDll.lib. Without those, it won't compile.

In main.dsp, I don't see any references to FirstDll.dll, SecondDll.dll, or ThirdDll.dll.

I put main.exe, FirstDll.dll, SecondDll.dll, and ThirdDll.dll in the same directory, and it works fine. When I rename SecondDll.dll to _SecondDll.dll, then I get the runtime error message about missing SecondDll.dll

And I'm baffled why these statements cause the _ASSERTE to fail:
   typedef const char* const (CALLBACK* GET_PROC)(USHORT);
   GET_PROC pGetBuf;
   pGetBuf  = (GET_PROC)GetProcAddress(hLibrary, "FirstGetBuf");
   _ASSERTE(pGetBuf != NULL);

I've looked at several websites and books with Windows dll examples, and they all use a typedef like the above to have GetProcAddress to work. I speculate if I could figure out how to have GetProcAddress to work ok, I could get rid of the (First|Second|Third)Dll.lib references and the (First|Second|Third)Dll.h statements.

I guess this is a variation on "dll hell" :-(

ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
<I've got the main app dependent on FirstDll.h, FirstDll.lib, SecondDll.h, SecondDll.lib, ThirdDll.lib, and ThirdDll.lib. Without those, it won't compile.>

I can't see your project but it still sounds like what I said in my first comment - you have dependancies.  The way the app is compiled it EXPECTS ALL THREE dll's to be present and checks for them during startup, hence your crash.
> No, it's  probably a variation of "C++ name mangling hell" ;o)

I don't think so, because everything works ok with all three dll's are present. It runs fine. The problem is when one or more are missing.

> I can't see your project but it still sounds like what I said in my first comment - you have dependancies.  The way the app is compiled it EXPECTS ALL THREE dll's to be present and checks for them during startup, hence your crash.

I certainly agree, but I don't see ** how ** to remove the dependencies.  What am I doing or not doing that causes the app to insist that all three be present?
Here is a link to a vc6 project that has main and then three subprojects for the three .dll's
http://cleanspeech.sf.net/misc/EeLoadLib.zip
When you load the libraries dynamically, you shouldn't declare their functions with __declspec(dllimport) at all, because that's what makes the application _demand_ their presence (I think)! Even if that's not correct, I think the following should work:

1. remove the includes of the three "xxxDll.h" in main.cpp
2. Put the:
    typedef const char* const (CALLBACK* GET_PROC)(USHORT);
   in main.cpp before void main(void). Could also go other places.
3. Do:

  GET_PROC pGetBuf;
   pGetBuf  = (GET_PROC)GetProcAddress(hLibrary, "FirstGetBuf");
   _ASSERTE(pGetBuf != NULL);
 
when FirstDll is successfully loaded.

You haven't shown where you have tried putting the GetProcAddress in your code, but if it's in that spot where you have commented it out, it couldn't work with dynamic loading, because the library was never loaded (hLibrary == NULL) or already released (else...FreeLibrary)!
I forgot: I suspect you are linking with FirstDll.lib etc., you should remove that as well.
<I certainly agree, but I don't see ** how ** to remove the dependencies.  What am I doing or not doing that causes the app to insist that all three be present?>

Remove these from the project linking / external dependancies / whatever.  They should not appear anywhere in the settings of the project.  (From the dll's I think you still need to export them else no other app can get at them).

IF you only call the functions via a LoadLibrary method then it should compile.  Anywhere it doesn't is an indecation you are not using a LoadLibrary type approach.
I've tried a number of different things, and the core problem seems to be that the statement:
pGetBuf = GetProcAddress(hLibrary, "FirstGetBuf");
isn't working.

I'm obviously got something incorrectly setup in the FirstDll and/or the main project.
Show us how you are using it now...
> No, it's  probably a variation of "C++ name mangling hell" ;o)
> .... use extern "C" ...

Well, I've been able to get it working. I first changed the (First|Second|Third).cpp files to .c files to avoid the name mangling. That helped * A LOT *. Then I went back and removed the (First|Second|Third).lib references and used the extern "C" as part of the typedef's.

Working fine now. If SecondDll.dll is missing, that LoadLibrary calls fails appropriately, but the main.exe is able to start without SecondDll.dll being present.

Thanks.
You always have the possibility to split points (your app was dependant via the lib references).
I thought about that ... was in a hurry and didn't take the time to see just how to split points. I'll do a "placeholder" question for 100 points and let you have it.
https://www.experts-exchange.com/questions/21865981/Placeholder-quesiton-for-AA.html
Thankyou.