2014-09-25 3 views
2

A (не-COM) DLL Delphi имеет функцию экспортируемая:PInvokeStackImbalance при вызове функции DLL Delphi

function GetQuestions(Digit1, Digit2: string; CountryISO: string):string; 

Я добавил этот DLL в качестве существующего элемента в Visual Studio 2012 и установить его Build Action до Отсутствует, Скопировать в выходной каталог до Копирование всегда.

Класс, содержащий DllImportAttribute:

public class RefundLibrary 
{ 
    [DllImport("RefundLibrary.dll", EntryPoint = "GetQuestions", 
     CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] 
    public static extern IntPtr GetQuestions(string digit1, string digit2, 
     string countryISO); 
} 

Когда я называю этот метод в Page_Load в виде WebForm (не уверен, если это уместно), он бросает PInvokeStackImbalance для возможного несоответствия подписи на ниже указанной линии:

protected void Page_Load(object sender, EventArgs e) 
{ 
    IntPtr str = RefundLibrary.GetQuestions("", "", "BE"); //<- here 
    string result = Marshal.PtrToStringUni(str); 

    testp.InnerText = result; 
} 

Я также попытался изменить тип возвращаемого метода метода DllImport в строку, ошибка идентична.

Я считаю, что Marshal.PtrToStringUni(str) верен, насколько Embarcadero docs идти?

В RAD Studio, строка является псевдонимом для UnicodeString

Действительно ли это несоответствие подписи? Что мне не хватает (за исключением, очевидно, достойного понимания P/Invoke)?

+1

Вы уверены, что это StdCall? Дисбаланс обычно происходит, когда это должно быть cdecl. – plinth

+1

Кроме того, я не думаю, что вы можете импортировать функции Delphi с сигнатурами, которые используют аргументы Delphi String в .NET и ожидают, что это будет Just Work. Строки Delphi представляют собой структуры, управляемые RTL, со специальной обработкой памяти, подсчетом ссылок и т. Д. –

+0

Настройка @plinth CallingConvention.Cdecl ничего не меняет. –

ответ

3

Вы не можете назвать эту функцию. Он использует соглашение о вызове Delphi только register и использует строки Delphi. Измените его на:

procedure GetQuestions(
    Digit1: WideString; 
    Digit2: WideString; 
    CountryISO: WideString; 
    out Questions: WideString 
); stdcall; 

На C# стороне:

[DllImport("RefundLibrary.dll")] 
public static extern void GetQuestions(
    [MarshalAs(UnmanagedType.BStr)] 
    string digit1, 
    [MarshalAs(UnmanagedType.BStr)] 
    string digit2, 
    [MarshalAs(UnmanagedType.BStr)] 
    string countryISO, 
    [MarshalAs(UnmanagedType.BStr)] 
    out string questions 
); 

Использование WideString/BStr отлично подходит для выходного параметра. Поскольку контент выделяется в общей куче COM-кластера, это означает, что вызывающий может освободить его.

Вы можете использовать PWideChar/LPWStr для входных параметров. Это будет хорошо. Я использовал WideString, потому что я хотел быть последовательным. Тебе решать.

+1

ты мой герой! –

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

  • Нет связанных вопросов^_^