【问题标题】:How do you call a managed (C#) function from C++?如何从 C++ 调用托管 (C#) 函数?
【发布时间】:2009-09-24 06:11:22
【问题描述】:

我有一个 C# DLL 文件项目 (my_cs_dll.dll),它定义了一个带有静态成员函数的静态类。

namespace Foo
{
    public static class Bar
    {
        public static double GetNumber() { return 1.0; }
    }
}

我还有一个使用 /clr 的 C++ DLL 项目。

#using <my_cs_dll.dll>

double get_number_from_cs() { return Foo::Bar::GetNumber(); }

我在 C++ 项目的公共属性引用部分添加了对 'my_cs_dll.dll' 的引用(复制本地/复制依赖项均为 True)。

我还在 C++ 项目的 Configuration Properties C/C++ General 'Resolve#using References' 部分中添加了 'my_cs_dll.dll' 的路径。

一切都没有错误地构建,但是在运行时我不断收到来自系统的“System.IO.FileNotFound”异常,声称它找不到my_cs_dll.dll 程序集。

这两个 DLL 文件肯定存在于我正在运行的同一目录中。

我已经尝试了上述设置的各种变体,并阅读了我可以找到的关于托管/非托管互操作的所有内容,但我似乎无法理解问题所在...

我使用的是 Visual Studio 2008 和 .NET 3.5。

【问题讨论】:

    标签: c# c++ managed-c++


    【解决方案1】:

    听起来您的 C# 程序集在运行时没有被解析。您的 C# dll 是否与可执行文件位于同一目录(或子目录)?自从我这样做以来已经有一段时间了,但我的回忆是,除非您的程序集安装在 GAC 中,否则它必须位于可执行文件所在的目录(或子目录)中,而不是正在使用的 dll 的位置它。这与 .NET 安全功能有关。

    如果您仍然遇到问题,您可以尝试使用自己解决程序集。在启用 clr 的 C++ 项目中,尝试添加以下内容:

    using namespace System;
    using namespace System.Reflection;
    void Resolve()
    {
        AppDomain::CurrentDomain->AssemblyResolve +=
            gcnew ResolveEventHandler(OnAssemblyResolve);
    }
    Assembly ^OnAssemblyResolve(Object ^obj, ResolveEventArgs ^args)
    {
    #ifdef _DEBUG
        String ^path = gcnew String(_T("<path to your debug directory>"));
    #else
        String ^path = gcnew String(_T("<path to your release directory>"));
    #endif
        array<String^>^ assemblies =
            System::IO::Directory::GetFiles(path, _T("*.dll"));
        for (long ii = 0; ii < assemblies->Length; ii++) {
            AssemblyName ^name = AssemblyName::GetAssemblyName(assemblies[ii]);
            if (AssemblyName::ReferenceMatchesDefinition(gcnew AssemblyName(args->Name), name)) {
                return Assembly::Load(name);
            }
        }
        return nullptr;
    }
    

    您可能需要稍微调整一下代码才能使其在您的项目中编译。就我而言,我在启用 clr 的项目中创建了一个类的两个函数静态方法。只需确保在代码中尽早调用 Resolve() 函数,即在尝试调用 get_number_from_cs() 之前。

    虽然使用 COM 是一种选择,但它不是必需的。您目前的方法是正确的。如果你想要一些手把手,看看这个CodeProject example。这是我让我的非托管应用程序使用我的托管程序集的方法。

    【讨论】:

    • 嗨,马特,“它必须位于可执行文件所在的目录(或子目录)中,而不是使用它的 dll 的位置” dll 嵌套在下面的几个子目录中exe。将托管 dll 移动到与可执行文件相同的目录可以立即解决问题。谢谢!!
    • 好的,太好了。我的印象是,只要 dll 在可执行文件的子目录中,无论多深,程序集都会被解析。但正如我所说,我已经有一段时间没有看到这个了。
    • 我在从嵌入式资源加载 C# DLL 时使用了类似的代码。诀窍是将此代码放在不引用 C# DLL 的文件中。 .Net 程序集的延迟加载似乎是在进入包含对所讨论程序集的引用的编译单元(.cpp 文件)时发生的,而不是在实际调用引用的程序集时发生的,如果有的话。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    相关资源
    最近更新 更多