3

I am calling a delphi function within a dll from c#. Here is the delphi function signature -

function CALinkDecode(sCode: PWideChar; SubscriberID, MailshotID, LinkID: PDWORD):
  PAnsiChar; stdcall;

And here is how i am calling it.

 string input = "qvoxyetvr7wksss2zbrmr";
        int cas, cam, cal;
        var errorString = CALinkDecode(input, out cas,
                                         out cam, out cal);

But when i run the app its evaluating this condition as true in delphi function -

if (sCode = nil) or (Length(sCode) <> 21) or (SubscriberID = nil) or (MailshotID = nil) or (LinkID = nil) then
begin
  Result := 'E_INVALIDARG';
end

I would just like to know if i am passing in the correct datatypes for the function signature and what is the correct way to do it. Thanks.

10
  • You could start by identifying which part of the predicate fails. You should also post the C# declaration. Commented May 26, 2013 at 9:19
  • @MarceloCantos Length(sCode) <> 21 is the predicate that fails. Commented May 26, 2013 at 9:35
  • Then what's in input? Commented May 26, 2013 at 9:36
  • @MarceloCantos Input is a pointer to a WideChar within a string and not the sting itself. Check answer. Commented May 26, 2013 at 9:37
  • @MarceloCantos string input = "qvoxyetvr7wksss2zbrmr"; Commented May 26, 2013 at 9:38

1 Answer 1

4

Your immediate problem is likely that you are passing ANSI text to the sCode parameter. Unfortunately you omitted your p/invoke declaration which would have made that clear.

That's easy to fix, but you have much bigger problems. This function is hard to call because it has been designed incorrectly. It's only viable if it returns constant strings that are allocated by the compiler rather than heap allocated strings. You could force it to work with that signature if you:

  1. Exported a deallocator function from the native code.
  2. Allocated the string using a shared heap, e.g. the COM heap.

It looks like you are returning COM error codes in string form. That's perverse. Instead you could make your life very easy by returning HRESULT.

Anyway, to answer the direct question you declare the p/invoke like this:

[DllImport(@"Mylib.dll", CharSet=CharSet.Unicode)]
static extern IntPtr CALinkDecode(
    string sCode,
    out uint SubscriberID,
    out uint MailshotID,
    out uint LinkID
);

Then call like this

IntPtr retvalptr = CALinkDecode(...);

Then marshal the pointer to a string

string retval = Marshal.PtrToStringAnsi(retvalptr);

But remember that this can only work if the returned string data is statically allocated. Otherwise you will have leaks, or access violations.

My primary advice is to redesign the interface. Don't return an error code in a string.

On a general note, if you must pass strings from Delphi to C# do it like this:

  • Declare an out parameter of type WideString in the Delphi code. This wraps a COM BSTR.
  • On the managed side declare an out parameter of type string. Decorate that parameter with [MarshalAs(UnmanagedType.BStr)].

Note that you cannot marshal a WideString return value to MS tools because Delphi uses a different ABI for return values. That's why you use an out parameter.

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

4 Comments

Here we go... I started answering this question on two separate occasions this morning, but eventually gave up on the full expectation that David's answer would show up at some point and trump everything.
@David Excellent. If i had to return an HRESULT, in my c# code, how would i call the function. In other words, to what type in c# would i map it or set it.
@David Heffernan. Sorry forgot to Thank you. Works like a charm. bows
@Styles Map HRESULT to uint or perhaps int. Signed integers are easier to work with in C# when you perform arithmetic. But with an HRESULT you usually are doing just comparisons and bit flag tests. So uint works fine.

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.