RiskX
RiskX

Reputation: 591

Access violation exception when using a DLL function

I created a simple DLL as part of my C++ exercises, but I'm getting an access violation exception when invoking DLL function. Here is the DLL's header file(I doubt the CPP will be usefull here):

#pragma once

namespace MathFuncs
{
class MyMathFuncs
{
public:
    // Returns a + b
    static __declspec(dllexport) double Add(double a, double b);

    // Returns a - b
    static __declspec(dllexport) double Subtract(double a, double b);

    // Returns a * b
    static __declspec(dllexport) double Multiply(double a, double b);

    // Returns a / b
    // Throws DivideByZeroException if b is 0
    static __declspec(dllexport) double Divide(double a, double b);
};
}

And here is my main:

#include <iostream>
#include "windows.h"

using namespace std;

int main(void)
{
    double (__cdecl *MYPROC)(double,double);
    /* get handle to dll */
    HINSTANCE hGetProcIDDLL = LoadLibrary("DLLExample.dll"); 
if(hGetProcIDDLL == NULL)
    throw;
   /* get pointer to the function in the dll*/
    FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL,"Add"); 
    if(lpfnGetProcessID)
        throw;
    MYPROC = (double (__cdecl *)(double,double))lpfnGetProcessID;
    if(MYPROC)
        throw;

    double x = MYPROC(5.5,5);

    return 0;
}

Any suggestions? Thanks!

Upvotes: 1

Views: 9471

Answers (4)

Ian Hatch
Ian Hatch

Reputation: 1381

I think Access violation exception when using a DLL function is the correct answer but it's kind of hard to interpret - the problems I see are:

  1. The checks are backwards - if we fail to get a function pointer, we continue, and we only throw if we successfully get a function pointer.

  2. The member functions should be exported fine since the functions are static, but we fail to get a function pointer because the DLL doesn't export a function called "Add" - the actual name will be mangled and can be found in the .map file, if generated.

  3. Since we didn't find a function pointer, we're then casting NULL to the function pointer type and trying to call it, so that's where we get our access violation.

The code should be:

FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL,"**MangledAddFunctionName - see .map file**");
if(lpfnGetProcessID == NULL)
    throw;
MYPROC = (double (__cdecl *)(double,double))lpfnGetProcessID;
if(MYPROC == NULL)
    throw;

double x = MYPROC(5.5,5);

Upvotes: 0

moswald
moswald

Reputation: 11667

Your problem lies here:

FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL,"Add"); 
if(lpfnGetProcessID)  // <-- error!
    throw;
MYPROC = (double (__cdecl *)(double,double))lpfnGetProcessID;
if(MYPROC)  // <-- error!
    throw;

double x = MYPROC(5.5,5);

If lpfnGetProcessId has an address, you're throwing an exception. If not, you later try to call it (boom!).

You're going to want to decorate your functions with extern "C" to make sure they are exported as user-friendly names. This means they can't be inside a class:

namespace MathFuncs
{
   extern "C" __declspec(dllexport) double Add(double, double);
}

Upvotes: 3

Mr.C64
Mr.C64

Reputation: 42924

Are you sure that the method MathFuncs::MyMathFuncs::Add() is actually exported as simple "Add", like in your GetProcAddress call?

I suspect there is some form of C++ name mangling involved.

You may want to use DUMPBIN /EXPORTS from the command line to see the actual exported method name.

Moreover, if the return value of GetProcAddress is not NULL (see your if test), the function succeeds: why do you throw?

Note also that using your DLL would be simpler if you adjust your class header file in such a way to use it in both exports and imports, e.g.

#if defined(MATHFUNCS_EXPORT) // Inside DLL implementation
#define MATHFUNCS_API __declspec(dllexport)
#else   // Outside DLL
#define MATHFUNCS_API __declspec(dllimport)
#endif  // MATHFUNCS_EXPORT

class MyMathFuncs
{
public:

  static MATHFUNCS_API double Add(double a, double b);
  ...
};

In this way the client can just #include your header file (and link with corresponding .lib file), without using LoadLibrary/GetProcAddress.

Upvotes: 1

mah
mah

Reputation: 39797

Without code to your DLL, one can only speculate, and the naming you've chosen seems to change mid-stream, but it looks like you're doing the following:

1) load the dll and throw an exception if this fails... ok. 2) locate a function in the dll that seems to add two values together -- but you throw an exception if this succeeds? Since you're not throwing an exception, NULL was returned and thus you failed to locate the function. 3) Call the function -- which is at NULL and so you're going to fail here.

I suspect the problem is that you are not accounting for C++ name mangling. You can either change the function name in your call to GetProcAddress() to account for it correctly, or you can declare the function with extern "C" to remove mangling.

Upvotes: 2

Related Questions