-1

This is my first question here. I'm also new to programming, so I'll do my best to make it as clear as possible.

There's this DLL that was originally written in Delphi. One of its functions requires an int (Integer in Delphi) as its argument and in turn returns a string (PWideChar in Delphi).

The DLL documentation does not bring many details, so I'm trying to explore different possibilities in order to get the proper results. Also, there's no issue with the DLL, as I'm able to successfully call this function from Python by using restype. E.g.:

DLLName.FunctionName.restype = c_wchar_p 

When I call the callback function below from C# (5.0) though, I'm able to see something whenever I use any number type, being that either sbyte, int or long, for example. However, I get an error when I try to use string, which I'd think would be the appropriate data type to be placed as its return data type:

[DllImport(dll_path, CallingConvention = CallingConvention.StdCall)]
    public static extern sbyte GetNameByID(int nID);

This was my first trial:

public static string GetName()
    {   
       string result = GetNameByID(1)
       return result;
    }

But, as I mentioned, I'd only see something being returned when I use numerical data types instead of string. I also (naively) gave it a trial with .ToString() or casting the result with (string)...


SOLUTION AFTER INVESTIGATION:

For those that may be facing similar issues, this is how the issue was solved, after some tentatives to figure it out:

The function call returns a pointer, so:

    [DllImport(dll_path, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr GetNameByID(int nID);

And then, when hadling its return, marshalling the pointer to Unicode string:

public static string GetName()
    {   
       string result = Marshal.PtrToStringUni(GetNameByID(1)));
       return result;
    }
5
  • 1
    Who is responsible for the memory that the DLL function returns a pointer to? If the caller is responsible for freeing the memory, that will complicate the C# code a bit, as you would have to use IntPtr for the return value, and then marshal the character data manually. Commented Nov 21, 2021 at 0:05
  • 1
    We need to see how the Delphi code is allocating the string. If it uses SysAllocString then BStr will work fine. But it may not be doing that. Commented Nov 21, 2021 at 1:57
  • Hi @RemyLebeau, there are a couple of other functions in this DLL in which IntPtr needed to be used, but that's not the case of this specific one. It returns a string with less then 10 characters. Commented Nov 21, 2021 at 3:18
  • @roccaforte the length of the string doesn't matter. The way the string is allocated matters greatly. Commented Nov 21, 2021 at 5:21
  • We can't answer this until we see the Delphi code and there learn how the memory is managed for the return value Commented Nov 21, 2021 at 9:12

1 Answer 1

0

I had a similar problem using a C++ DLL. Maybe this will work in your case as well:

[DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string getNameById(int nID);

public static string GetName()
{
    string result = GetNameByID(1);
    return result;
}

EDIT: Found this link with a similar issue already on stack overflow.

Sign up to request clarification or add additional context in comments.

9 Comments

CharSet.Ansi is not compatible with Delphi's PWideChar. And UnmanagedType.BStr requires a COM BSTR, which Delphi strings are not. Use UnmanagedType.LPWStr instead.
Hello Jakub. Thanks for helping. This gave me some direction, as a matter of fact. However, the application suddenly closes and it has been difficult to track what is happening, as there is no exception being raised and I can't see any specific errors. What @RemyLebeau mentioned also helped a lot, as UnmanagedType.LPWStr seems to be the correct one to use. Unfortunately, I'm not sure where to go from here. I know that's an open question: do you have any idea on what may be happening? It's quite tricky, as I can do it with Python with no issues.
Just complementing: the application started to suddenly close after making the changes you suggested accordingly. This happens with both UnmanagedType.Bstr and UnmanagedType.LPWStr. I also tried to use a StringBuilder instead of string itself, with no success though.
@roccaforte do you have any Delphi code for the DLL? Either the implementation itself, or at least a demo? If not, any document, at least? You are leaving out a lot of important details that matter when interfacing with a native DLL in C#.
@roccaforte I found a link to a similar issue, posted it on this answer.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.