0

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                                          "

VBA for Excel Code

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


C# Code Snippet

[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);
}

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Try catching the Win32Exception. `catch(Win32Exception w)` then you can call `var e=w.GetBaseException();` to get more detail on exception. – vendettamit Mar 01 '16 at 22:17
  • Thank you for the response @vendettamit, I am having trouble with this. – Commander Zarkov Mar 02 '16 at 13:30
  • Thank you for the response @vendettamit, I am having trouble with this. – Commander Zarkov Mar 02 '16 at 13:40
  • `public int StartTheDataSpace() { //I've not been totally forthcoming here... //There was actually an array by which the integers were passed int[] try1 = {0, -1, -1, 2, 0, 0, 0, 0, 0 }; StringBuilder c = new StringBuilder(128); StringBuilder d = new StringBuilder(128); c.Append(" 12345678901234[...] "); try { return dllSpace(try1[1], try1[1], c, d); } catch (System.ComponentModel.Win32Exception ex) { Console.WriteLine(ex.Data); return -1; } }` – Commander Zarkov Mar 02 '16 at 13:41
  • The above code is not working for me... I thought I knew how to implement a try - catch... – Commander Zarkov Mar 02 '16 at 13:44

1 Answers1

0

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
);
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • And here I was thinking that I tried every combination. Thank you David Heffernan, I am embarrassed to say I have been working on this particular problem for many days. I simply added ref in front of the two integer declarations and the dllSpace returned 0 which is the "no error" response. Thanks again. – Commander Zarkov Mar 02 '16 at 13:28