当前位置:  开发笔记 > 编程语言 > 正文

从C#调用Delphi DLL会产生意外结果

如何解决《从C#调用DelphiDLL会产生意外结果》经验,为你挑选了2个好方法。

我有一个我没有编写的Delphi DLL,但需要从C#ASP.NET 3.5应用程序调用.这是我从开发人员那里得到的函数定义:

function CreateCode(SerialID : String; 
    StartDateOfYear, YearOfStartDate, YearOfEndDate, DatePeriod : Word; 
    CodeType,RecordNumber,StartHour,EndHour : Byte) : PChar;
    external 'CreateCodeDLL.dll';

这是我的C#代码:

[DllImport( "CreateCodeDLL.dll", 
    CallingConvention = CallingConvention.StdCall, 
    CharSet=CharSet.Ansi)]
public static extern IntPtr CreateCode( string SerialID,
                                        UInt16 StartDateOfYear,
                                        UInt16 YearOfStartDate,
                                        UInt16 YearOfEndDate,
                                        UInt16 DatePeriod,
                                        Byte CodeType,
                                        Byte RecordNumber,
                                        Byte StartHour,
                                        Byte EndHour);

最后,我对这个方法的调用:

//The Inputs 
String serialID = "92F00000B4FBE";
UInt16 StartDateOfYear = 20;
UInt16 YearOfStartDate = 2009;
UInt16 YearOfEndDate = 2009;
UInt16 DatePeriod = 7;
Byte CodeType = 1;
Byte RecordNumber = 0;
Byte StartHour = 15;
Byte EndHour = 14;            

// The DLL call
IntPtr codePtr = CodeGenerator.CreateCode(serialID, StartDateOfYear, 
                YearOfStartDate, YearOfEndDate, DatePeriod, CodeType, 
                RecordNumber, StartHour, EndHour);

// Take the pointer and extract the code in a string
String code = Marshal.PtrToStringAnsi(codePtr);  

每次我重新编译这个确切的代码并运行它,它返回一个不同的值.期望值是由数字组成的10位数代码.返回的值实际上是12位数.

最后一个重要的信息是我有一个测试.EXE,它有一个允许我测试DLL的GUI.使用.EXE的每个测试都返回相同的10位数字(预期结果).

所以,我必须相信我已经错误地声明了我对DLL的调用.思考?



1> newgre..:

Delphi 默认使用所谓的fastcall调用约定.这意味着编译器尝试将参数传递给CPU寄存器中的函数,并且如果参数多于空闲寄存器,则仅使用堆栈.例如,Delphi使用(EAX,EDX,ECX)作为函数的前三个参数.
在您的C#代码中,您实际上正在使用stdcall调用约定,该约定指示编译器通过堆栈传递参数(以相反的顺序,即先推送最后一个参数)并让被调用者清理堆栈.
相反,C/C++编译器使用的cdecl调用强制调用者清理堆栈.
只要确保你在双方都使用相同的调用约定.Stdcall主要用于因为它几乎可以在任何地方使用,并且每个编译器都支持它(Win32 API也使用此约定).
请注意,.NET不支持fastcall.


请注意,"fastcall"在不同的上下文中表示不同的内容.微软的版本与Embarcadero的版本不同,我怀疑GCC与它们的不同之处.在Delphi中,调用约定甚至不称为"fastcall"; 这是"注册"调用约定.

2> Barry Kelly..:

jn是对的.给定的函数原型不能直接从C#中调用,只要它在Delphi的register调用约定中即可.您需要stdcall为它编写包装函数 - 如果您没有源代码,可能在另一个DLL中 - 或者您需要让维护该函数的人员将其调用约定更改为stdcall.

更新:我还看到第一个参数是Delphi字符串.这不是C#可以提供的东西.应该是PChar而不是.此外,重要的是要明确该函数是Ansi还是Unicode; 如果DLL是用Delphi 2009(或更高版本)编写的,那么它是Unicode,否则它是Ansi.

推荐阅读
mobiledu2402852413
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有