2
votes

My client just sent me a delphi dll to be consumed for my asp.net app, and below is the dll's signature:

function GerarChave(pChave: ShortString; pData: ShortString; pAcao: ShortString): PAnsiChar; stdcall;

How should I call it? I've tried everything like

[DllImport("CEIINT.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "GerarChave")]
    public static extern string GerarChave([MarshalAs(UnmanagedType.BStr)]string pChave, [MarshalAs(UnmanagedType.BStr)]string pData, [MarshalAs(UnmanagedType.BStr)]string pAcao);

string chave = "ABC123";
string data = "19/09/2019";
string acao = "0";
GerarChave(chave, data, acao);

but I always get a System.AccessViolationException error which says:

System.AccessViolationException... Attempted to read or write protected memory. This is often an indication that other memory is corrupt

Could anybody help me please? Thanks in advance!

1
Delphi shortstring matches no pinvoke type. Get the dll vendor to supply a dll using interop types.David Heffernan
@DavidHeffernan According to docwiki.embarcadero.com/Libraries/Tokyo/en/System.ShortString the memory size is fixed at 256 bytes. So it should be marshallable as either a MarshalAs(UnmanagedType.ByValTStr, SizeConst=256) whereas in the DllImport-Attribute the CharSet parameter should be set to CharSet.Ansi or a byte array with MarshalAs(UnmanagedType.ByValArray, SizeConst=256). Of course, the first character must be manually read/written as the length.ckuri
@ckuri Wrong. The first byte is the string length.David Heffernan
@DavidHeffernan That's what I said with "Of course, the first character must be manually read/written as the length".ckuri
Going to be hard to get that first byte in there in general since you'd need to account for the local ANSI charset and hope that you can encode all chars greater than 127 in UTF16. Which I suppose you will always be able to do but not going to be much fun. If you had to do this you'd handle the encoding yourself and marshal as byte array. Better to fix the bogus DLL.David Heffernan

1 Answers

3
votes

Like David Heffernan said, you should try to get back to your client to request a DLL with more interoperable types.

If you have no other choice you could try to do the conversions manually, first by changing the signature to an byte array:

[DllImport("CEIINT.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "GerarChave")]
public static extern string GerarChave(
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] byte[] pChave, 
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] byte[] pData, 
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] byte[] pAcao);

Then define the following method to convert a string to a Delphi ShortString:

public byte[] GetDelphiShortString(string str)
{
  var bytes = new byte[256];
  bytes[0] = (byte)Encoding.Default.GetBytes(str, 0, str.Length, bytes, 1);
  return bytes;
}

Finally, you should be able to call the Delphi function via:

GerarChave(GetDelphiShortString(chave), GetDelphiShortString(data), GetDelphiShortString(acao));