obsługa stringów z dll do MQL

O jezykach programowania w platformach i nie tylko.
259
Maniak
Maniak
Posty: 3968
Rejestracja: 15 cze 2011, 23:20

obsługa stringów z dll do MQL

Nieprzeczytany post autor: 259 »

Witam,

Mam taki upierdliwy problem: jak wyrzucić obrobiony string z mojego dll do MQL bez wywalenia tego drugiego lub pisania do obszaru pamięci którym nikt tak naprawdę nie zarządza?

Np w dll:

Kod: Zaznacz cały

MT4_EXPFUNC char* __stdcall mojString(char* input1, char* input2)
{
	char *test;
	strcpy(test, input);
	strcat(test, input2);
	return test;
}
W MQL:

Kod: Zaznacz cały

Print (mojString("poniedzialek|", "_______wtorek"));
To wydaje się działać w MQL. Ale... wcale nie do końca bo jak weźmie się długie stringi to wyniki są dziwne. Głównie dlatego, że jak podejrzewam oddaję do MQL wskaźnik który wskazuje... no właśnie co? Brakuje mi alokacji pamięci.
Teoretycznie mógłbym alokować ją w kodzie dll ale to jest błąd, bo po wykonaniu kodu taki obszar staje się śmieciem? Teraz też to wygląda na śmieć, tyle że istniejący w wolnej przestrzeni... zgadza się?

W zasadzie powinienem chyba podać wyjście jako parametr. Wtedy MQL alokuje pamięć i teoretycznie wszystko powinno być ok. Ale nie działa tak jakbym się spodziewał:

Np. dll:

Kod: Zaznacz cały

MT4_EXPFUNC void __stdcall mojString(char* input, char* input2, char* output)
{
	char *test;
	strcpy(test, input);
	strcat(test, input2);
	strcpy(output, test);
}
W MQL:

Kod: Zaznacz cały

string output ="                          ";
mojString("poniedzialek|", "_______wtorek", output); // tak, tak, string& output w imporcie... jedyna forma wskaźnika w MQL ;-)
Print (output);
Ale kończy się to zwyczajnie błędem dll i string output nie zawiera nic... hmm, a może znów brak alokacji dla *test więc strcpy się wywala bo nie ma gdzie pisać?
Próbowałem też z tablicami ale to kończyło się wyparowaniem MT4...

Ale coś takiego też nie działa:

Kod: Zaznacz cały

MT4_EXPFUNC void __stdcall mojString(char* input, char* output)
{
	strcpy(output, input);
}
Nawet jak dopilnuje się długości obu stringów żeby były takie same. Prościej już się nie da.

Jak to w ogóle ugryźć?
Ja chcę "tylko" przekazać c_string do dll (ciąg znaków zakończony NULL o dowolnej długości, takich używa MQL) i dostać z powrotem obrobiony c_string, zazwyczaj o innej długości.
Jakże często ludzie mają już gotową opinię zanim zdążą pojąć istotę rzeczy.
A gdy już ta istota w pełni do nich dotrze, jakże często muszą zmagać się z konsekwencjami swojej opinii ;-)

Awatar użytkownika
reptile
Maniak
Maniak
Posty: 2799
Rejestracja: 13 gru 2008, 13:48

Nieprzeczytany post autor: reptile »

Pomyśl o kodowaniu stringa.
MT4 programuja rosjanie.. ASCII i od poczatku jest z tym problem.
zrob maly test z przekodowaniem,przerabiaelm takie cos z mysql
R.E.P.T.I.L.E. - Robotic Electronic Person Trained for Infiltration and Logical Exploration (off-line,only e-mail)

Awatar użytkownika
Esco
Przyjaciel Forum
Przyjaciel Forum
Posty: 2603
Rejestracja: 11 kwie 2010, 20:56

Nieprzeczytany post autor: Esco »

A może WinAPI - alokowanie pamięci, skopiowanie stringa wewnątrz MQL a później przekazanie wskaźnika do DLL?

W druga stronę odwrotnie z dopilnowaniem ArrayResize na długość wyjściowego z DLL.

259
Maniak
Maniak
Posty: 3968
Rejestracja: 15 cze 2011, 23:20

Nieprzeczytany post autor: 259 »

Znalazłem:

Po pierwsze wyjście funkcji: char* mojString() jest ok - MQL alokuje sobie automatycznie do 64k i przekopiuje tam ten string :-)

Po drugie wejście i dalsza obróbka: char* input jest ok, ale dalej do obróbki trzeba zrobić sobie dodatkowy buforek i wskaźnik do tego buforka przekazać na zewnątrz. Nie zapominając o tym, żeby na samym końcu go zwolnić - inaczej za każdym wywołaniem będą przyrastać śmieci.

string c++ jest rzeczywiście przydatny i łatwo robi się stringi z c stringów. W drugą stronę jest mała ale istotna pułapka: string.c_str() generuje co prawda c string ale NIE NALEŻY go bezpośrednio używać:
The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only guaranteed to remain unchanged until the next call to a non-constant member function of the string object.
W praktyce oznacza to wyparowanie terminala gdyby zrobić tak:

Kod: Zaznacz cały

return (char*)output.c_str();
:-D

Trzeba przekopiować wygenerowany string do następnego buforka.
np:

Kod: Zaznacz cały

MT4_EXPFUNC char* __stdcall mojString(char* input1, char* input2)
{
	using namespace std;
	
	string input_str1 = string (input1);// tworzy c++ string z c string;
	string input_str2 = string (input2);
	
	// teraz można się pobawić stringami... powiedzmy:
	
	string output_str;
	output_str.append(input_str1);
	output_str.append(" ");
	output_str.append(input_str2);

	// i teraz wyjście, po pierwsze trzeba mieć buforek na wyściowy c string:
	
	char* out = new char[output_str.size()+1]; // trzeba dodać jedno miejsce na NULL
	
	// i dopiero teraz wygenerować i przekopiować wyjściowy c string:
	
	strcpy(out, output_str.c_str());

	return out;
}
To jest uproszczone, np. nie dealokuje tymczasowych buforów ale to już pestka żeby to wsadzić gdzie należy.

Uff, ale się nad tą głupotą namęczyłem... a wszystko poszło o brak spójnej dokumentacji, szczególnie ze strony Metaquotes.
Jakże często ludzie mają już gotową opinię zanim zdążą pojąć istotę rzeczy.
A gdy już ta istota w pełni do nich dotrze, jakże często muszą zmagać się z konsekwencjami swojej opinii ;-)

crn
Gaduła
Gaduła
Posty: 117
Rejestracja: 17 mar 2009, 22:07

Nieprzeczytany post autor: crn »

ja zrobie delikatny offtopic, ale moze Ci sie to przydac. Potrzebowalem przekazywac przez referencje tablice stringow do mql. Mialem strasznie dziwne wyniki. W efekcie okzalo sie, ze musze w mqlu zrobic:

//jak nie zalzy Ci an czasie proponuje petli do 20 :)

Kod: Zaznacz cały

string example = "asdsfsddsfgdfggggggggggggggggggggggggggggggggggggggg";
i dopiero wtedy referencja dzialala.

Pozdrawiam

Awatar użytkownika
reptile
Maniak
Maniak
Posty: 2799
Rejestracja: 13 gru 2008, 13:48

Nieprzeczytany post autor: reptile »

crn pisze:W efekcie okzalo sie, ze musze w mqlu zrobic:
W sensie pierwszy raz zaalakowac lenght ?
R.E.P.T.I.L.E. - Robotic Electronic Person Trained for Infiltration and Logical Exploration (off-line,only e-mail)

259
Maniak
Maniak
Posty: 3968
Rejestracja: 15 cze 2011, 23:20

Nieprzeczytany post autor: 259 »

Chodzi chyba o to, że jak zrobi się w mql string to on mimo że ma on alokowaną pamięć to jest pusty i zaczyna się od NULL co potem może zmylać jak się takie wsadzi do tablicy i przekazuje do dll..
Jest spora różnica różnica pomiędzy tym, co rozumie się jako tablicą stringów w MQL a tym jak rozumie się to w C: sam string jako tablicę znaków. Tu tablica, tam tablica ale inne. Tablica stringów w MQL = tablica zawierająca tablice znaków. Ale... na początku tej tablicy w MQL (bajtowo) wcale nie są znaki tylko bodajże wielkość tablicy o ile dobrze pamiętam... trzeba się trochę nakombinować żeby trafić w odpowiednie miejsce :-)
Jakże często ludzie mają już gotową opinię zanim zdążą pojąć istotę rzeczy.
A gdy już ta istota w pełni do nich dotrze, jakże często muszą zmagać się z konsekwencjami swojej opinii ;-)

Awatar użytkownika
Esco
Przyjaciel Forum
Przyjaciel Forum
Posty: 2603
Rejestracja: 11 kwie 2010, 20:56

Nieprzeczytany post autor: Esco »

Pewnie referencja do nie zainicjalizowanego stringa = NULL.

259
Maniak
Maniak
Posty: 3968
Rejestracja: 15 cze 2011, 23:20

Nieprzeczytany post autor: 259 »

Może tak być - wskaźnik wskazuje na początek tego co w MQL nazywa się string, a w c chr* czyli początkowy adres gdzie należy szukać szeregu znaków zakończonych NULL. A tam co? NULL... inaczej mówiąc nasz char* str_ref wskazuje na char str[0]
I w tym kontekscie ta sztuczka z pre-alokacją w MQL ma sens :-)

To o czym trzeba pamiętać jeżeli chodzi o przekazywanie danych MQL<->dll to kto jest właścicielem jakiego fragmentu pamięci i kto może co modyfikować.

Np. wystarczy przekazać Close[] jako parametr (dla ułatwienia wejściowy i wszystko jedno tablicę czy wskaźnik do tej tablicy) do dll żeby wyparować całość przy pierwszym dotknięciu. Kto wie dlaczego? ;-)
Jakże często ludzie mają już gotową opinię zanim zdążą pojąć istotę rzeczy.
A gdy już ta istota w pełni do nich dotrze, jakże często muszą zmagać się z konsekwencjami swojej opinii ;-)

Awatar użytkownika
Esco
Przyjaciel Forum
Przyjaciel Forum
Posty: 2603
Rejestracja: 11 kwie 2010, 20:56

Nieprzeczytany post autor: Esco »

259 pisze: Np. wystarczy przekazać Close[] jako parametr (dla ułatwienia wejściowy i wszystko jedno tablicę czy wskaźnik do tej tablicy) do dll żeby wyparować całość przy pierwszym dotknięciu. Kto wie dlaczego? Wink
Close pewnie jest w pamięci chronionej głównego wątku MT4.

ODPOWIEDZ