views:

156

answers:

3

I'm converting a function from Visual Basic 6.0 as:

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

In C#, I'm declare the function as:

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

When call RequestOperation from C#, it throws an exception:

[System.AccessViolationException] = {"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."}

I have successful in calling many other functions like this, but only this function throws the exception.

+3  A: 

This function is clearly not throwing an AccessViolationException - instead, it is generating an access violation fault by "attempting to read or write protected memory". .NET is translating that fault into an AccessViolationException.

You'll have to go figure out why it is "attempting to read or write protected memory". In particular, did you initialize the StringBuilder you are passing to it? Please post the code you use to call this method.

John Saunders
YesI have initialize the StringBuilder with Capicity = 4096Vb6 code callingDim bufSearchRequest As String * 4096retCode = SearchRequestOperation(hDocumentType, bufSearchRequest, Len(bufSearchRequest), fieldIdx, queryType, stringQuery)and this is C# callingStringBuilder searchRequest = new StringBuilder(4096);retCode = RequestOperation(hDocumentType, searchRequest, searchRequest.Capacity, index, queryType, query);
Thai_VS
As Eran says, the error is clearly happening because you're passing a StringBuilder object into a function that is expecting a string. They are not interchangeable.
Alex Warren
Eran is incorrect. The DLL is returning a string through the searchRequestBuf argument. Therefore StringBuilder has to be used. String can only be used if the DLL does not modify the input string. See for instance here. http://msdn.microsoft.com/en-us/library/ms235282(VS.80).aspx
MarkJ
@ThaiV Can you clarify why you accepted this answer? Did initialising the StringBuffer solve the problem?
MarkJ
@ThaiV: Did this answer help you?
John Saunders
@downvoter: care to explain the reason for your vote?
John Saunders
A: 

I think the StringBuilder in the function declaration has something to do with it. You should use just plain String instead.

Eran Betzalel
The StringBuilder parameter type is used for [OutAttribute]
Thai_VS
I don't think it's matter. Nevertheless, you have no reason of using StringBuilder as a parameter as it suppose to **build strings** in an optimized performance and not to pass as data container.
Eran Betzalel
-1 Eran, you are incorrect. The DLL is returning a string through the searchRequestBuf argument. Therefore StringBuilder has to be used - String cannot be used because .NET strings are immutable. See for instance here on MSDN http://msdn.microsoft.com/en-us/library/ms235282(VS.80).aspx
MarkJ
Wow, that's really weird... I guess you can only expect this crude implementation from Microsoft. I mean - It's a String Builder, it builds strings... what does it have to do with passing data by ref?!
Eran Betzalel
The P/Invoke mechanism of .NET marshals data between managed and unmanaged code. It marshals [out] string data into a `StringBuilder` just fine. You should read up on P/Invoke before calling it "crude".
John Saunders
I know what P/Invoke does. The `StringBuilder` part at P/Invoke - I didn't know and never got to use it. It still looks to me like a crude design to use a class called `StringBuilder` to output string data.
Eran Betzalel
It's used for `out` parameters where the function itself _writes_ into the string buffer you provide to it. The only .NET class which provides reasonable correspondence for a "mutable string buffer" is `StringBuilder`.
Pavel Minaev
Indeed, hence - crude design.
Eran Betzalel
How would you design it to not be crude?
John Saunders
I would use a different name than `StringBuilder`. I'd use StringBuilder for its intended use - to build strings at an optimum efficiency.
Eran Betzalel
A: 

/// Return Type: int ///dth: int ///searchRequestBuf: BSTR->OLECHAR* ///buflen: int ///FieldNum: int ///OP: int ///value: BSTR->OLECHAR* [System.Runtime.InteropServices.DllImportAttribute("", 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)] string value) ;

Sheng Jiang 蒋晟
In a VB6 `Declare` statement, a ByVal String is marshalled as a pointer to an ANSI string, not a BSTR. If you want to write it that way, it should be `System.Runtime.InteropServices.UnmanagedType.LPStr` both times
MarkJ