I have a Delphi DLL that I did not write, but need to call from a C# ASP.NET 3.5 app. Here is the function definition I got from the developers:
function CreateCode(SerialID : String; StartDateOfYear, YearOfStartDate, YearOfEndDate, DatePeriod : Word; CodeType,RecordNumber,StartHour,EndHour : Byte) : PChar; external 'CreateCodeDLL.dll';
And here is my C# code:
[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);
And finally, my call to this method:
//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);
Every time I re-compile this exact code and run it, it returns a different value. The expected value is a 10-digit code comprised of numbers. The returned value is actually 12 digits.
The last important piece of information is that I have a test .EXE that has a GUI that allows me to test the DLL. Every test using the .EXE returns the same 10-digit number (the expected result).
So, I have to believe that I have declared my call to the DLL incorrectly. Thoughts?
Delphi uses the so called fastcall calling convention by default. This means that the compiler tries to pass parameters to a function in the CPU registers and only uses the stack if there are more parameters than free registers. For example Delphi uses (EAX, EDX, ECX) for the first three parameters to a function.
In your C# code you’re actually using the stdcall calling convention, which instructs the compiler to pass parameters via the stack (in reverse order, i.e. last param is pushed first) and to let the callee cleanup the stack.
In contrast, the cdecl calling used by C/C++ compilers forces the caller to cleanup the stack.
Just make sure you’re using the same calling convention on both sides. Stdcall is mostly used because it can be used nearly everywhere and is supported by every compiler (Win32 APIs also use this convention).
Note that fastcall isn’t supported by .NET anyway.