如何从 C++ 调用托管 (C#) 函数?

发布于 2024-08-05 20:59:27 字数 798 浏览 6 评论 0原文

我有一个 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++ 项目配置属性 C/C++ 常规“Resolve#using References”部分中添加了 'my_cs_dll.dll' 的路径。

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

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

我已经尝试了上述设置的各种变化,并阅读了我能在托管/非托管互操作中找到的所有内容,但我似乎无法弄清楚出了什么问题......

我正在使用 Visual Studio 2008和.NET 3.5。

I have a C# DLL file project (my_cs_dll.dll) which defines a static class with a static member function.

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

I also have a C++ DLL project which is using /clr.

#using <my_cs_dll.dll>

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

I've added a reference to 'my_cs_dll.dll' in the C++ project Common Properties references section (copy local/copy dependencies are both True).

And I've also added the path to 'my_cs_dll.dll' in the C++ project Configuration Properties C/C++ General 'Resolve#using References' section.

Everything builds without error, however at runtime I keep getting a 'System.IO.FileNotFound' exception from the system claiming it can't find the my_cs_dll.dll assembly.

Both DLL files are definitely present in the same directory from which I'm running.

I have tried all sorts of variations on the settings mentioned above and read everything I could find on manged/unmanaged interop, but I can't seem to get my brain around what is wrong...

I'm using Visual Studio 2008 and .NET 3.5.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

撩心不撩汉 2024-08-12 20:59:27

听起来您的 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 示例。这是我遵循的一个让我的非托管应用程序使用我的托管程序集的方法。

It sounds like your C# assembly is not being resolved at runtime. Is your C# dll in the same directory as (or a subdirectory of) your executable? It's been a while since I did this, but my recollection is that unless your assembly is installed in the GAC, it must be in the directory (or a subdirectory) where your executable is located, as opposed to the location of the dll that's using it. This has to do with the .NET security features.

If you are still having problems, you can try using resolving the assembly yourself. In your clr-enabled C++ project, try adding the following:

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;
}

You may have to tweak the code a little bit to get it to compile in your project. In my case, I made the two functions static methods of a class in my clr-enabled project. Just make sure you call the Resolve() function early on in your code, i.e., before you try to call get_number_from_cs().

While using COM is an option, it is not necessary. You're on the right path with your current approach. If you want some hand-holding, take a look at this CodeProject example. It's the one I following to get my unmanaged application to use my managed assemblies.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文