困惑的DLL入口点(入口点未找到异常)

Gre*_*egD 9 c# c++ dll visual-studio-2010

我正在尝试学习如何在C#中使用DLL.我有一个非常简单的DLL只是为了测试基础知识.

// MainForm.cs


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;

namespace DLL_Test
{
        public partial class Form1 : Form
        {
            [DllImport("TestDLL.dll",
                        EntryPoint="?Add@@YGHHH@Z",
                        ExactSpelling = true,
                        CallingConvention = CallingConvention.StdCall)]
            public static extern int Add(int a, int b);

            public Form1()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                int num;
                try
                {
                    num = Add(2, 3);
                    richTextBox1.AppendText(num.ToString() + "\n");
                }
                catch (DllNotFoundException ex)
                {
                    MessageBox.Show(ex.ToString());
                }
                catch (EntryPointNotFoundException ex)
                {
                    MessageBox.Show(ex.ToString());
                }
             }
         }
}
Run Code Online (Sandbox Code Playgroud)

和DLL代码:

// TestDLL.cpp

__declspec(dllexport) int __stdcall Add(int a, int b) {
return(a + b);
}
Run Code Online (Sandbox Code Playgroud)

dumpbin返回以下内容:

ordinal   hint   RVA        name
      1      0   00011005   ?Add@@YGHHH@Z = @ILT+0(?Add@@YGHHH@Z)
Run Code Online (Sandbox Code Playgroud)

这(以及下面列出的其他尝试)都返回了相同的异常:

System.EntryPointException: Unable to find entry point named "..."
Run Code Online (Sandbox Code Playgroud)

所以我对如何解决这个问题感到茫然.也许我不明白DllMain如何作为DLL的C#入口点.TestDLL.dll在我在C++应用程序中测试时有效.

在寻求帮助后,我尝试了以下更改:

// TestDLL.cpp

extern "C" __declspec(dllexport) int __stdcall Add(int a, int b) {
return(a + b);
}
Run Code Online (Sandbox Code Playgroud)

这从dumpbin得到了这个

ordinal   hint   RVA        name
      1      0   00011005   _Add@8 = @ILT+135(_Add@8)
Run Code Online (Sandbox Code Playgroud)

因此,我改变了我的C#代码:

 // MainForm.cs

...

[DllImport("TestDLL.dll",
                        EntryPoint="_Add",
                        ExactSpelling = true,
                        CallingConvention = CallingConvention.StdCall)]
            public static extern int Add(int a, int b);

...
Run Code Online (Sandbox Code Playgroud)

我也尝试过__cdecl:

// TestDLL.cpp

extern "C" __declspec(dllexport) int __cdecl Add(int a, int b) {
return(a + b);
}
Run Code Online (Sandbox Code Playgroud)

.

// MainForm.cs

...

[DllImport("TestDLL.dll",
                        EntryPoint="_Add",
                        ExactSpelling = true,
                        CallingConvention = CallingConvention.Cdecl)]
            public static extern int Add(int a, int b);

...
Run Code Online (Sandbox Code Playgroud)

也许我误解了召唤惯例.任何帮助将非常感激.谢谢.

Ser*_*ier 17

使用

extern "C" __declspec(dllexport) int __stdcall Add(int a, int b) { ... }
Run Code Online (Sandbox Code Playgroud)

[DllImport("TestDLL.dll", CallingConvention = CallingConvention.Stdcall)] 
public static extern int Add(int a, int b); 
Run Code Online (Sandbox Code Playgroud)

extern "C"将使用params和返回类型来阻止名称修改?Add@@YGHHH@Z.__stdcall将_添加前缀并添加@8:( _Add@8其中8是参数的总大小).请注意,它还会影响参数在堆栈上的推送方式.

在您的DLLImport语句中,自指定后CallingConvention.StdCall,您无需指定名称mangling.只需给出常规名称(Add)和.NET将处理名称mangling(_Add@8).

请注意,您必须指定CallingConvention或.NET不会发出正确的代码来推送堆栈上的参数