-
Есть DLL, которая писана на delphi 7, и ее исходники. Там идет работа со строками, с памятью. Если функции из DLL возвращают PСhar на выделенную (кстати, чем надо выделять для совместимости с NET) память, то где и как надо (и надо ли) освобождать эту память? Какие соглашения о вызовах прописывать в экспортируемых функциях (stdcall, cdecl, др.)?
-
В MSDN по С# cм. CallingConvention для DllImportAttribute Пример из MSDN [DllImport("msvcrt.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] - поддерживается и соглашение StdCall,ThisCall,Winapi
Память выделить и удалить можно в вашей длл, одна функция выделяет память и возвращает указатель. Другая освобождает память. Ее конечно надо будет вызвать, как отпадет необходимость в в блоке памяти. Второй вариант - функции передается указатель на уже выделенную в NET коде память и размер, если памяти не хватает, возвращается соответствующий код ошибки.
-
спасибо 2-й вариант меня больше устраивает
Только вот чем выделять память в C#, чтоб она была совместима с менеджером памяти в DLL, передаваясь как PChar?
-
Просто массив например, правда при преобразовании в указатель надо использовать команду fixed что бы массив не перемещался в памяти,или явно используя стек, в этом случае gc не убирает блок памяти, а он освобождается при выходе из области видимости блока, в котором распределялась память. Запросить память из стека например char *name=stacalloc char [256]
В MSDN есть примеры по словам stacalloc и слову fixed, написано коротко и как раз для обоих вариантов:-)
-
Попробовал со stackalloc. С char не получилось, выкрутился с byte. Передается в DLL все нормально. Назад вроде тоже должно возвращать в выделенную память, но что-то не получается. Перед выходом из DLL поставил отладочную печать - показывает верно записанные (в выделенную извне память) данные. А в самом C# уже показывает, что начальный байт равен 0, хотя таким быть не должен. Вот пример кода вызова: [DllImport( "f32.dll", EntryPoint="s2lp", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall )]
unsafe private static extern Int32 s2lp( Byte* l1, Byte* l2, Byte* p2 );
unsafe private void button1_Click( object sender, EventArgs e )
И вот здесь в цикл не входит :( В дельфи функция описана как function s2lp( l1, l2, p2: PChar ): Cardinal; stdcall; В чем может быть затык?
-
> С char не получилось, выкрутился с byte.
Я просто не совсем правильно сказал, тип char в дельфи и тип сhar в с# - разные типы. Так что тип байт более близкий к char или sbyte.
По коду - ( *( cL2 + i ) ).ToString(); - не даст вам букву А например, а даст ее код 61. Почему не входит в цикл -сказать трудно, если вы пишете, что в память действительно написано, что надо.... ???
Вот еще варианты безопасного кода, в массив b возвращается строка из реестра, которая потом преобразуется в строку C# объявление всех переменных тут не привожу
[DllImport("Advapi32.dll",SetLastError=true)] public static extern IntPtr RegQueryValueEx(IntPtr key,string valueName,IntPtr Reserv,out uint lptype,ref byte lpdata,ref uint lpsize);
byte [] b=new byte[1024];
int l=b.Length;
Decoder d=Encoding.Unicode.GetDecoder();
int k1=RegQueryValueEx(k,s1,ref t,ref b[0],ref l); char[] chars=new char[l+1]; d.GetChars(b,0,(int)l,chars,0); string s=new string(chars); //**********************
-
Нашел ошибку. В DLL просто присваивал pIn := PAnsiChar( str ) а надо было копировать память.
> По коду - ( *( cL2 + i ) ).ToString(); - не даст вам букву А например, а даст ее код 61 Но как из байтов получить символы?
-
См. класс Decoder, возможно может выглядеть так
byte [] b - массив куда получили байты
Decoder d=Encoding.ASCII.GetDecoder();
char[] chars=new char[размер строки]; d.GetChars(b,0,размер строки-1,chars,0); string s=new string(chars);
или еще упростить
string s=new string(d.GetChars(b));
-
Вообще написал неверно [7], извиняюсь char [] chars;
byte [] b1=new byte[3] ;
Encoding e1=Encoding.Unicode;
byte [] unicbyte=Encoding.Convert(Encoding.GetEncoding(1251),e1,b1);
chars=new char[unicbyte.Length];
e1.GetChars(unicbyte,0,unicbyte.Length,chars,0);
MessageBox.Show(new string(chars),"Test"); Вот пример написал, думаю переделать будет не сложно
-
спасибо, все получилось
-
stdcall в DllImport по умолчанию, явно можно не вызывать.
А вот как dll загружается в С# - статически или динамически? Было бы не плохо и так и этак.
-
Судя по литературе (насколько я понял) - динамически. Загрузка происходит при первом обращении к длл. Да и из поведения программы это следует. Можно указать несуществующую длл, но ошибка возникнет только при обращении к функции длл.
-
А в юникод обязательно переводить? А то у меня база в win1251, dll туда же.
-
А как передать в dll число??? В делфях MyProc (var LLength : byte); в С#
byte PBuffer = 20;
....
MyProc (PBuffer);
При трассировке dll значение PBuffer не передаётся. Делфя пишет IV.
-
Что-то я так и не понял, как из byte* получить string без всяких перекодировок. Encoding.Convert последним параметром просит byte[], а у нас byte*. ToString выдаёт byte. Опять не совместимость.
-
чёрт, не выходит На делфях
var
edLogin, edPassword : WideString;
.....
procedure PostInfo (aLogin, aPassword : PWideChar; var LLength, PLength : byte); stdcall;
begin
if (aLogin = nil) or (aPassword = nil) then exit;
LLength := Length (edLogin);
Move (edLogin[1], aLogin[0], LLength);
PLength := Length (edPassword);
Move (edPassword[1], aPassword[0], PLength);
MessageBoxW (0, PWideChar (edLogin), PWideChar (edPassword), MB_OK);
MessageBoxW (0, aLogin, aPassword, MB_OK);
end; на C#
[DllImport("bin/OJRes", CallingConvention = CallingConvention.StdCall)]
unsafe private static extern void PostInfo(
char* Login,
char* Password,
ref byte LLength,
ref byte PLength);
unsafe public static void postinfo(string Login, string Password)
catch
Main_Form.Login = new string(aLogin, 0, LLength);
Main_Form.Password = new string(aPassword, 0, PLength);
} Первый MessageBox показывает всё правильно, второй - ровно половину. Т.е. если ввести 1234567890, то будет 12345 (остальное \0). Где теряется? Может память не так выделяется?
-
Дико извиняюсь, но проблема не в net.
Если не лень, удалите [13]-[16].
|