2012-01-04 1 views
6

Я объявил импорт DLL в моей программе C#, который выглядит следующим образом:Множественные вызовы функций из C# в C++ неуправляемый код вызывает AccessViolationException

[DllImport("C:\\c_keycode.dll", EntryPoint = "generateKeyCode", 
      CallingConvention = CallingConvention.Cdecl)] 
static extern IntPtr generateKeyCode(char[] serial, char[] option, char c_type); 

Он ссылается на функцию generateKeyCode() внутри моей DLL.

Вот код, который вызывает ошибку (используемые точки останова):

const char* generateKeyCode(char serial[], 
       char option[], 
       char c_type) 
{ 
returnBufferString = ""; 
SHA1_CTX context; 
int optionLength = 0; 
#ifdef WIN32 
unsigned char buffer[16384] = {0}; 
#else 
unsigned char buffer[256] = {0}; 

#endif 
//char output[80]; 
char keycode[OPTION_KEY_LENGTH+1]  = ""; 
int digest_array_size = 10; //default value for digest array size 
unsigned char digest[20] = {0}; 
char optx[24] = {0}; 
char c_type_upper; 
// Combine serial # and Option or Version number 

char str1[30] = {0}; 
int i; 
int size = 0; 
int pos = 0; 


... 
... 
} 

В принципе, я импортировал этот DLL, так что я мог бы передать параметры функции, и это может сделать его алгоритм и просто вернуть мне результат , Я использовал эту функцию маршалера ...

public static string genKeyCode_marshal(string serial, string option, char type) 
{ 
    return Marshal.PtrToStringAnsi(generateKeyCode(serial.ToCharArray(), 
      option.ToCharArray(), type)); 
} 

... так что я мог правильно позвонить. Внутри моего заголовочного файла C++ я определил строку, как указано в ответе на этот вопрос question (это переменная returnBufferString, присутствующая в верхней части функции C/C++).

Я вызываю эту функцию несколько раз, так как я использую элемент управления NumericUpDown для перехода от 1.0 до 9.9 с шагом 0,1 (каждый вверх или вниз сопровождает другой вызов функции), а затем снова назад. Тем не менее, каждый раз, когда я пытаюсь это сделать, программа захватывается после кажущегося набора вызовов функций (останавливается на 1.9 на обратном пути, если я просто иду вверх и вниз, или раньше, если я чередую немного вверх и вниз) ,

Обратите внимание: это работает и дает мне значение, которое я хочу, там нет расхождений.

Я изменил размер буфера на какое-то меньшее число (5012), и когда я попытался запустить программу, при первом вызове функции это привело к исключению AccessViolationException. Однако удвоение размера буфера до двух (32768) оригинала не имело никакого эффекта по сравнению с оригиналом - вплоть до 9,9 от 1,0 и обратно назад, оно останавливается на 1,9 и выдает исключение.

EDIT: По умолчанию ANSI, поэтому ANSI. Проблем нет. Это проблема распределения памяти?

+0

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

+0

Символ в C# имеет ширину 2 байта. В C char имеет только 1 байт (я думаю, вам нужно, чтобы wchar_t составлял 2 байта в зависимости от параметров компилятора). Я бы начал там. –

ответ

0

Я знаю, что это может быть неудовлетворительным, но как только я снял перенаправление вывода я использую для отладки из моих C/C++ DLL, проблема остановилась , Сейчас все работает, поэтому я предполагаю, что это по сути эквивалентно ответе на мой собственный вопрос. Спасибо всем за ответы.

2

Я бы предложил попробовать следующее:

[DllImport("C:\\c_keycode.dll", EntryPoint = "generateKeyCode", 
     CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
static extern IntPtr generateKeyCode(string serial, string option, char c_type); 

Обратите внимание на новый CharSet области DllImport атрибута.

Следующая идея заключается в том, чтобы использовать MarshalAs атрибут явно:

[DllImport("C:\\c_keycode.dll", EntryPoint = "generateKeyCode", 
     CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] 
static extern IntPtr generateKeyCode([MarshalAs(UnmanagedType.LPTStr)] string serial, [MarshalAs(UnmanagedType.LPTStr)] string option, char c_type); 
+0

Hi Krizz. Он получил меня .1 далее (получил меня к 1.9 вместо 2.0 на обратном пути). Я думал об этом, но не думал, что это поможет. Спасибо за ответ, хотя. –

+0

Вы пробовали оба? Я добавил редактирование. – Krizz

+0

может быть, но дело также в том, чтобы полагаться на CLR на маршал 'string' вместо использования' char [] '. Вы тоже изменили его? – Krizz

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