вызов Delphi DLL из C # - PullRequest
       17

вызов Delphi DLL из C #

1 голос
/ 12 июня 2010

У меня есть Delphi dll, определенная так:

TMPData = record
 Lastname, Firstname: array[0..40] of char;
 Birthday: TDateTime;
 Pid: array[0..16] of char;
 Title: array[0..20] of char;
 Female: Boolean;
 Street: array[0..40] of char;
 ZipCode: array[0..10] of char;
 City: array[0..40] of char;
 Phone, Fax, Department, Company: array[0..20] of char;
 Pn: array[0..40] of char;
 In: array[0..16] of char;
 Hi: array[0..8] of char;
 Account: array[0..20] of char;
 Valid, Status: array[0..10] of char;
 Country, NameAffix: array[0..20] of char;
 W, H: single;
 Bp: array[0..10] of char;
 SocialSecurityNumber: array[0..9] of char;
 State: array[0..2] of char;
end;   

function Init(const tmpData: TMPData; var ErrorCode: integer; ResetFatalError: boolean = false): boolean;

procedure GetData(out tmpData: TMPData);

Мои текущие сигнатуры c # выглядят так:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TMPData
{            
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)]
    public string Lastname;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)]
    public string Firstname;
    [MarshalAs(UnmanagedType.R8)]
    public double Birthday;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 16)]
    public string Pid;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)]
    public string Title;
    [MarshalAs(UnmanagedType.Bool)]
    public bool Female;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)]
    public string Street;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 10)]
    public string ZipCode;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)]
    public string City;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)]
    public string Phone;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)]
    public string Fax;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)]
    public string Department;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)]
    public string Company;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 40)]
    public string Pn;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 16)]
    public string In;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 8)]
    public string Hi;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)]
    public string Account;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 10)]
    public string Valid;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 10)]
    public string Status;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)]
    public string Country;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 20)]
    public string NameAffix;
    [MarshalAs(UnmanagedType.I4)]
    public int W;
    [MarshalAs(UnmanagedType.I4)]
    public int H;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 10)]
    public string Bp;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 9)]
    public string SocialSecurityNumber;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = 2)]
    public string State;
}

[DllImport("MyDll.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Init(TMPData tmpData, int ErrorCode, bool ResetFatalError);

[DllImport("MyDll.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetData(out TMPData tmpData);

Сначала я вызываю Init, устанавливая BirthDay, LastName и FirstName.Затем я вызываю GetData, но полученная структура TMPData неверна.Поля FirstName, LastName и Birthday заполнены, но данные неверны.Является ли отображение правильным?("массив [0..40] символа" равен "[MarshalAs (UnmanagedType.LPStr, SizeConst = 40)]")?

Обновление:

Я обновил сопоставление c #с обратной связью, которая будет выглядеть следующим образом:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct TMPData 
{             
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Lastname; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Firstname; 
    [MarshalAs(UnmanagedType.R8)] 
    public double Birthday; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] 
    public string Pid; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Title; 
    [MarshalAs(UnmanagedType.Bool)] 
    public bool Female; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Street; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string ZipCode; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string City; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Phone; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Fax; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Department; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Company; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)] 
    public string Pn; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] 
    public string In; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)] 
    public string Hi; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Account; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Valid; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Status; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Country; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string NameAffix; 
    [MarshalAs(UnmanagedType.I4)] 
    public int W; 
    [MarshalAs(UnmanagedType.I4)] 
    public int H; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] 
    public string Bp; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] 
    public string SocialSecurityNumber; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)] 
    public string State; 
} 

Функция Init:

[DllImport("MyDll.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
public static extern bool Init(TMPData tmpData, int ErrorCode, bool ResetFatalError); 

теперь завершается ошибкой со следующей ошибкой:

"Попытка чтения или записи защищенапамять. Это часто указывает на то, что другая память повреждена.

, когда я вызываю ее, как показано ниже:

int errorCode = 0;
bool resetLastError = true;
TMPData tmpData = new TMPData();

        tmpData.Lastname = "TestLastName";
        tmpData.Firstname = "TestName";
        tmpData.Birthday = 28856.0;
        tmpData.Pid = "12345678";
        tmpData.Title = null;
        tmpData.Female = false;
        tmpData.Street = null; 
        tmpData.ZipCode = null;
        tmpData.City = null;
        tmpData.Phone = null;
        tmpData.Fax = null;
        tmpData.Department = null; 
        tmpData.Company = null;
        tmpData.Pn = null;
        tmpData.In = null;
        tmpData.Hi = null;
        tmpData.Account = null;
        tmpData.Valid = null;
        tmpData.Status = null;
        tmpData.Country = null;
        tmpData.NameAffix = null;
        tmpData.W = 0;
        tmpData.H = 0;
        tmpData.Bp = null;
        tmpData.SocialSecurityNumber = 0;
        tmpData.State = null;

bool success = Init(tmpData, errorCode, resetLastError);    

Если я изменю ByValTStr на LPStr в определении структуры, тогда Initфункция завершается успешно, но функция GetData возвращает неверные строковые значения. Если я изменяю LPStr обратно на ByValTStr, функция Init завершается ошибкой, но функция GetData возвращает правильные строки. Я не уверен, стоит ли маршалировать массив [0..x] char как LPStrByValTStr?

Ответы [ 3 ]

1 голос
/ 23 июня 2010

ладно, наконец-то все заработало.спасибо за помощь.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]  
public struct TMPData  
{              
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]  
    public string Lastname;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]  
    public string Firstname;  
    [MarshalAs(UnmanagedType.R8)]  
    public double Birthday;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]  
    public string Pid;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]  
    public string Title;  
    [MarshalAs(UnmanagedType.Bool)]  
    public bool Female;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]  
    public string Street;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]  
    public string ZipCode;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]  
    public string City;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]  
    public string Phone;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]  
    public string Fax;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]  
    public string Department;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]  
    public string Company;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]  
    public string Pn;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)]  
    public string In;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]  
    public string Hi;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]  
    public string Account;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]  
    public string Valid;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]  
    public string Status;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]  
    public string Country;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]  
    public string NameAffix;  
    [MarshalAs(UnmanagedType.R4)]  
    public int W;  
    [MarshalAs(UnmanagedType.R4)]  
    public int H;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]  
    public string Bp;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]  
    public string SocialSecurityNumber;  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]  
    public string State;  
}  

[DllImport("MyDll.dll")]         
[return: MarshalAs(UnmanagedType.Bool)]         
public static extern bool Init(ref TMPData tmpData,ref int ErrorCode, bool ResetFatalError);         

[DllImport("MyDll.dll")]         
[return: MarshalAs(UnmanagedType.Bool)]         
public static extern bool GetData(ref TMPData tmpData);    
0 голосов
/ 15 июня 2010

Из какой версии Delphi собирается DLL? В Delphi 2009 был введен Unicode , что означало бы, что вам нужно будет использовать строковый тип Unicode в C #, а если это будет до Delphi 2009, тогда Unicode не будет. LPStr равен 8 битам , а тип символов ByValTStr определяется аргументом System.Runtime.InteropServices.CharSet в System.Runtime.InteropServices.StructLayoutAttribute, применяемом к содержащейся структуре.

См .: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.unmanagedtype.aspx

Вы изначально сказали, что получаете данные обратно, но это было неверно. Как было неправильно? Мусор или просто поменялся местами, усеченный и т. Д.?

0 голосов
/ 12 июня 2010

Как упомянул в своем комментарии dtb, 0..40 - это 41 символ, а не 40. Очевидно, что все ваши определения строк не учитывают 0-й элемент.

Кроме того, если я правильно читаю, (я не знаю C #, но я знаю C), похоже, что вы определяете массивы char как указатели на long (Unicode, 16 бит на символ) ) строки. Есть две потенциальные проблемы с этим. Во-первых, массив символов, объявленный таким образом, не является указателем на строку, это встроенная строка. Во-вторых, это всего лишь массив WideChars (16 бит на символ), если он был создан с версией Delphi 2009 или более поздней. В противном случае это массив символов Ansi (8 бит на символ).

...