Czy istnieje możliwość przekazania Tablicy lub Stringu jako argumentu do procedury napisanej w MASMie? Jeśli tak, to jak rozwiązać taki problem?
Procedura napisana w MASMie znajdowałaby się w osobnej bibliotece dll.
Normalny marshalling, tak jak przy komunikacji z C, C++ czy z Delphi.
Od strony C# wygląda to jak zwykła tablica albo string, a od strony natywnej jako wskaźnik.
Szczerze mówiąc, nigdy wcześniej nie zajmowałem się czymś takim. Wyszukałem taki przykład:
[DllImport("StringLib.Dll")]
public static extern void
PassLPWStr([MarshalAs(UnmanagedType.LPWStr)]String s);
gdzie:
UnmanagedType.LPWStr - A pointer to a null-terminated array of Unicode characters.
I dzięki temu dostane tablice zakończoną NULLem, po której w procedurze w MASMie mógłbym "poruszać się po znakach"?
I dzięki temu dostane tablice zakończoną NULLem, po której w procedurze w MASMie mógłbym "poruszać się po znakach"?
Dostaniesz wskaźnik do tablicy zakończonej znakiem\0
. W tej postaci tablica będzie tylko do odczytu, tj. istniejący string musi być przekazany z C#, a w MASMie nie powinieneś go modyfikować (a zmiany nie będą odzwierciedlone w C#).
LPWStr
oznacza stringa w UTF-16 (dwa bajty na znak).
Jeśli chcesz dostać zwykły tekst ASCII/ANSI (w bieżącej stronie kodowej) użyj LPStr
.
A co musiałbym zrobić, żeby zwrócić nowy napis? Napisałem coś takiego:
[DllImport("bibliotekaASM.dll", CallingConvention = CallingConvention.StdCall)]
private static extern String szyfruj([MarshalAs(UnmanagedType.LPStr)]String s1, [MarshalAs(UnmanagedType.LPStr)]String s2, int length_s1, int length_s2);
W masmie "edytuje" przekazaną jako parametr tablice, ale ta edycja nie jest widoczna po wyjściu z masma (String przekazany jako parametr pozostał bez zmian), ale gdy zwracam wskaźnik to w nowym Stringu mam właśnie te zedytowaną tablice:) I w sumie chciałbym tu zakończyć całą historie, ale pojawił się problem. Moj visual 2010 w wersji debug i w wersji release bardzo ładnie się zachowuje, tylko gdy uruchomię program za pomocą pliku exe w wersji release, to przy wykorzystaniu procedury z masma wyrzuca mi error:
An unhandled exception of type 'System.AccessViolationException' occurred in WindowsFormsApplication1.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Wie ktoś w czym może być problem?
Nie ma chyba dobrego sposobu na zwrócenie stringa, bo pojawia się problem kto (i jak, i kiedy) miałby zaalokować a potem zwolnić bufor.
Ale możesz przekazać StringBuilder
jako dodatkowy parametr.
Czyli coś takiego:
StringBuilder sb = new StringBuilder(256); // rozmiar bufora
funkcja_z_asma(coś, tam, sb, 256); // funkcja wypełnia bufor sb, więdząc że ma 256 znaków
String s = sb.ToString();
Rozumiem że sb też przesłać z pomocą marshallingu?
I czy wtedy sposób poruszania się po tablicy i szkic procedury mógłby wyglądać następująco?
nazwa proc uses EDI ESI ECX EDX EBX cos:dword, tam:dword, sb:dword, size:dword
mov ebx, sb
;poczatek petli
;edycja
mov [ebx], eax ; w eax wynik edycji
inc ebx
;koniec petli (wykonana 256 razy)
ret
nazwa endp
Edit: Zrealizowałem to w taki sosób:
Dllka w masmie na takiej samej zasadzie jak powyżej.
Sygnatura funkcji:
[DllImport("bibliotekaASM.dll", CallingConvention = CallingConvention.StdCall)]
private static extern void funkcja([MarshalAs(UnmanagedType.LPStr)]String s1, [MarshalAs(UnmanagedType.LPStr)]String s2, [MarshalAs(UnmanagedType.LPStr)]StringBuilder s3,int length_s1, int length_s2);
Wywołanie:
String text = this.richTextBox1.Text;
String klucz = this.richTextBox3.Text;
int length_text = this.richTextBox1.Text.Length;
int length_klucz = this.richTextBox3.Text.Length;
StringBuilder sb = new StringBuilder(length_text);
funkcja(text, klucz, sb, length_text, length_klucz);
this.richTextBox2.Text = sb.ToString();