3

我在 c# 的 dll 中调用 delphi 函数。这是delphi函数签名-

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

这就是我所说的。

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

但是当我运行应用程序时,它在 delphi 函数中将这个条件评估为 true -

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

我只想知道我是否为函数签名传递了正确的数据类型,以及正确的方法是什么。谢谢。

4

1 回答 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.

于 2013-05-26T11:45:25.710 回答