创建一个C++ DLL并在C#中使用它

4

我想制作一个C++ DLL,然后在C#应用程序中调用和引用它。我已经按照许多指南制作了一个简单的dll,但是当我尝试在C#应用程序中引用它时,我会收到以下错误:

无法加载 DLL 'SDES.dll':找不到指定的模块。

程序的代码如下(请耐心等待,我将包含所有文件)

//These are the DLL Files.

#ifndef TestDLL_H
#define TestDLL_H

    extern "C"
    {
        // Returns a + b
        __declspec(dllexport) double Add(double a, double b);

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

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

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

#endif

//.cpp
#include "test.h"

#include <stdexcept>

using namespace std;

    extern double __cdecl Add(double a, double b)
    {
        return a + b;
    }

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

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

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

        return a / b;
    }

//C# Program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("SDES.dll")]
        public static extern double Add(double a, double b);
        static void Main(string[] args)
        {
            Add(1, 2); //Error here...
        }
    }
}

你们有任何想法,我在程序中可能缺失了些什么?如果我遗漏了某些代码或者您有任何问题,请告诉我。

5个回答

5
请下载 Dependency Walker 工具并打开你的 SDES.dll。检查所有依赖的 DLL 是否可以加载。如果发现缺失的依赖项,也将其 DLL 放入目标目录中。
您使用的是 64 位系统吗?如果是,请将 C# 和 C++ 目标架构设为相同的(均为 32 位或均为 64 位)。
我刚测试了您的函数,效果不错。
    [DllImport("Native_CPP.dll", CallingConvention=CallingConvention.Cdecl)]
    public static extern double Add(double a, double b); 

    static void Main(string[] args)
    {
        Console.WriteLine(Add(1.0, 3.0));

        Console.ReadLine();
    }

输出:

4

这是我在Visual Studio 2010中的操作步骤:
  • 创建一个新解决方案

  • 创建一个新的C#项目

  • 创建一个新的C++-Dll项目(不需要MFC和其他内容)

  • 复制粘贴您的头文件和cpp文件

  • 构建C++-Dll

  • 将DLL复制到您的C#项目的Debug/Release目录下(具体取决于您使用的是哪个版本,通常为“Solution/CSharpProjectName/bin/Debug/”或“Solution/CSharpProjectName/bin/Release/”)

  • 将以下P/Invoke签名添加到C#文件中:

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

    注意:我必须传递参数CallingConvention.Cdecl,否则会出现异常。

  • 按照上面所示运行C#项目

P.S:我不需要设置架构。它只是起作用了。(我使用的是64位机器,带有64位操作系统。)


好的...你所说的“项目解决方案”,是指与SDES.dll相同的目录吗?然而,依赖项检查器不应再有任何投诉。 - Simon
是的。我很抱歉没有说得更具体。 - Major
我的笔记本电脑(我用来设计程序的系统)是64位的。我同时有目标为任意CPU的选项。你认为将目标切换为具体的64位会改变我面临问题的性质吗? - Major
我曾经遇到过这个问题,但是我得到了一个BadFileFormatException。然而,本地项目默认针对32位(即使在64位系统上)。如果您尝试从64位(=“Any CPU”在64位系统上)程序集加载32位DLL,则会导致应用程序崩溃。请尝试通过在C#项目中设置32位来同时针对32位。 - Simon
1
MSVCRT90.dll是C++运行时库,很可能被“throw new invalid_argument()”调用使用。要么将MSCVRT90.dll复制到C++ EXE旁边,并在清单文件中指定它,要么安装Visual C++ 2008可再发行组件,这将把MSVCRT90.dll放在Windows/System32/...中供需要的任何程序使用。 - JBRWilkinson
显示剩余4条评论

0

0
SDES.dll 放置在 C# .exe 所在的文件夹中。

我在命令行中运行了C#程序的.exe文件,只得到了相同的文本错误。 - Major

0

SimulateGameDLL 定义在哪里?我在 C/C++ 代码中没有看到它。


感谢您指出这一点,Leppie。我尝试了不同的教程,忘记改回来了。我已经编辑了我的原始帖子以反映它应该是什么,但我仍然遇到了相同的问题。至于将dll放在与.exe相同的文件夹中,我已经这样做了,但我仍然遇到了相同的问题。 - Major

0

我刚编译了代码,没有出现错误。这是我的命令行。

> cl /LD test.cpp -o SDES.dll
> csc test.cs
> test.exe

你是使用命令控制台,还是将此添加到项目属性中的? - Major
我刚刚使用了像上面展示的命令行。如果您正在使用VS,您可能已启用了过多的选项 :) - leppie
很可能。当我在命令提示符中尝试运行cl /LD test.cpp -o SDES.dll命令时,会出现错误消息,指出它无法识别cl命令。 我是否缺少扩展名? - Major
从开始菜单中运行“Visual Studio命令工具”之类的东西,以获取带有VC的命令行环境。 - Yin Zhu
谢谢 Yin。我运行了这些命令,第一个命令(cl /LD test.cpp -o SDES.dll)导致以下警告:cl : 命令行警告 D9002:忽略未知选项“-0” cl : 命令行警告 D9024:无法识别的源文件类型“SDES.dll”,假定为对象文件 test.cpp c1xx:致命错误 C1083:无法打开源文件:“test.cpp”:没有那个文件或目录 - Major

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接