2012-10-15 9 views
5

Próbuję powiązać proste dll C++ przedstawione w http://msdn.microsoft.com/en-us/library/ms235636.aspx w mojej aplikacji konsoli C#, ale dostaję EntryPointNotFoundException dla Add wewnątrz dll w czasie wykonywania. Moja klasa testu to:EntryPointNotFoundException podczas wiązania biblioteki DLL języka C++ w C#

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

Co nie jest poprawne?

+0

możliwe duplikat: http://stackoverflow.com/questions/5877349/pinvoke-and-entrypointnotfoundexception – Star

+0

jadę do odgadnięcia, że ​​CallingConvention nie pasuje. Zakładam również, że MathFuncsDll.dll nie deklaruje metody o nazwie 'Dodaj' jako możliwej do eksportu. –

Odpowiedz

13

Można spróbować deklarowania funkcji poza klasą, a także eksportuje je 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); 
} 

Realizacja:

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

Telefoniczny kod:

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

Dzięki!Ale jeśli mam duże klasy, musiałbym zawrzeć wszystkie metody, których chcę użyć, prawda? – alex555

+0

Można je organizować w przestrzeniach nazw. Nie sądzę, aby można było wywoływać metody klasy C++ za pomocą P/Invoke, ponieważ P/Invoke został utworzony w celu wywołania dowolnego niezarządzanego kodu (w tym zwykłego C, w którym pojęcie klasy nie istnieje). Więc nadal możesz używać klas w kodzie niezarządzanym, ale tylko ujawniać funkcje, które musisz wywołać z zarządzanego kodu. –

5

W takich przypadkach można pobrać Dependency Walker, załadować bibliotekę DLL i wyświetlić listę funkcji eksportu. Możesz także użyć do tego celu DumpBin.

Domyślnie funkcja eksportowana z biblioteki DLL w C++ lub C używa Name Decoration (zwanej także Name Mangling).

Jak powiedział na MSDN: funkcja

A zdobiony imię dla C++ zawiera następujące informacje:

  • nazwa funkcji.
  • Klasa, której funkcją jest członek, jeśli jest to funkcja członka. Może to obejmować klasę, która otacza klasę funkcji i tak dalej.
  • Przestrzeń nazw, do której należy funkcja (jeśli jest częścią przestrzeni nazw).
  • Rodzaje parametrów funkcji.
  • Konwencja wywołująca.
  • Typ zwracanej funkcji.

Tak urządzone nazwę funkcji Add, na przykład, będzie wyglądać [email protected]@[email protected]@[email protected].

Ale możliwe jest wymuszenie na kompilatorze C++ ujawnienia nieokreślonych nazw dla funkcji C++ przez zamknięcie funkcji i wszelkich prototypów funkcji w bloku extern "C" {…}, jak zasugerował Darin Dimitrov.

Chociaż jeśli zamierzasz korzystać z biblioteki DLL innej firmy (nie możesz jej modyfikować) lub po prostu nie chcesz wystawiać ozdobionych nazw z jakiegoś powodu, możesz wyraźnie podać nazwę tej funkcji:

[DllImport("MathFuncsDll.dll", EntryPoint = "[email protected]@[email protected]@[email protected]")] 
public static extern double Add(double a, double b); 
+0

Użyłem dumpbina, ale nie wiedziałem, co z tym zrobić. Dzięki za dobrą radę z EntryPoint – alex555