【问题标题】:Unable to use Custom .dll (C#) from C++/CLI无法从 C++/CLI 使用自定义 .dll (C#)
【发布时间】:2016-01-18 20:15:15
【问题描述】:

提前感谢您的时间和帮助。

目标:我正在尝试在 C++ 项目中使用我的 C# 库

我做了什么

  1. 用我的 C# 项目创建了一个简单的 .dll 文件。命名:ClassLibrary1.dll
  2. 创建了一个名为:CppClr(公共语言运行时支持更改为:/clr)的 C++ 控制台应用程序
  3. 将 ClassLibrary1.dll 复制到 CppClr 项目的根目录

以下是我的 ClassLibrary1(C#) 代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace ClassLibrary1
{
    public class Class1
    {
        public static void output()
        {

            String mystr; 


            mystr = "Helloo World"; // create a new string

            Console.WriteLine(mystr);
            Console.WriteLine("From C++ Managed Code!");
            Console.ReadLine();
        }
    }
}

以下是我的 C++/CLI 代码:

#include "CppClr.h"
#using <ClassLibrary1.dll>

int main()
{
    ClassLibrary1::Class1::output();
}

问题:我在运行 C++/CLI 代码时遇到的错误:

未知模块中发生“System.IO.FileNotFoundException”类型的未处理异常。附加信息:无法加载文件或程序集“ClassLibrary1,版本=1.0.0.0,Culture=neutral,PublicKeyToken=null”或其其中之一依赖关系。系统找不到指定的文件。

【问题讨论】:

  • 您需要将 .dll 包含到您的 C++ 项目中的任何项目引用中吗?
  • 我不知道你是什么意思...
  • 请看这里:social.msdn.microsoft.com/Forums/en-US/… 我不相信在根文件夹级别有 ​​.dll 就足够了。您的解决方案中应该有一种方法可以右键单击并包含引用 > 浏览 > 找到您的 .dll 并将其包含在您的解决方案中。
  • 解决方案建议我还需要在 .dll 文件中包含 .lib 文件。但是,当我创建 ClassLibrary1 时,它只生成了 ClassLibrary1.dll 和 ClassLibrary1.pdb,没有生成任何 .lib 文件。

标签: c# .net visual-studio dll c++-cli


【解决方案1】:

您的问题只是您的 C++ 可执行文件无法在运行时找到/加载 C# DLL 的问题。

.NET 运行时在几个不同的地方寻找加载程序集。其中最简单的是来自运行已编译应用程序的同一目录。在 C++ 项目的根目录中拥有 ClassLibrary1.dll 是不够的 - 它需要位于运行项目的同一目录中。

作为一个快速而肮脏的测试,您应该能够通过将ClassLibrary1.dll 复制到 C++ 项目的输出目录来验证这一点。如果您在调试配置中运行,这可能类似于C:\Projects\CppClr\Debug\ 或您的 C++ 项目所在的任何位置。验证这是包含已编译 CppClr.exe 文件的目录。将 DLL 复制到此处并运行项目后,运行时应该能够找到 DLL,并且一切正常。

但是,如果您经常更新 C# 项目,这可能会有点麻烦,因为每次发生更改时,您都需要不断地将其复制到 C++ 输出文件夹。解决方案是在 C++ 项目中将 reference 添加到您的 C# 库中。

在 Visual Studio 中,打开您的 C++ 项目。在解决方案资源管理器中,右键单击 references 并选择 Add reference... 接下来,单击 Browse... 按钮对话框底部并浏览到磁盘上ClassLibrary1.dll 的位置。点击添加,然后点击OK

现在,无论何时构建 C++ 项目,它都会将 ClassLibrary1.dll 程序集复制到项目的输出文件夹中。您还应该能够从 C++ 文件的顶部删除 #using &lt;ClassLibrary1.dll&gt; 指令,因为添加 DLL 作为项目引用应该执行相同的功能。

【讨论】:

  • 嗨,Ben,谢谢你的建议,我暂时无法测试它,因为它在我的工作计算机上,但我会在明天确认它是否有效。
  • 嗨,Ben,我已将我的 .dll 文件添加到 .exe 文件所在的文件夹中,但它仍然找不到。它给出了以下错误:error C1107: could not find assembly 'ClassLibrary1.dll': please specify the assembly search path using /AI or by setting the LIBPATH environment variable
  • 好吧,实际上现在您遇到了 compile time 错误,而之前您遇到了 runtime 错误。您的 C++ 项目根目录似乎已配置为程序集搜索路径的一部分。要解决此问题,请将ClassLibrary1.dll 的一份副本放在项目根目录中(就像以前一样)。这让 编译器 可以在代码中的 #using 指令的帮助下找到程序集。然后确保在运行时可执行文件的目录中有 second 副本。另一种方法是添加 C# 项目作为正确的参考,正如我在上面答案的第二部分中描述的那样。
【解决方案2】:

Chad 分享的 msdn 链接是你想添加从 C++ 项目创建的 dll 的情况。

您需要做的是为您的 C# 库创建一个强名称。

  • 要为您的类库创建强名称,请在 Visual Studio .NET 命令提示符处键入以下命令: sn.exe -k MyKeyFile.SNK

  • 将 MyKeyFile.SNK 文件复制到您的项目文件夹中。

  • 双击 AssemblyInfo.cs 文件以在解决方案资源管理器中打开该文件。
  • 替换 AssemblyInfo.cs 文件中的以下代码行

    [assembly: ComVisible(false)]
    [assembly: AssemblyDelaySign(false)]
    [assembly: AssemblyKeyFile("")]
    

    [assembly: ComVisible(true)] 
    [assembly: AssemblyDelaySign(false)] 
    [assembly: AssemblyKeyFile("..\\..\\MyKeyFile.SNK")]
  • 按 CTRL+SHIFT+B 生成托管 DLL。
  • 现在注册托管 DLL 以用于 COM 或 Native C++
  • 从本机 C++ 代码或使用它调用托管 DLL。

此处的链接与 OP 试图做的很接近。 https://support.microsoft.com/en-us/kb/828736

【讨论】:

  • 我的访问被拒绝sn.exe -k MyKeyFile.SNK。我想这需要以管理员身份运行?这是一台公司计算机,我没有管理员权限。还有其他方法吗?
  • 在这种情况下,您至少需要访问这个文件夹。我猜它是一个Windows 7系统。 "C:\Users\All Users\Microsoft\Crypto\RSA\MachineKeys" 这是默认密钥容器所在的位置,由 sn 工具使用。
  • 我确实可以访问该文件夹,但是当我运行上述命令时,我得到:Failed to create MyKeyFile.SNK -- Access Denied 我相信我无法在此文件夹中输出文件,有没有办法指定在哪里输出文件?
  • 我应该完全指定访问权限,我的意思是,检查您对该文件夹拥有哪些权限。右键单击 MachineKeys 文件夹->选择属性->转到安全选项卡,检查您的用户名是否属于具有读取和执行权限的组。如果您不这样做,请联系您拥有的任何 IT 帮助台,并要求他们为您提供对该文件夹的读取和执行权限。
  • 如果 C++ 项目按照原始问题中的说明使用 CLR 支持进行编译,则没有理由按照此答案的建议向 COM 注册 C# 库。我认为混淆源于标题声明“Native C++”这一事实,在这种情况下,COM 可能是一个解决方案。不过这绝对是Managed C++,应该可以直接加载一个C#.NET DLL。
【解决方案3】:

我可以通过指定dll文件的绝对路径来解决这个问题。

之前:

#using "ClassLibrary1.dll"

之后:

#using "C:\user\ClassLibrary1\ClassLibrary1\bin\Debug\ClassLibrary1.dll"

如果这对您有用,您需要转到 Properties -> C/C++ -> General -> "Resolve #using References" 并在此处添加路径。那么你可以在没有完整路径的情况下再次使用#using "ClassLibrary1.dll"

已找到答案here

【讨论】:

  • 将绝对路径放入已编译的二进制文件中并不是最佳做法。但如果您不关心可维护性,这是一条可行的路。
猜你喜欢
  • 2013-07-27
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
相关资源
最近更新 更多