2016-06-19 1 views
0

Я использую сообщество VS 2015 с веб-приложением ASP.NET MVC, которое использует стороннюю C++ DLL. У меня нет исходного кода. Документация очень скудна, как и любое полезное сообщение с авторами третьей стороны DLL.C# вызов C++ сторонняя DLL (без источника) вызывает исключение - не совместимо с PInvoke

Я спросил связанный SO Question и получил хороший ответ от @Steven. Я изменил свой код в соответствии с его ответом и пытаюсь сделать успешный вызов третьей стороне C++ DLL. Код:

// Вызов DLL

MyDLLInput _DLLInput = new MyDLLInput(); 
{ 
    SomeList = new int[288], 
    ... 
    SomeInt = 22, 
    SomeDbl = 1.45, 
    ... 
    PathtoData = "C:\\Some\\Path\\To\\Data" 
};  

var ids = new int[] { 0, 12, 33, 67, 93 }; 
Array.Copy(ids, _DLLInput.SomeList, ids.Length); 

// Call DLL Entry Point 
MyDLLOutput _DLLOutput = MyDLL.Unit(_DLLInput); 

Поднимает исключение: тип подпись

методы не PInvoke совместима.

// C# Input STRUCT

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct MyDLLInput 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)] 
    public int[] SomeList; 
    ... 
    public int SomeInt; 
    public double SomeDbl; 

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
    public string PathtoData; 
}; 

// C# Выход STRUCT

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct MyDLLOutput 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)] 
    public int[] SomeList; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 288)] 
    public double[] SomeDblArray; 
    ... 
    public int SomeInt;  // Same as input 
    public double SomeDbl;  // Same as input 
} 

// C# DllImport

public class MyDLL 
{ 
    [DllImport("My_DLL.dll", 
     EntryPoint = "[email protected]@[email protected]@[email protected]@@Z", 
     CallingConvention = CallingConvention.Cdecl)] 
    public static extern MyDLLOutput Unit(MyDLLInput UnitInput); 
} 

// C++ My_DLL.h

#define EPS_API __declspec(dllexport) 

struct DLLInput 
{ 
    int SomeList[288]; 

    int SomeInt; 
    double SomeDbl; 

    char PathtoData[256]; 
}; 

struct DLLOutput 
{ 
    int SomeList[288]; 
    double SomeDblArray[288]; 
    ... 
    int SomeInt; 
    double SomeDbl; 
}; 

EPS_API DLLOutput Unit(DLLInput UnitInput); 

Я думаю, что я должен быть рядом, но не смогли найти какой-либо SO или Google результаты поиска, которые помогают. Кто-нибудь видит, что я делаю неправильно?

+1

У вас есть право EntryPoint? Он не имеет отношения к 'LOutput const volatile __cdecl Unit (struct DLLInput)'. – 1201ProgramAlarm

+0

@ 1201ProgramAlarm Я вижу, о чем вы говорите, и исправил его в моем примере. Спасибо. – rwkiii

+1

Есть ли у вас какие-либо другие типы в вашей выходной структуре, например 'char []'? Из [этого сообщения] (http://stackoverflow.com/questions/27201996/c-sharp-methods-type-signature-is-not-pinvoke-compatible) ваш тип вывода должен быть blittable, а массивы char - нет (они должны быть строками). – 1201ProgramAlarm

ответ

1

Расширение на то, что сказал Бен.

Вам нужно удалить определения const вне встроенной структуры. Объявляя компоновку структуры как последовательной, компилятор ожидает ТОЧНО одно и то же количество членов, объявленных ТОЧНО одним и тем же порядком, с каждым объявленным типом, ТОЧНО одинакового размера с обеих сторон (т.е. на C++ и C#). Эти объявления const добавляют к макету памяти, и поэтому подписи несовместимы.

char не такой же размер в C# и C++, byte (хотя они могут меняться в зависимости от платформы, оба типа гарантируют не менее 8 бит). Вы можете собрать массив byte вместо string, но все в порядке.

Создать массив byte, который совместим с массивом C++ char (такого же размера).

UTF8Encoding utf8 = new UTF8Encoding(); 
public byte[] PathToData = new byte[256]; 
PathToData = utf8.GetBytes(pathToDataString); 

На другой ноте, хотя, если документация не хватает, и авторы не являются полезными, лично я бы дважды подумать об использовании этой 3-й партии. Вызов это одно, отладка - другое.

+0

У меня была проблема совместимости с PInvoke до добавления константы в каждую структуру. Я увидел еще один пример MS, который определил const для размеров массива, но я не знал, что это вызвало накладные расходы в сигнатуре. Хотя теперь я удалил его с массивами, определенными с помощью '[288]', но у меня все еще такая же проблема. Я также проверил каждого участника, чтобы убедиться, что они определены точно как DLL сторонних DLL. Я отредактирую свой вопрос и удалю 'const' - вы говорите иначе, чем это выглядит так, как будто я правильно закодирован? – rwkiii

+0

Я проверил тройную проверку, что все члены определены и в точном порядке, как .h - У меня также есть все 'int []' и 'double []', установленные с атрибутами маршаллинга в соответствии с моим кодом выше. Единственные члены, которых я не сортировал, являются членами 'int' и' double'. Я не вижу способа их сортировки. В структуре вывода нет других типов. – rwkiii

+0

@ rwkiii Вам не нужно сортировать один двойной или int, они POD. Варианты массива должны быть отсортированы. – lfgtm

Смежные вопросы