Преобразование функции из Visual Basic 6.0 в C# вызывает исключение AccessViolationException.

Я конвертирую функцию из Visual Basic 6.0 как:

Declare Function RequestOperation Lib "archivedll" (ByVal dth As Long, ByVal searchRequestBuf As String, ByVal buflen As Long, ByVal FieldNum As Long, ByVal OP As Long, ByVal value As String) As Long

В С# я объявляю функцию как:

[DllImport("archivedll")]
public static extern int RequestOperation(int dth ,StringBuilder searchRequestBuf, int bufferLen, int fieldNum, int op, string value);

При вызове RequestOperation из C# возникает исключение:

[System.AccessViolationException] = {"Попытка чтения или записи защищенной памяти. Часто это указывает на то, что другая память повреждена."}

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


person Thai Vong    schedule 10.11.2009    source источник


Ответы (3)


Эта функция явно не выдает AccessViolationException — вместо этого она генерирует ошибку нарушения доступа, «попытку чтения или записи в защищенную память». .NET переводит эту ошибку в ошибку AccessViolationException.

Вам придется выяснить, почему он «пытается прочитать или записать защищенную память». В частности, вы инициализировали StringBuilder, который вы ему передаете? Пожалуйста, опубликуйте код, который вы используете для вызова этого метода.

person John Saunders    schedule 10.11.2009
comment
Да, я инициализировал StringBuilder с помощью кода Capicity = 4096 Vb6, вызывающего Dim bufSearchRequest As String * 4096 retCode = SearchRequestOperation(hDocumentType, bufSearchRequest, Len(bufSearchRequest), fieldIdx, queryType, stringQuery), и это C#, вызывающий StringBuilder searchRequest = new StringBuilder(4096 ); retCode = RequestOperation(hDocumentType, searchRequest, searchRequest.Capacity, index, queryType, query); - person Thai Vong; 10.11.2009
comment
Как говорит Эран, ошибка явно происходит из-за того, что вы передаете объект StringBuilder в функцию, ожидающую строку. Они не взаимозаменяемы. - person Alex Warren; 10.11.2009
comment
Эран не прав. DLL возвращает строку через аргумент searchRequestBuf. Поэтому необходимо использовать StringBuilder. Строка может использоваться только в том случае, если DLL не изменяет входную строку. См., например, здесь. msdn.microsoft.com/en-us/library/ms235282 (VS.80).aspx - person MarkJ; 10.11.2009
comment
@ThaiV Можете ли вы пояснить, почему вы приняли этот ответ? Инициализация StringBuffer решила проблему? - person MarkJ; 10.11.2009
comment
@ThaiV: Этот ответ помог вам? - person John Saunders; 10.11.2009

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

person Eran Betzalel    schedule 10.11.2009
comment
Тип параметра StringBuilder используется для [OutAttribute]. - person Thai Vong; 10.11.2009
comment
Я не думаю, что это имеет значение. Тем не менее, у вас нет причин использовать StringBuilder в качестве параметра, поскольку он предполагает создание строк с оптимизированной производительностью, а не для передачи в качестве контейнера данных. - person Eran Betzalel; 10.11.2009
comment
-1 Эран, ты не прав. DLL возвращает строку через аргумент searchRequestBuf. Поэтому необходимо использовать StringBuilder — String нельзя использовать, поскольку строки .NET неизменяемы. См., например, здесь, в MSDN msdn.microsoft.com/en -us/library/ms235282(VS.80).aspx - person MarkJ; 10.11.2009
comment
Вау, это действительно странно... Я думаю, вы можете ожидать только такую ​​грубую реализацию от Microsoft. Я имею в виду - это String Builder, он строит строки... какое отношение он имеет к передаче данных по ссылке?! - person Eran Betzalel; 10.11.2009
comment
Механизм P/Invoke .NET упорядочивает данные между управляемым и неуправляемым кодом. Он просто маршалирует строковые данные [out] в StringBuilder. Вы должны прочитать о P/Invoke, прежде чем называть его грубым. - person John Saunders; 10.11.2009
comment
Я знаю, что делает P/Invoke. Часть StringBuilder в P/Invoke - я не знал и никогда не использовал ее. Мне все еще кажется грубым замыслом использовать класс с именем StringBuilder для вывода строковых данных. - person Eran Betzalel; 11.11.2009
comment
Он используется для out параметров, когда сама функция записывает в строковый буфер, который вы ей предоставляете. Единственный класс .NET, который обеспечивает разумное соответствие для изменяемого строкового буфера, — это StringBuilder. - person Pavel Minaev; 01.12.2009
comment
Действительно, отсюда - сырой замысел. - person Eran Betzalel; 02.12.2009
comment
Как бы вы спроектировали его, чтобы он не был грубым? - person John Saunders; 03.12.2009
comment
Я бы использовал другое имя, чем StringBuilder. Я бы использовал StringBuilder по прямому назначению — для построения строк с оптимальной эффективностью. - person Eran Betzalel; 04.12.2009

/// Return Type: int
///dth: int
///searchRequestBuf: BSTR->OLECHAR*
///buflen: int
///FieldNum: int
///OP: int
///value: BSTR->OLECHAR*
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="RequestOperation")]

public static extern int RequestOperation(int dth, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.BStr)] string searchRequestBuf, int buflen, int FieldNum, int OP, [System.Runtime.InteropServices.MarshalAsAttribute( System.Runtime.InteropServices.UnmanagedType.BStr)] строковое значение) ;

person Sheng Jiang 蒋晟    schedule 10.11.2009
comment
В операторе VB6 Declare строка ByVal сортируется как указатель на строку ANSI, а не на BSTR. Если вы хотите так написать, то оба раза должно быть System.Runtime.InteropServices.UnmanagedType.LPStr - person MarkJ; 11.11.2009