11

I try to bind a simple c++ dll shown in http://msdn.microsoft.com/en-us/library/ms235636.aspx in my c# console app, but I get a EntryPointNotFoundException for Add within dll at runtime. My test class is

namespace BindingCppDllExample
{
    public class BindingDllClass
    {
        [DllImport("MathFuncsDll.dll")]
        public static extern double Add(double a, double b);
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            double a = 2.3;
            double b = 3.8;
            double c = BindingDllClass.Add(a, b);

            Console.WriteLine(string.Format("{0} + {1} = {2}", a, b, c));
        }
    }
}

What is not correct?

alex555
  • 1,676
  • 4
  • 27
  • 45
  • possible duplicate: http://stackoverflow.com/questions/5877349/pinvoke-and-entrypointnotfoundexception – Alaa Jabre Oct 15 '12 at 09:05
  • I am going to guess that your CallingConvention does not match. I also assume that the MathFuncsDll.dll doesn't declare a method named `Add` as exportable. – Security Hound Oct 15 '12 at 12:11

2 Answers2

19

You could try declaring the functions outside of a class and also exporting them with extern "C":

Header:

// MathFuncsDll.h
namespace MathFuncs
{
    // Returns a + b
    extern "C" __declspec(dllexport) double Add(double a, double b);

    // Returns a - b
    extern "C" __declspec(dllexport) double Subtract(double a, double b);

    // Returns a * b
    extern "C" __declspec(dllexport) double Multiply(double a, double b);

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

Implementation:

// MyMathFuncs.cpp
#include "MathFuncsDll.h"
#include <stdexcept>

using namespace std;

namespace MathFuncs
{
    double Add(double a, double b)
    {
        return a + b;
    }

    double Subtract(double a, double b)
    {
        return a - b;
    }

    double Multiply(double a, double b)
    {
        return a * b;
    }

    double Divide(double a, double b)
    {
        if (b == 0)
        {
            throw new invalid_argument("b cannot be zero!");
        }

        return a / b;
    }
}

Calling code:

namespace BindingCppDllExample
{
    public class BindingDllClass
    {
        [DllImport("MathFuncsDll.dll")]
        public static extern double Add(double a, double b);
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            double a = 2.3;
            double b = 3.8;
            double c = BindingDllClass.Add(a, b);

            Console.WriteLine(string.Format("{0} + {1} = {2}", a, b, c));
        }
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thanks! But if I have large classes I would have to wrap all methods I want to use, isn't it? – alex555 Oct 15 '12 at 10:33
  • You could organize them in namespaces. I don't think that you could call C++ class methods using P/Invoke because P/Invoke was created to call any unmanaged code (including plain C in which the notion of a class doesn't exist). So you could still use classes in your unmanaged code but only expose the functions you need to be called from the managed code. – Darin Dimitrov Oct 15 '12 at 10:35
7

In cases such as this, you can download Dependency Walker, load your DLL into it and look at the Export Functions list. You can also use DumpBin for this.

By default, function exported from a C++ or C DLL are using Name Decoration (also called Name Mangling).

As said on MSDN:

A decorated name for a C++ function contains the following information:

  • The function name.
  • The class that the function is a member of, if it is a member function. This may include the class that encloses the function's class, and so on.
  • The namespace the function belongs to (if it is part of a namespace).
  • The types of the function's parameters.
  • The calling convention.
  • The return type of the function.

So decorated name for your Add function, for example, will look like Add@MyMathFuncs@MathFuncs@@SANNN@Z.

But it is possible to force the C++ compiler to expose undecorated names for C++ functions by enclosing the function, and any function prototypes, within an extern "C" {…} block, as Darin Dimitrov suggested.

Although if you're going to use a third-party DLL (so you can't modify it) or you just don't want to expose decorated names for some reason, you can specify the function's name explicitly:

[DllImport("MathFuncsDll.dll", EntryPoint = "Add@MyMathFuncs@MathFuncs@@SANNN@Z")]
public static extern double Add(double a, double b);
Nick Hill
  • 4,867
  • 3
  • 23
  • 29