Read a string from a pascal dll RRS feed

  • Question

  • Hi,

    Ik have a pascal dll which has a function that returns a Widestring.

    Now i want to use the dll in C# like this:

    [DllImport(@"Test.dll", CallingConvention = CallingConvention.StdCall)] public static extern string GetOne();

     private void button1_Click(object sender, EventArgs e)
                     textBox1.Text = GetOne();
                catch (Exception ex)
                    string tmp = "Just to read the exception when debugging";

    I get this warning: Test.exe has triggered a breakpoint.

    How to imprt a string from a Pascal DLL?

    Sunday, January 26, 2020 9:24 AM

All replies

  • - when widestring = unicode, perhaps you need to add  CharSet = CharSet.Unicode
    - when the dll was compiled for x86: your process needs to be compiled for x86, too
    - you DID use StdCall in your pascal compiler? when not, the stack will get corrupted

    Sunday, January 26, 2020 9:41 AM
  • Hi,

    this is my psacal code:

    library Test;
    {$mode objfpc}{$H+}
      { you can add units after this };
    function GetOne(): WideString; stdcall; export;
      Result := 'One';
    function GetNumber() : Integer; stdcall; export;
      Result := 1;
      GetOne, GetNumber;

    I use stdcall and i compile for Win64. Notice the GetNumber(); That works fine, in C# i get the number without warnings. The string function does not work. I tried at the pascal site widestring, string and  pchar. None seems to work.

    • Edited by HansvB69 Sunday, January 26, 2020 10:46 AM
    Sunday, January 26, 2020 10:37 AM
  • I'm not a pascal programmer but I suspect the problem may be related to returning a string literal from the dll.  The marshaling performed by P/Invoke knows how to handle unmanaged memory allocated by CoTaskMemAlloc and SysAllocString, but a string literal in an unmanaged dll is a different story.

    Try changing the C# DllImport of the GetOne function so that it returns an IntPtr.  Then you can manually marshal that IntPtr to a string with Marshal.PtrToStringUni.

    • Edited by RLWA32 Sunday, January 26, 2020 11:40 AM
    Sunday, January 26, 2020 11:39 AM
  • Sunday, January 26, 2020 11:48 AM
  • "Try changing the C# DllImport of the GetOne function so that it returns an IntPtr."

    I do not know how to do that.

    Sunday, January 26, 2020 1:39 PM
  • "Try changing the C# DllImport of the GetOne function so that it returns an IntPtr."

    I do not know how to do that.

    [DllImport(@"Test.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    public static extern IntPtr GetOne();


    IntPtr istr = GetOne();
    string str = Marshal.PtrToStringUni(istr);

    Sunday, January 26, 2020 1:48 PM
  • Delphi's WideString type is a counted string, where the first part contains the length of the string.  The documentation says it is compatible with a COM BSTR.  Thus, I think Marshal.PtrToStringBSTR is probably the right answer.

    But some experimentation will be required.

    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    Monday, January 27, 2020 6:51 PM
  • The observation about Delphi's data type made me curious so I did a quick test with the following

    extern "C" LPWSTR __stdcall GetOne()
    	return SysAllocString(L"One");

    and this was the result -

    Tuesday, January 28, 2020 3:00 PM
  • Any progress?
    Wednesday, February 5, 2020 3:30 PM