2013-03-07 19 views
8

funkcji DLL w C wygląda następująco:Wywołanie znaku * w C DLL obsługiwane jako ciąg w języku C#. Problem ze znakami NUL

int my_Funct(char* input, char* output); 

Muszę zadzwonić to od C# aplikacji. Zrobić to w następujący sposób:

...DllImport stuff... 
public static extern int my_Funct(string input, string output); 

Ciąg wejściowy jest doskonale przekazane do biblioteki DLL (mam widoczny dowód tego). Wynik działania funkcji wypełnia się, mimo że jest błędny. Mam dane hexa w nim, jak:

3F-D9-00-01 

ale niestety wszystko, co jest po dwóch zer jest cięty, a tylko dwa pierwsze bajty przyjść do mojego C# aplikacji. Zdarza się, ponieważ (jak sądzę) traktuje jako znak null i przyjmuje go jako koniec ciągu.

Każdy pomysł, jak mogę się go pozbyć? Próbowałem go określić jako IntPtr zamiast ciąg, ale nie wiem, co z nim zrobić później. że próbował wykonać po:

byte[] b1 = new byte[2]; 
Marshal.Copy(output,b1,0,2); 

2 powinna być zwykle długość tablicy bajtów. Ale dostaję wszelkiego rodzaju błędy: jak "Żądany zakres rozciąga się poza koniec tablicy." lub "Próba odczytu lub zapisu chronionej pamięci ..."

Doceniam każdą pomoc.

+0

(1) Ciągi C# są szersze niż char; mają szerokość 2 char zamiast 1. (2) Wartość char * zwracana przez tę funkcję nie będzie miała wymaganej dodatkowej struktury, która będzie poprawnym łańcuchem C# (nawet jeśli ma właściwą szerokość). –

+0

Musisz przeczytać na temat COM Interop i P/Invoke, aby dowiedzieć się, jak wykonać to działanie. Zrób to i oddzwoń, jeśli masz pytania na temat tego materiału. –

+0

Urządzenie pinvoke marshaller obsługuje tylko ciągi C. Oczywiście nie jest ciągiem C, gdy ma bajty, które mają znaczenie po 0. Jest to bajt []. Ale przy znaczącym rozłączeniu się nikt nie może zrozumieć, jak * wiele * bajtów jest istotnych. Ta funkcja jest bardzo trudna w użyciu również z kodu C, która nie poprawia się po jej przekręceniu. Lepiej to napraw. Użyj MarshalAs.SizeConst, jeśli długość jest przewidywalna. –

Odpowiedz

12

Niepoprawnie sortujesz ciąg wyjściowy. Używanie string w deklaracji p/invoke jest właściwe przy przekazywaniu danych z zarządzanego na natywny. Ale nie można tego użyć, gdy dane płyną w przeciwnym kierunku. Zamiast tego należy użyć StringBuilder. Tak:

[DllImport(...)] 
public static extern int my_Funct(string input, StringBuilder output); 

Następnie przydzielić pamięć dla wyjścia:

StringBuilder output = new StringBuilder(256); 
//256 is the capacity in characters - only you know how large a buffer is needed 

a następnie można wywołać funkcję.

int retval = my_Funct(inputStr, output); 
string outputStr = output.ToString(); 

Z drugiej strony, jeśli te parametry mają znaki puste w nich wtedy nie można zebrać jak struny. A to dlatego, że marshaller nie będzie sterował niczym poza wartością zerową. Zamiast tego musisz go ustawić jako tablicę bajtów.

public static extern int my_Funct(
    [In] byte[] input, 
    [Out] byte[] output 
); 

Który pasuje do Twojej deklaracji C.

Następnie zakładając ANSI kodowania przekonwertować ciąg wejściowy do tablicy bajtów tak:

byte[] input = Encoding.Default.GetBytes(inputString); 

Jeśli chcesz użyć innego kodowania, to oczywiste, jak to zrobić.

A dla wyjścia trzeba przydzielić tablicę. Zakładając, że to ta sama długość jak wejście byłoby to zrobić:

byte[] output = new byte[input.Length]; 

I jakoś czynność C ma znać długość tablic. Zostawię to tobie!

Następnie można wywołać funkcję

int retval = my_Funct(input, output); 

A potem przekonwertować tablicę wyjściowego z powrotem do C# ciąg ponownie wykorzystać klasę Encoding.

string outputString = Encoding.Default.GetString(output); 
+0

Dziękuję bardzo! Wersja [Out] byte [] ... działa !!! – user2124150

Powiązane problemy