Robert Giesecke's Unmanaged Exports - OUT strings

667 Views Asked by At

I'm working from VBA into .NET. I have a working version of an interface using CLI and stdcall

I'm trying to remove the resulting dependency on the C++ 2015 runtime, and it looks like I can do it using UnmanagedExports.

But I have a couple of questions.

  1. Can I just use "ref string" as a parameter and have it work?
  2. If so, can I replace it with "out string"?
  3. In either cases, do I have to do any string/string length management?

  4. I currently pass a couple of callbacks in as "int". From an example I saw elsewhere, it looks like on the C# side, using this, I should be able to replace those parameters with Func for a callback such as Function A(p1 as String, p2 as Long, p3 as String) as Long

Any advice would be much appreciated.

1

There are 1 best solutions below

1
On

You need a combination of StrPtr, possibly StrConv on the Access side, and IntPtr on the .NET side:

        'VBA7    
        Private Declare PtrSafe Function Command Lib "External.dll" (ByVal CommandName As String, ByVal Result As LongPtr, ByRef ResultLength As Long) As Long
        'VBA pre7
            Private Declare Function Command Lib "External.dll" (ByVal CommandName As String, ByVal Result As Long, ByRef ResultLength As Long) As Long

'Example to use.
'Result will be up to "i" characters - no new string involved
            Dim i As Long, x As Long, strResult As String
            i = 100
            strResult = Space(i)
            x = Command(CommandName, Arguments, StrPtr(strResult), i)

If you use StrConv, the string type is up to you. If you don't, the pointer will be pointing to a Unicode array.

C# side:

    [DllExport("Command", CallingConvention.StdCall)]
    public static int Command(string commandName, string arguments, IntPtr result, out /*or ref*/ int resultLength)
{
       string inputStr = Marshal.PtrToStringUni(result); //Unicode
       resultLength = inputStr.Length;
       int x = MainFunc.Command(commandName, arguments, ref inputStr);
       if(null == inputStr)
       {
            inputStr = "";
       }
       if(inputStr.Length > resultLength)
       {
            inputStr = inputStr.Substring(0, resultLength);
        }
        byte[] outputBytes = Encoding.Unicode.GetBytes(inputStr);
        Marshal.Copy(outputBytes, 0, result, outputBytes.Length);
        resultLength = inputStr.Length;
        return x;
    }