C#中的“非托管导出”

11
我一直在尝试在Visual Studio 2010 Pro/C#项目中使用Robert Giesecke的扩展程序“Unmanaged Exports”,但无法使其正常工作 - 当我检查已编译的DLL以查看导出函数时,查看器(http://www.nirsoft.net/utils/dll_export_viewer.html)总是为空,似乎没有定义任何导出函数。
我已经几乎完全复制了示例,并将构建/配置管理器/活动平台设置为x86。我该如何检查执行所有操作的MSBuild任务是否实际运行?项目文件应包含什么内容(对我来说它似乎非常空)?

1
您也可以使用http://www.dependencywalker.com/来查看导出的函数。我之前使用过上述方法,但是如果没有更多信息,很难确定出现了什么问题。可能需要查看整个项目以调试出错的地方。 - Joel Lucsy
2个回答

25
我建议您按照文档的方式进行操作,而不要依赖于作者不提供支持的未经文档记录的 hack。我们可以通过以下示例来实现此操作:
namespace Publics {
    public class Class1 {
        public static void Run() { 
            // Stuff...
        }
    }
}

将一个新的C++/CLI类库添加到您的项目中。右键单击解决方案,选择“添加”,然后选择“新建项目”。打开“其他语言”节点,选择Visual C++、CLR,然后选择“类库”项目模板。右键单击新项目,选择“属性”,选择“常规属性”,再选择“框架和引用”,点击“添加新引用”按钮。在“项目”选项卡中,选择要导出方法的C#项目。
删除预生成的带有//TODO注释的空类,并编写以下代码:
extern "C" __declspec(dllexport)
void __stdcall Example() 
{
    Publics::Class1::Run();
}

构建您的解决方案。运行dumpbin.exe /exports命令对DLL进行导出检查,以确保Example函数已经导出。您应该会看到类似于以下内容:
      1    0 00001020 _Example@0 = _Example@0

除了名称和调用约定之外,您现在还有许多选择来调整导出函数。例如,如果您想要导出一个实例方法而不是静态方法,则可以编写以下函数:

extern "C" __declspec(dllexport)
void __stdcall Example() 
{
    Publics::Class1^ obj = gcnew Publics::Class1;
    obj->Run();
}

等等,如果您要进行这种复杂的操作,就需要对C++/CLI语言有一定了解。最后但并非不重要的是,您还可能会发现在尝试使用Giesecke的IL重写器时出现了什么问题。否则,它将使用与C++/CLI编译器相同的技术导出托管方法。


2
+1 我非常感激这个教程。我学到了很多东西。我一直以为UnmanagedExports在执行某种黑魔法。很高兴知道真相。 - David Heffernan
这在Mono中可以工作吗? - denfromufa
从您在帖子中插入的编译C++/CLI类库创建的混合模式程序集/DLL中,函数“Example()”是否可以从非托管代码(例如Delphi、本机C++)访问,就像它是一个常规的纯非托管DLL一样?当非托管代码调用导出函数时,CLR是否会自动启动? - Niklas Peter
1
@HansPassant,我很困惑,因为这篇文章似乎使用了一个额外的层次结构:C# => C++/CLI => 本机C++ => 非托管客户端,而你的方法是:C# => C++/CLI => 非托管客户端。与使用托管COM服务器相比,你的方法有哪些不足之处(除了需要编写C++/CLI外,在使用COM时也需要在非托管应用程序中添加一些代码)?我认为,使用你建议的C++/CLI进行性能优化比使用COM更好。是的,我会试一下。 - Niklas Peter
那个人并不是第一个认为可以自动完成的人。当你不得不调试它时,愿上帝怜悯你的灵魂。 - Hans Passant
1
这不会导致两个程序集吗(一个混合的和一个托管的)? - Ray

1
我一直在使用1.1.3版本,现在发现有一个支持NuGet的更新版本。我刚刚进行了测试。
“我能否检查一下执行所有操作的MSBuild任务是否实际运行了呢?”
您可以通过命令行获取MSBuild的更多详细信息或调整Visual Studio请求的详细程度: “工具>选项>项目和解决方案>生成和运行>MSBuild项目生成输出详细程度”[VS 2010]。完成故障排除后,您可能想要重置它。
我看到目标和任务被调用了,但是直到我将项目平台切换为x86之后才看到任何结果。然后我看到各种相关的日志条目,包括“添加.vtentry:0 .export”....
“项目文件应该包含什么内容(对我来说似乎非常空)?”
项目文件中不需要太多内容。NuGet会自动完成:对DllExport程序集的引用以及目标文件的包含。
我能想到的可能会使您困惑的一些事情:
  1. 确保你正在构建该项目。解决方案构建管理器可能有一些未设置为选定解决方案配置文件的项目不进行构建。
  2. 确保你检查的是正确的 DLL 文件。构建任务会将路径写入构建日志中,该行以 Assembling 开头。

我已经苦苦挣扎了几个小时...而你提到的点#2正是解决方案!VS有很多输出文件夹,包含构建的*.dll文件,但并不是所有的都能工作(没有导出函数),只有在..\ClassLibrary1\bin\x86\Debug中的一个实际上可以。这可能是初学者的错误,但还是谢谢:D - Martin Schneider

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