Любопытная проблема DllImport, при передаче ДЛИННОГО параметра повреждение памяти

#c# #c #.net-3.5 #dllimport

#c# #c #.net-3.5 #dllimport

Вопрос:

Я создал DLL-функцию для использования внутри C # с использованием DllImport, но у меня возникли проблемы с вызовом метода, поскольку у меня возникают проблемы с повреждением памяти;

 [DllImport("mydll.dll", EntryPoint = "callinmydll")]
public static extern int testdllcall(double *firstinput, long firstcount, double *secondoutput, long secondcount);
 

Вот часть заголовка библиотеки C ;

 extern "C" {              

mydll_API int callinmydll(double *in, long firstcount, double *out, long secondcount);

}
 

Реализация.

 mydll_API int callinmydll(double *in, long firstcount, double *out, long secondcount)
{
    for( int i =0 ; i < 10 ; i   ) 
    {
        *(out   i) = (*(in   i)   10 );
    }

    return 0;
}
 

Теперь, когда моя функция DllImport вызывает функцию callinmydll и передает ей действительные данные, вот тут все становится интересным. Указатель in содержит данные, как и firstcount . Хотя все, что находится за пределами этой точки, повреждено. Почему? Любопытно, что я перестраиваю свою функцию на double, double *, long, long теперь повреждение происходит после третьего параметра. Мне любопытно, что происходит, поскольку я передаю действительные данные; два действительных указателя и приведение int к int64.

Помогите!

Комментарии:

1. Не совсем уверен, но это не long в c , больше похоже на int в c #, т.е. от -2147483647 до 2147483647

2. Соглашения о вызовах также не совпадают.

Ответ №1:

В Win32 C a long по-прежнему 32-разрядный. В вашей подписи C # используется long 64-разрядный код. Ваш второй и четвертый параметры должны быть int в сигнатуре C #.

Смотрите Эту таблицу для получения дополнительной информации.

Итак, ваша подпись выглядит так:

 [DllImport("mydll.dll", EntryPoint = "callinmydll")]
public static extern int testdllcall(double *firstinput, int firstcount, double *secondoutput, int secondcount);
 

Кроме того, убедитесь, что ваше соглашение о вызовах правильное, как указал Ramhound в комментариях. Ваша функция C выглядит так, как будто она использует соглашение CDecl, а .NET по умолчанию использует StdCall . Вы можете установить соглашение о вызовах в атрибуте:

 [DllImport("mydll.dll", EntryPoint = "callinmydll", CallingConvention = CallingConvention.Cdecl)]
 

Комментарии:

1. Спасибо за ответ, теперь имеет смысл.

2. Если управляемый код предназначен для запуска в 32-разрядной или 64-разрядной среде Windows, то как следует использовать ДЛИННЫЙ параметр?

3. Предполагая, что «ДЛИННЫЙ» означает Win32 long, его следует маршалировать как int .