GregD
GregD

Reputation: 195

Confused over DLL entry points (entry point not found exception)

I'm trying to learn how to use DLL's in C#. I have a very simple DLL just to test the basics.

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

And the DLL code:

// TestDLL.cpp

__declspec(dllexport) int __stdcall Add(int a, int b) {
return(a + b);
}

dumpbin returns the following:

ordinal   hint   RVA        name
      1      0   00011005   ?Add@@YGHHH@Z = @ILT+0(?Add@@YGHHH@Z)

This (and other attempts listed below) have all returned the same exception:

System.EntryPointException: Unable to find entry point named "..."

So I am at a loss for how to solve this. Perhaps I do not understand how DllMain functions as the C# entry point for a DLL. TestDLL.dll works when I test it in a C++ application.

After searching for help, I've attempted the following changes:

// TestDLL.cpp

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

Which results in this from dumpbin

ordinal   hint   RVA        name
      1      0   00011005   _Add@8 = @ILT+135(_Add@8)

Thus, I changed my C# code:

 // MainForm.cs

...

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

...

I've also tried __cdecl:

// TestDLL.cpp

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

.

// MainForm.cs

...

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

...

Perhaps I'm misunderstanding the calling conventions. Any help would be very appreciated. Thank you.

Upvotes: 9

Views: 36903

Answers (3)

volpif
volpif

Reputation: 1

For future reference: I had a similar problem, solved creating an EMPTY C++ dll project. Probably the standard Visual Studio template causes some trouble.

Refer to this link: http://www.codeproject.com/Articles/9826/How-to-create-a-DLL-library-in-C-and-then-use-it-w

Upvotes: 0

Serge Wautier
Serge Wautier

Reputation: 21898

use

extern "C" __declspec(dllexport) int __stdcall Add(int a, int b) { ... }

and

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

extern "C" will prevent name mangling with params and return type such as ?Add@@YGHHH@Z. __stdcall will prepend an _ and add @8 : _Add@8 (where 8 is the total size of arguments). Note that it also affects the way parameters are pushed on the stack.

In your DLLImport statement, since you specify CallingConvention.StdCall, you don't need to specify the name mangling. Just give the regular name (Add) and .NET will take care of name mangling (_Add@8).

Note that you must specify the CallingConvention or .NET wouldn't emit the correct code to push arguments on the stack

Upvotes: 18

Darin Dimitrov
Darin Dimitrov

Reputation: 1039408

The following should work.

Unmanged:

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

Managed:

class Program
{
    [DllImport("TestDLL.dll")]
    public static extern int Add(int a, int b);

    static void Main()
    {
        Console.WriteLine(Add(1, 2));
    }
}

Upvotes: 0

Related Questions