Zacząłem aktualizować aplikację WinForms .NET 2.0 do .NET 4.0. No cóż, proces aktualizacji był tylko kwestią zamiany celu platformy, ale sprawił, że faktycznie działa. Sądziłem, że to wszystko.Czy środowisko P/Invoke zmieniło się w .NET 4.0?
Wygląda jednak na to, że coś zmieniło się drastycznie w .NET 4.0 w odniesieniu do współpracy. Używając DllImport(), aplikacja osadza kilka bibliotek dll Delphi. Gdy aplikacja jest przeznaczona dla .NET 2.0, wszystko działa normalnie. Ale kiedy zmieniłem go na docelowy .NET 4.0, rzeczy zaczynają szaleć, jak coś psuje pamięć.
Na przykład zamienia pojedyncze cyfry na "0" w dziwnych miejscach. Dane przekazane w IStream otrzymują 8 znaków zastąpionych (Hex) 00 00 00 00 00 00 80, ale tylko około 70% czasu. Dwa kolejne wywołania w celu pobrania tej samej wartości zwracają różne wyniki (pobieranie wartości z pamięci podręcznej w pamięci, udane za pierwszym razem, niepowodzenie po raz drugi). Ciągi wysyłane do dziennika są ucinane.
Próbowałem wiele rzeczy, próbując uczynić konwencje wywoływania bardziej wyraźnymi, żadna z nich nie ma żadnego efektu. Wszystkie ciągi są traktowane jako [MarshalAs (UnmanagedType.LPWStr)] po stronie .NET i PWChar po stronie Delphi.
Co zmieniło się w .NET 4.0, które złamałoby P/Invoke w ten sposób?
---------------------------- Edytuj ----------------- --------------------
Oto najprostszy przykład. To generuje plik PDF, który czasami działa poprawnie, ale częściej kończy się uszkodzony (i działa poprawnie w .NET 2.0):
[DllImport(DLLName)]
public static extern void SetDBParameters(
[MarshalAs(UnmanagedType.LPWStr)] string Server,
[MarshalAs(UnmanagedType.LPWStr)] string Database,
[MarshalAs(UnmanagedType.LPWStr)] string User,
[MarshalAs(UnmanagedType.LPWStr)] string Password,
short IntegratedSecurity);
procedure SetDBParameters(Server, Database, User, Password: PWChar;
IntegratedSecurity: WordBool); stdcall;
[DllImport(DLLName)]
public static extern short GeneratePDF(
[MarshalAs(UnmanagedType.LPWStr)] string Param1,
[MarshalAs(UnmanagedType.LPWStr)] string Param2,
[MarshalAs(UnmanagedType.LPWStr)] string Param3,
[MarshalAs(UnmanagedType.LPWStr)] string Param4,
out IStream PDFData);
function GeneratePDF(Param1, Param2, Param3, Param4: PWChar;
out PDFData: IStream): WordBool; stdcall;
private byte[] ReadIStream(IStream Stream)
{
if (Stream == null)
return null;
System.Runtime.InteropServices.ComTypes.STATSTG streamstats;
Stream.Stat(out streamstats, 0);
Stream.Seek(0, 0, IntPtr.Zero);
if (streamstats.cbSize <= 0)
return null;
byte[] result = new byte[streamstats.cbSize];
Stream.Read(result, (int)streamstats.cbSize, IntPtr.Zero);
return result;
}
WordBool i krótkie były pierwotnie logiczna (Delphi) i bool (C#), ja je zmienił być bardziej konkretnym, na wszelki wypadek.
---------------------------- Edytuj ----------------- --------------------
Wydaje się, że rzeczy, które napisałem wcześniej o WinFormach, okazały się nie całkiem odpowiednie, odtworzyłem jeden z problemów bez żadnego interfejsu użytkownika. Poniższy program generuje 0,1,2,3,4,5,6,7,8,9 pod 2,0/3,5, ale 0, -1, -1, -1, -1, -1, -1, - 1, -1 poniżej 4.0.
using System;
using System.Runtime.InteropServices;
namespace TestNet4interop
{
static class Program
{
[DllImport("TestSimpleLibrary.dll", PreserveSig=true, CallingConvention = CallingConvention.StdCall)]
public static extern void AddToList(long value);
[DllImport("TestSimpleLibrary.dll", PreserveSig=true, CallingConvention = CallingConvention.StdCall)]
public static extern int GetFromList(long value);
static void Main()
{
for (long i = 0; i < 10; i++)
{
AddToList(i);
Console.WriteLine(GetFromList(i));
}
}
}
}
i po stronie Delphi (skompilowane z Delphi 2007):
library TestSimpleLibrary;
uses
SysUtils,
Classes;
{$R *.res}
var
List: TStringList;
procedure AddToList(value: int64); stdcall;
begin
List.Add(IntToStr(value));
end;
function GetFromList(value: int64): integer; stdcall;
begin
result := List.IndexOf(IntToStr(value));
end;
exports
AddToList,
GetFromList;
begin
List := TStringList.Create;
end.
Może pokażesz nam podpis PInvoke? – JaredPar
Ten post http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/922fa431-5426-48c6-8949-538dfbb2f266 sugeruje, że przetaczanie uległ zmianie 4,0, ale nie zapewnia pełną listę co się zmieniło. –
Może interesujące wiedzieć: [Visual Studio 2010 SP1] (http://support.microsoft.com/kb/983509) nie ma ** ** rozwiązać ten problem, właśnie próbowałem go tutaj. –