在C++/CLI中无法找到入口点

3

很抱歉,尽管我试图缩短这段内容,但它仍然很长。

我知道一些C#和C ++,但正在学习CLI。我有一个本地的C函数,执行一些统计计算。它有1或2个嵌入式汇编语言指令 - 它的优点是速度非常快(像从消防龙带喝水一样)。我不会重写它。因此,我试图将其放入dll中,并从C#调用它。因此需要使用C ++ / CLI。

按我的估算,以下代码应该接近工作[尽管可能会出现错误的封送处理]。经过广泛的Stack_Overflow研究 - 顺便说一句,我很享受阅读很多问题并且有一些很棒的答案 - 我已经到达了编译事物的地步。 C#gui完成其工作,并能够为包装器函数组合一个可能有效的参数列表。然后是运行时错误...

类型为'System.EntryPointNotFoundException'的未处理异常在gui_proj.exe中发生

附加信息:无法在DLL 'Wrapper_proj.dll'中找到名为'process_these_files'的入口点。

我已经将代码简化到必要的部分(我认为是)。该dll在gui proj中被引用。对象浏览器似乎看到了入口点。Dependency Walker全部搞砸了 -“IESHIMS.DLL”真的?Silurian Inspect_Exe说它可以加载dll并显示基本属性,但无法显示任何导入/导出。[两个项目都是64位配置]。我在构建之前清理解决方案。

如何获得一个入口点'found'?我需要封送文件名吗?还是封送(空)结果数组?

gui_proj.cs中:

// I've also tried CallingConvention.StdCall
[DllImport("Wrapper_proj.dll", SetLastError = true, CharSet = CharSet.Ansi, EntryPoint = "process_these_files", CallingConvention = CallingConvention.Cdecl)]

static extern void process_these_files( [In] int length, [In] String[] file_names, [Out] byte[] output_calcs, [Out] UInt64[] file_sizes);

private void Calcs_on_files_ThreadStart(object oo)
{
    List<int> fil_indices = new List<int>();
    List<string> fil_names = new List<string>();
    List<UInt64> fil_sizes = new List<UInt64>();

    foreach (DataGridViewRow rr in dgvFiles.SelectedRows)
    {
        fil_indices.Add(rr.Index);
        fil_names.Add( ((string)rr.Cells["Full_Name"].Value) );
        fil_sizes.Add( ((UInt64)((long)rr.Cells["File_Size"].Value)) ); // expected size
    }
    int jj = fil_names.Count;
    int kk = 32 * fil_names.Count;
    byte[] calc_results = new byte[kk]; // "byte" is equivalent to "uint8_t"
    UInt64[] siz_results = new UInt64[jj];
    string[] fil_arr = fil_names.ToArray();
    process_these_files( jj, fil_arr, calc_results, siz_results);
}

Wrapper_proj.h文件中:
#include "stdafx.h"
#include <fstream>      // std::ifstream
...

// compiler supposedly defines *"_EXPORTS", though just being definitive here
#define Wrapper_proj_EXPORTS

#ifdef Wrapper_proj_EXPORTS
#define Wrapper_proj_API __declspec(dllexport) 
#else
#define Wrapper_proj_API __declspec(dllimport) 
#endif

namespace Wrapper_proj {
    // ++++ see note below
    public ref class wrap_it
    {
    public:
        // +++ see note below
        static  void process_these_files(
            int length, // each array has same length (varying sizes though, of 

course)
            array<System::String^>^ files,
            array<System::Byte>^ calcs,
            array<System::UInt64>^ fil_sizes);
    };
}

Wrapper_proj.cpp 文件中
#include "stdafx.h"
#include "Wrapper_proj.h"

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
using std::ios;

namespace Wrapper_proj {

    void wrap_it::process_these_files(
        int arr_length,
        array<System::String^>^ files,
        array<System::Byte>^ calcs,
        array<System::UInt64>^ fil_sizes)
    {
...
    // call native calc. fcn. (that has asy. lang. instructions)
...
    };  // process_these_files
}   // end namespace

如果我尝试在wrapper_proj.h中使用以下声明: "static Wrapper_proj_API void process_these_files(" 然后我会得到以下错误信息:
error C3387: 'process_these_files' : __declspec(dllexport)/__declspec(dllimport)不能应用于托管类型的成员 error C3395: 'City_Hash_Lib::City_Hash::process_these_files' : __declspec(dllexport)不能应用于具有__clrcall调用约定的函数
我想保留"public ref Class",但奇怪的是它似乎并没有阻止dllexport。
Dumpbin /EXPORTS显示如下:
Dump of file Wrapper_proj.dll File Type: DLL Summary 3000 .data 2000 .nep 1000 .pdata 27000 .rdata 1000 .reloc 3000 .rsrc A000 .text
创建一个.def文件以导出"process_these_files"会产生错误C3387。

1
你混淆了概念。当你编写C++/CLI ref class包装器时,不要使用[DllImport]。只需添加对C++/CLI项目的项目引用,即可直接使用wrap_it类。 - Hans Passant
@HansPassant 感谢您的回复。 是的,这有点令人困惑。 请耐心等待,您是说gui_proj.cs中不需要[DllImport]吗? [Wrapper_proj.dll已在那里引用。] - Willem-Jan Meinl
1个回答

3

由于您正在使用C++ / CLI,因此生成的图像是.NET图像。您只需要在C#文件中导入命名空间,并在C#项目中进行适当的引用即可。

我尝试了这个C#代码:

using Callee;

namespace Caller
{
    class Program
    {
        static void Main(string[] args)
        {
            Byte[] calcs = new Byte[10];
            UInt64[] fil_size = new UInt64[10];
            String[] files = new String[1];
            files[0] = "file1";

            Class1.process_these_files(1, files, calcs, fil_size);

        }
    }
}

我曾经在Visual Studio项目中调整设置,以使链接器的设置对齐。

我刚开始将示例代码推送到GitHub上。您可以从https://github.com/kc1073/Samples下载整个项目。


俗话说,啊!是的这个可行。谢谢![我已经点赞了,但声望还不够]。在添加“static”到process_these_files()之前,我可能尝试过类似的东西。所以,总的来说,你是说CLI包装器不需要[ DllImport ]吗,但是什么时候它是必要的?也就是说,我如何区分何时使用p/invoke [ DllImport ]和何时不使用? - Willem-Jan Meinl
命名空间导入与程序集引用是独立的。它只允许您省略[或别名]类型限定符,这仅在使用扩展方法调用语法时需要。 - Tom Blodget
你没有创建CLI包装器。C++代码是本地.NET代码,因此您将处理这个程序集引用的方式与如果process_these_files是用C#编写的相同。DllImport用于执行.NET到本机代码的操作。 - KC-NH

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