I have the following (VB6?) code working perfectly in VBA for Excel. The dll that I am using (x.dll) is a "black box" to me. I don't know what it is written in, whether it is unmanaged or not. I know very little about it from an historical technical point of view. I only know that this particular function works when called from Excel VBA and I cannot similarly get it to function when I call it from C# and I think I should be able to. Again the value of c.b128 is used by and changed by the dll.
'In VBA for excel the value inside "c.b128" is changed from
'" 1234567890123456789012345678901234567890123456789012345678901234567890123456789 "
'to
'" 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 123456789 "
Private Type k128
b128 As String * 128
End Type
Private Declare Function dllSpace Lib "x.dll" (aInfo As Long, _
bVec As Long, cQry As k128, dErr As k128) As Long
Function Space() As Long
Dim c As k128
Dim d As k128
c.b128 = Left(" 1234567890123456789012345678901234567890123456789012345678901234567890123456789", 128)
d.b128 = Left("", 128)
Space = dllSpace(-1, -1, c, d)
End Function
I tried to implement the same in .NET and got an error when it gets to "return dllSpace(-1, -1, c, d);" An unhandled exception of type system.accessviolationexception occured in [...] attempted to read or write protected memory. other memory is corrupt
I need to convert this to .NET and I get an AccessViolationException. Everywhere I read that the memory reserved by StringBuilders are accessible to dlls in C#. I have tried “ref StringBuilder” I have tried using byte[], I have tried using the unsafe descriptor, I don’t understand. Also if there is a way for me to see more of what is going on in memory using the IDE that would also be helpful to me. I can see all my variables in the local and watch windows, but I can’t see and don’t know how to see more details about the exception that is thrown. I am using Visual Studio Express 2013 for Windows Desktop on a Win7 32 bit OS machine.
This is a snippet from my c# code
[DllImport(@"x.dll")]
private static extern int dllSpace(int aInfo,
int bVec,
StringBuilder cQry,
StringBuilder dErr);
public int StartTheDataSpace()
{
StringBuilder c = new StringBuilder(128);
StringBuilder d = new StringBuilder(128);
c.Append(" 1234567890123456789012345678901234567890123456789012345678901234567890123456789 ");
return dllSpace(-1, -1, c, d);
}
The VBA code makes it clear that what you have is actually a structure containing a fixed length string. That means that StringBuilder
is the wrong type. You should instead use:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct k128
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string b128;
}
Also, as I understand it, VBA uses ByRef
as default. So the C# declaration should be:
[DllImport(@"x.dll")]
private static extern int dllSpace(
ref int aInfo,
ref int bVec,
ref k128 cQry,
ref k128 dErr
);
Now, it so happens that ref k128
has the same memory layout when marshalled as StringBuilder
with capacity 128 so you may find it more convenient to switch back to:
[DllImport(@"x.dll")]
private static extern int dllSpace(
ref int aInfo,
ref int bVec,
StringBuilder cQry,
StringBuilder dErr
);