2012-08-24 4 views
0

В настоящее время я разрабатываю надстройку Excel на C#, и я использую interop с библиотекой C++. Оба разработаны мной. Библиотека C++ не является компонентом COM, а только DLL, экспортирующая некоторые функции.C# dllimport parameters shift

У меня есть одна функция C#, которую я хочу передать число и две строки функции C++, а функция C++ возвращает строку. Сначала я пытался вернуть строку непосредственно, так что прототипы выглядят что-то вроде

//C# 
[return: MarshalAs(UnmanagedType.LPStr)] 
private static extern string Function([MarshalAs(UnmanagedType.I4)] int number, 
             [MarshalAs(UnmanagedType.LPStr)]string str1, 
             [MarshalAs(UnmanagedType.LPStr)] string str2); 
//C++ 
extern "C" __declspec(dllexport) string Function(int, char*, char*); 

(BTW, я установил уже соглашение о вызовах в C# для этой функции в качестве Cdecl)

Затем, когда я называю C# версии , и вступил в C++ (при отладке), я обнаружил, что параметры сдвинуты, поэтому целое число является значением указателя на первую строку, а первая строка является второй строкой, а вторая строка указывает на другое место , Я также проверил память и обнаружил, что параметры не были переданы в соответствии с соглашением _cdecl, целое число было последним, помещенное в стек (это нормально), но позиции двух строк были переключены. Есть много другой информации, которую добавил компилятор, поэтому я не хочу углубляться в это.

Однако позже я изменил возвращенную строку в качестве параметра, и прототипы выглядят как

//C# 
private static extern void Function([MarshalAs(UnmanagedType.I4)]int number, 
            [MarshalAs(UnmanagedType.LPStr)] string str1, 
            [MarshalAs(UnmanagedType.LPStr)] string str2, 
            [MarshalAs(UnmanagedType.LPStr), Out] StringBuilder returnStr); 
//C++ 
extern "C" __declspec(dllexport) void Function(int, char*, char*, string&); 

А теперь параметры правильно прошли.

Итак, мой первый вопрос: как это происходит?

Мой второй вопрос заключается в том, что даже при использовании второго метода я не мог правильно запустить программу, программа потерпела крах при возврате из функции C++ (фактически в функции C++ единственное, что нужно сделать, - вызвать другую функцию-член класса, поэтому функция просто похожа на оболочку функции-члена, и программа сразу же разбилась при возврате в функции-член. Так как функция warpper просто вызывает функцию-член, поэтому я не могу определить, где проблема).

У кого-нибудь есть идея, как это сделать? Таким образом, основной функцией этой функции является принятие числа и двух строк и возврат другой строки.

Спасибо в продвижении.

ответ

0

look at this article about the usage of stringbuilder in unmanaged code

попробовать что-то вроде этого:

//C# 
public string Function(int number, string str1, string str2) 
{ 
    StringBuilder sbStr1 = new StringBuilder(str1); 
    StringBuilder sbStr2 = new StringBuilder(str2); 
    StringBuilder sbReturnStr = new StringBuilder(1024); 
    Function(number, sbStr1 , sbStr2 , sbReturnStr , sbReturnStr.Capacity); 
    return sbReturnStr.ToString(); 
} 

//C# p/invoke 
private static extern void Function(int number, StringBuilder str1, StringBuilder str2, StringBuilder returnStrBuffer, int size); 

//C++ 
extern "C" __declspec (dllexport) void __stdcall Function(int number, const char* str1, const char* str2, char* returnStrBuffer, int size) 
{ 
    //fill the returnStrBuffer 
    strncpy(returnStrBuffer, "blablalb", size); //example!! 
} 
+0

Спасибо, очень совпадению вчера я говорил тот же блог на другой вопрос, и я обнаружил, что очень полезно! Я проверил также тот, который вы предоставили, и я узнал, что это немного сложно. Я попробую метод, о котором упоминалась другая статья того же блога, используя CoTaskMemAlloc. Если это не сработает, я могу попробовать этот последний вариант. Благодарю. –

+0

Еще раз спасибо за ваше обновление! Я только что прочитал блог, и я понял, что главная проблема возврата строки - проблема кучи. Я попробую вашу версию и версию, использующую AllocHGlobal. –

+0

Привет, codeteq, я попробовал вашу версию, но у меня возникла ошибка утверждения, что буфер слишком мал. Я выделил 1024 байта для построителя строк, как это могло произойти? –