简体   繁体   中英

Unable to find an entry point in C++/CLI

Pardon me, though I tried to shorten this, it's still long.

I know some C# and C++, but am learning CLI. I have a native C function that performs some, uh, statistical calc's. It has 1 or 2 embedded assembly language instructions -- the saving grace of it is sheer speed (like drinking water from a fire hose). I'm not re-writing it. Hence I'm trying to put it in a dll and call it from C#. Hence C++ / CLI.

By my reckoning the following code ought to be close to working [marshaling is probably wrong though]. After extensive Stack_Overflow research -- btw, have enjoyed reading lots of questions and there are some great answers -- I've gotten to the point of things compiling. The C# gui does it's work and is able to put together a presumably valid parameter list for the wrapper function. Then this runtime error...

An unhandled exception of type 'System.EntryPointNotFoundException' occurred in gui_proj.exe

Additional information: Unable to find an entry point named 'process_these_files' in DLL 'Wrapper_proj.dll'.

I've boiled the code down to essentials (I think). The dll is ref'd in the gui proj. The Object Browser seems to see the entry point. Dependency Walker is all screwed up -- "IESHIMS.DLL" really?! Silurian Inspect_Exe says it can load the dll and displays basic properties, but isn't able to show any imports/exports. [Both projects are 64-bit configured]. I clean the solution before I build.

How do I get an entry point to be ' found ' ? Do I need to marshal the file names? or marshal the (empty) result arrays?

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

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

In 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

+++ If I try the following declaration (in wrapper_proj.h) "static Wrapper_proj_API void process_these_files(" then I get

error C3387: 'process_these_files' : __declspec(dllexport)/__declspec(dllimport) cannot be applied to a member of a managed type

error C3395: 'City_Hash_Lib::City_Hash::process_these_files' : __declspec(dllexport) cannot be applied to a function with the __clrcall calling convention

++++ Would like to keep the "public ref Class", but oddly enough it doesn't seem to be preventing dllexport.

Dumpbin /EXPORTS says this...

Dump of file Wrapper_proj.dll File Type: DLL Summary 3000 .data 2000 .nep 1000 .pdata 27000 .rdata 1000 .reloc 3000 .rsrc A000 .text

Making a .def file to export "process_these_files" yielded error C3387.

Since you're using C++ /CLI, the resulting image is a .NET image. All you need to do is import the namespace in your C# file, with appropriate references in the C# project.

I tried this C# code:

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

        }
    }
}

I did have to play with settings on the projects in Visual Studio to get the linker settings to align.

I just started pushing sample code to GitHub. You can download the whole project from https://github.com/kc1073/Samples

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM