Search code examples
c#pinvoke

About DllImport in C#


Possible Duplicate:
Visual C++ managed app: Unable to find an entry point named ‘Add’

I'm learning to use platform invoke in C#.I follow the tutorial on msdn:

It works perfectly with C++ to use the MathFuncsDll.dll.

When I use:

[DllImport("MathFuncsDll.dll")] 

in my C# code, a dll not found exception raised. Then I change it to:

[DllImport("C:\\...\\MathFuncsDll.dll")] 

then a entry point not found exception appears.

How can I fix these problems?

For clarification, here is my code: The C++ dll:

header file:

//MathFuncsDll.h

#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport) 
#else
#define MATHFUNCSDLL_API __declspec(dllimport) 
#endif

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);
    };
}

The .cpp file:

// MathFuncsDll.cpp
// compile with: /EHsc /LD

#include "MathFuncsDll.h"
#include <stdexcept>

using namespace std;

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

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

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

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

here is the C# app call the functions:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace CSharpConsole
{
    class Program
    {
        //[DllImport("MathDll.dll")]

        [DllImport(@"C:\Users\...\Debug\MathDll.dll")]
        public static extern double Add(double a, double b);
        static void Main(string[] args)
        {
            double a = 6.2;
            int b = 3;

            Console.WriteLine(Add(a,b));
        }
    }
}

I create a completely new solution for this, the first DllIport line still doesn't work.And the second line give entry point exception.


Solution

  • When you use

    [DllImport("MathFuncsDll.dll")]
    

    the system will look for the DLL in the DLL search path. The first place searched is the directory which contains your executable file. That's the best place to put your DLL.

    If you see "entry point not found" then that means simply that the entry point was not found.

    The article you link to does not use p/invoke to link to the C++ DLL. That article describes how to link to a native DLL from managed C++. So you appear to be doing something different from that since you are using C# and p/invoke. Unless you supply precise details of what you are doing, for example the code, it's hard to prescribe a remedy.


    OK, now you have added some code. That helps a lot.

    You should not use static methods for p/invoke exports. Remove the MyMathFuncs and have plain old C-style functions:

    extern "C" 
    {
    
        double __declspec(dllexport) Add(double a, double b)
        {
             return a + b;
        }
    }
    

    No need for a header file that declares those functions. Just a single .cpp file should get it done. The use of extern "C" stops your names from being mangled by the C++ compiler.

    If you need to inspect your DLL to see what it exports, use Dependency Walker.

    On the C# side use:

    [DllImport(@"...", CallingConvention=CallingConvention.Cdecl)]
    public static extern double Add(double a, double b);