访问德尔福DLL抛出异常ocasional [英] Accessing Delphi DLL throwing ocasional exception

查看:113
本文介绍了访问德尔福DLL抛出异常ocasional的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我打电话有时抛出一个异常一个DLL的方法,有时没有。

When I'm calling a Dll method it sometimes throws an exception, and sometimes doesn't.

我打电话是这样的:

public class DllTest
{

    [DllImport(@"MyDll.dll")]
    public extern static string MyMethod(string someStringParam);
}


class Program
{       

    static void Main(string[] args)
    {
        DllTest.MyMethod("SomeString");
    }
}

和的例外,我得到的有时是这样的:

And the exception I get sometimes is this:


AccessViolationException

AccessViolationException

尝试读取或写保护的内存。这通常是指示其他内存已损坏。

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

有没有人有任何想法,为什么我只得到这个异​​常的有时的?为什么它运行顺利,有时?

Does anyone have any idea why I only get this exception sometimes? Why does it run smoothly sometimes?

推荐答案

您已经清楚在P之间的不匹配/调用代码和Delphi代码。您还没有表现出德尔福代码,但C#代码,就足以知道Delphi代码应该是什么样子。

You clearly have a mismatch between the p/invoke code and the Delphi code. You have not shown the Delphi code but the C# code is enough to know what the Delphi code should look like.

的DllImport 属性使用默认值调用约定和字符集。这意味着该调用约定 STDCALL 和字符集是ANSI。您还没有指定任何编组属性必须被使用,因此默认编组

Your DllImport attribute uses default values for calling convention and character set. This means that the calling convention is stdcall and the character set is ANSI. You have not specified any marshalling attributes so default marshalling must be used.

所以你的Delphi代码必须是这样的:

Therefore your Delphi code must look like this:

function MyMethod(someStringParam: PChar): PChar; stdcall;
begin
  Result := ??;
end;



而现在这里的问题。在一个非常特殊的方式的P / Invoke编组把一个字符串返回值。它假定它是p的责任/调用编组,以释放返回值的内存。并且它具有使用相同的分配器的本机代码。由编组作出的假设是共享的COM分配器将被使用。

And now here's the problem. The p/invoke marshaller treats a string return value in a very special way. It assumes that it is the responsibility of the p/invoke marshaller to deallocate the return value's memory. And it has to use the same allocator as the native code. The assumption made by the marshaller is that the shared COM allocator will be used.

因此​​,规则是,本机代码必须通过调用分配与COM分配器的存储器 CoTaskMemAlloc 。我敢打赌,你的代码没有做到这一点,这肯定会导致错误。

So the rule is that the native code must allocate the memory with the COM allocator by calling CoTaskMemAlloc. My bet is that your code does not do that and that will certainly result in errors.

下面是你如何做一个本地的Delphi功能,能够随着工作的例子在你的代码的C#签名。

Here is an example of how you could make a native Delphi function that works with the C# signature in your code.

function MyMethod(someStringParam: PChar): PChar; stdcall;
var
  Size: Integer;
begin
  Size := SizeOf(Char)*(StrLen(someStringParam)+1);//+1 for zero-terminator
  Result := CoTaskMemAlloc(Size);
  Move(someStringParam^, Result^, Size);
end;






虽然你可以采用这种方式,我建议替代。元帅您的所有字符串为 BSTR 上的德尔福侧C#侧和 WideString的。这些匹配其也由COM分配器分配类型。双方都知道该怎么做这些类型,将让您的生活更轻松。


Whilst you could adopt this approach I recommend an alternative. Marshal all your strings as BSTR on the C# side and WideString on the Delphi side. These are matching types which are also allocated by the COM allocator. Both parties know exactly what to do with these types and will make your life easier.

不幸的是,你不能返回一个 WideString的来自全国各地的互操作边界德尔福功能,因为Delphi使用了不同的ABI函数返回值。这个问题的更多细节可以在我的问题发现为什么一个WideString的不作为互操作的函数的返回值?

Unfortunately, you cannot return a WideString from a Delphi function across an interop boundary because Delphi uses a different ABI for function return values. More details of this issue can be found in my question Why can a WideString not be used as a function return value for interop?

因此,要解决这一点,我们可以从Delphi代码声明的返回类型为 TBStr 。然后,您的代码是这样的:

So to work around that, we can declare the return type from the Delphi code to be TBStr. Your code would then look like this:

C#

[DllImport(@"MyDll.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string MyMethod(
    [MarshalAs(UnmanagedType.BStr)]
    string someStringParam
);



德尔福

function MyMethod(someStringParam: WideString): TBStr; stdcall;
begin
  Result := SysAllocString(POleStr(someStringParam));
end;

这篇关于访问德尔福DLL抛出异常ocasional的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆