2011-11-23 109 views
2

另一个德尔福互操作问题中返回结构......C#调用DLL德尔福该结构

我有这样的Delphi代码:

library DelphiDll; 

uses 
    Dialogs, 
    SysUtils, 
    Classes; 

    type 
    TestEnum = (teOne, teTwo); 

    TTestRecord = record 
    end; 

    TTestType = record 
     MyTestRecords: array [1..255] of TTestRecord; 
     MyTestEnum: TestEnum; 
    end; 

    {$R *.res} 

    function DllFunction(var testType: TTestType): Boolean stdcall; export; 

    begin 
    testType.MyTestEnum := teTwo; 

    Result := True; 
    end; 

    exports DllFunction; 

    begin 
    end. 

而这个C#代码:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 

namespace DelpiDllTester 
{ 
    public enum TestEnum 
    { 
     One, 
     Two 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct TestType 
    { 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)] 
     public TestRecord[] MyTestRecords; 
     public TestEnum MyTestEnum; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct TestRecord 
    { 
    } 

    class Program 
    { 
     [DllImport("DelphiDll.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] 
     public static extern bool DllFunction(ref TestType testType); 

     static void Main(string[] args) 
     { 
      TestType testType = new TestType(); 
      bool dllFunctionResult = DllFunction(ref testType); 

      Console.WriteLine(dllFunctionResult); 
      Console.WriteLine(testType.MyTestEnum); 

      Console.ReadLine(); 
     } 
    } 
} 

当我运行C#代码时,testType.MyTestEnum的控制台输出始终是枚举值One,即使它在Delphi代码中明确设置为Two。

现在,如果我只是简单地将TestType结构中的TestRecord结构数组改为使用简单的整数数组,那么一切都很好。

为什么整数数组工作,但结构数组没有?

回答

3

主要问题是TTestRecord中没有定义内容。 C#代码编组为1的字段.Delphi编译器认为它的大小为0.因此两个结构之间存在不匹配。 C#代码为Marshal.SizeOf(typeof(TestType))返回260,而Delphi编译器为SizeOf(TTestType)返回8。

在真实的代码中,大概会在该记录中包含一些实际内容,当您这样做时,一切都将开始起作用。

请注意@JMarsch和@Ken White也提供了有效点。您需要确保枚举正确编组并且布局匹配。由于结构体被填充的方式,你可能在没有对枚举编组做任何事情的情况下离开,但是你也可能不幸运!

+0

Doh!你曾经有过这样的一段时间,你只是陷入了一种思考,似乎无法摆脱。我提供的代码是真实代码的一个修剪过的示例,但我没有注意到这样一个事实,即我的裁剪代码和空记录会导致这样的问题。再次感谢所有的评论。下次我会更加关注。 – meyousikmann

2

自从我使用Delphi(如'98)以来,这已经是整个其他生命周期了,但是,据我所知,Delphi中的枚举是1个字节的数字。在c#中的枚举是整数(32位)。

所以,你可以尝试定义你的C#枚举作为

enum TestEnum: byte {One, Two} 

这并不能说明问题是它如何与一个int数组工作。关于唯一可以想到的其他事情是确保c#enum的值与Delphi Enum的值完全匹配(所以使用teOne,teTwo),但由于我们实际上是在讨论整数/字节,我不明白这怎么重要。

+0

我也在想,都必须有如何枚举类型在C#中处理,而不是德尔福的问题。它实际上最终成为一个我忽略的更简单的问题。空记录一直是罪魁祸首。不过,感谢您的帮助。 – meyousikmann

2

您需要在Delphi代码中设置枚举大小。德尔福将尽可能小,但.NET方面预计int。以下添加到您的代码枚举声明之前:

{$MINENUMSIZE 4} // can also use {$Z4} but it's not clear later when 
        // you're trying to maintain the code. 
        // Or you can use {$Z-} and {$Z+}, for 
        // {$Z1} and {$Z4} respectively 

// Your enum declaration 

{$MINENUMSIZE 1} 
+0

看到我的答案。虽然这个问题是相关的,但房间里有一个更大的大象。 –

+0

我正在假设海报知道没有内容的记录不会起作用,并且这是用于解释目的的嘲弄代码。事实上,如果不是,海报试图在实际代码中使用无内容记录,那将是一个更大的大象。 (其实,重新阅读帖子下方的文字,我想你已经明白了 - 我认为它可能是**真实的代码,正如“改变...使用简单的整数数组”所表明的那样。赶上,并+1您的答案。) –

+0

我其实已经知道这一点,但我有这样的隧道视觉关于枚举,我看不到什么是坐在我的脸前。然而,我和你一样思考,由于空记录问题,这并没有解决我的问题。我无法摆脱我的思路。不过,感谢您的帮助。 – meyousikmann