Ontosy Posted June 12, 2022 Share Posted June 12, 2022 (edited) How send string that containing a 0 chr to a dll? $a=DllCall('file.dll', 'none', 'func', 'str', 'Test One'&Chr(0)&'Two') Not work. I use a char replace in dll source but do it is possible to avoid it? Edited June 12, 2022 by Ontosy Link to comment Share on other sites More sharing options...
Werty Posted June 12, 2022 Share Posted June 12, 2022 Have you tried with Null? Untested $a=DllCall('file.dll', 'none', 'func', 'str', 'Test One'& Null &'Two') Some guy's script + some other guy's script = my script! Link to comment Share on other sites More sharing options...
Ontosy Posted June 12, 2022 Author Share Posted June 12, 2022 (edited) Tested "Null" now: not work. Quote Null as string it has no value (empty string). Edited June 12, 2022 by Ontosy Link to comment Share on other sites More sharing options...
jchd Posted June 12, 2022 Share Posted June 12, 2022 NULL isn't a string! Pass an empty string: $str = '' TheDcoder 1 This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
pixelsearch Posted June 13, 2022 Share Posted June 13, 2022 One question : why chr(0) can't be considered as a full character ? Maybe OP could create a structure containing his string, include his chr(0)'s within the string, then pass the pointer of the structure (and probably its length) to the dll, for example : Local $hDLL = DllOpen(@ScriptDir & "\afac9.dll") If $hDLL = -1 Then Exit Msgbox(0, "DllOpen", "error occured") Local $sData = "1234" & chr(0) & "6789" Local $iBufferSize = StringLen($sData) ; $iBufferSize = 9 (as chr(0) counts for 1 char) Local $tStruct = DllStructCreate("char[" & $iBufferSize & "]") If @error Then Exit Msgbox(0, "DllStructCreate", "error " & @error) DllStructSetData($tStruct, 1, $sData) If @error Then Exit Msgbox(0, "DllStructSetData", "error " & @error) MsgBox(0, "$iBufferSize = " & $iBufferSize, DllStructGetPtr($tStruct)) Local $aRet = DllCall($hDLL, "int:cdecl", "string_with_chr0", "ptr", DllStructGetPtr($tStruct)) If @error Then Exit Msgbox(0, "DllCall", "error " & @error) $tStruct = 0 DllClose($hDLL) C++ code : #include <windows.h> #include <iostream> using namespace std; extern "C" __declspec(dllexport) int string_with_chr0 (LPVOID string_adress) { cout << "String adress = " << string_adress << endl; return 0; } The C++ keyword "cout" isn't really recommended in a dll, but as we run the AutoIt script from Scite, then we can access the informative output of the dll into Scite's console (which imho is a fast way for debugging while creating a dll called from AutoIt) Next step should be to access directly the memory from C++ code (using the string adress + string length, i.e $iBufferSize) and do what has to be done when a chr(0) is encountered at a memory location, like the one found in the pic above. There is certainly a shorter way to achieve this, maybe another reader could share his solution. Link to comment Share on other sites More sharing options...
jchd Posted June 13, 2022 Share Posted June 13, 2022 Weird things happen when dealing with strings containing one or more 0x00 This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
Ontosy Posted June 13, 2022 Author Share Posted June 13, 2022 (edited) It work. How get string in string_address length in c++ code? I have to a parameter? How get string instead of string_address? Edited June 13, 2022 by Ontosy Link to comment Share on other sites More sharing options...
pixelsearch Posted June 13, 2022 Share Posted June 13, 2022 (edited) @Ontosy Yes you have to add a parameter to pass the string length, as showed in the script below Local $hDLL = DllOpen(@ScriptDir & "\afac9.dll") If $hDLL = -1 Then Exit Msgbox(0, "DllOpen", "error occured") Local $sData = "1234" & chr(0) & "6789" Local $iBufferSize = StringLen($sData) ; $iBufferSize = 9 (as chr(0) counts for 1 char) Local $tStruct = DllStructCreate("char[" & $iBufferSize & "]") If @error Then Exit Msgbox(0, "DllStructCreate", "error " & @error) DllStructSetData($tStruct, 1, $sData) If @error Then Exit Msgbox(0, "DllStructSetData", "error " & @error) MsgBox(0, "$iBufferSize = " & $iBufferSize, DllStructGetPtr($tStruct)) Local $aRet = DllCall($hDLL, "int:cdecl", "string_with_chr0", _ "ptr", DllStructGetPtr($tStruct), "int", $iBufferSize) If @error Then Exit Msgbox(0, "DllCall", "error " & @error) $tStruct = 0 DllClose($hDLL) C++ code : #include <windows.h> #include <iostream> using namespace std; extern "C" __declspec(dllexport) int string_with_chr0 (void* string_adress, int string_length) { char string_text[string_length]; memcpy (string_text, string_adress, string_length); cout << "String adress = " << string_adress << endl; cout << "String length = " << string_length << endl; cout << "String text = " << string_text << endl; for (int i = 0; i < string_length; i++) { cout << string_text[i] << " "; } cout << endl; // MessageBox(0, "", "Inside Dll", MB_OK | MB_TOPMOST); return 0; } I've added a variable in C++ code, named string_text, which contains... the string text and its inner chr(0) When this variable is displayed in Scite Console, it will display only "1234" as chr(0) at 5th position will be treated as the end of the string. But you can see in C++ For loop (and in Scite Console) that the variable contains all the characters, when they're displayed one by one. Edited June 13, 2022 by pixelsearch typo Link to comment Share on other sites More sharing options...
Solution pixelsearch Posted June 13, 2022 Solution Share Posted June 13, 2022 Though the preceding script works, I'm not a big fan of these C char[] arrays that you can't display because there is a chr(0) inside and their manipulation isn't very easy. I tried initially to use std::string but I couldn't make it (i.e. to fill a std::string directly from both parameters) though I guess it's doable. Anyway, now that the char[] array is created and functional in the preceding script, I succeeded to create a std::string based on the char[] array, which gives good results for displaying the variable at once (no for loop). Also, manipulating std::string is easier than manipulating char[] So if we add the 3 following lines at the end of the preceding C++ code, this is the good result that will be displayed in Scite Console : std::string true_string(string_text, string_length); cout << "True String : size = " << true_string.size() << endl; cout << "True String : text = " << true_string << endl; Now that's fresh air If I find a way to create the std::string directly (without the char[] lines) then I'll add a post here. Ontosy 1 Link to comment Share on other sites More sharing options...
pixelsearch Posted June 13, 2022 Share Posted June 13, 2022 (edited) 1 hour ago, pixelsearch said: If I find a way to create the std::string directly (without the char[] lines) then I'll add a post here. Just found it C++ code : #include <iostream> using namespace std; extern "C" __declspec(dllexport) int string_with_chr0 (void* string_adress, int string_length) { string string_text (static_cast<char*>(string_adress), string_length); cout << "String size = " << string_text.size() << endl; cout << "String text = " << string_text << endl; return 0; } Edited June 13, 2022 by pixelsearch Link to comment Share on other sites More sharing options...
pixelsearch Posted June 16, 2022 Share Posted June 16, 2022 Looong post coming, divided in 4 parts : 1) the workable solution which solved OP's need : how to pass Chr(0) from Autoit to a dll. This will be a short resume of precedent posts, showing also that Scite Console can be used for output during this process. 2) Extend this solution to wide characters (Unicode), replacing Chr(0) with ChrW(1034) for example... but Scite Console will stop displaying the output, because of the wide char. 3) Try another way for wide char's, but here again, Scite Console won't display the wide char's part. 4) Several examples of MessageBox directly in C++ code : if we really want to debug a C++ code (without the use of a debugger) then C++ MessageBox can help a lot because it will display the wide char's part (then we can forget Scite's console which helps only when dealing with ANSI characters) Part 1) ANSI characters chr(0) to chr(255) As we need to pass a chr(0) from AutoIt to the dll, we can't use a "str" parameter in DllCall because the string will be truncated + possible error at run time. The solution found is to create a structure of char's and pass its pointer to the dll AutoIt code (without error checking to make it shorter, error checking found in preceding posts) Local $hDLL = DllOpen(@ScriptDir & "\afac9b.dll") Local $sData = "1234" & Chr(0) & "6789" Local $iBufferSize = StringLen($sData) ; $iBufferSize = 9 Local $tStruct = DllStructCreate("char[" & $iBufferSize & "]") DllStructSetData($tStruct, 1, $sData) MsgBox(0, "$iBufferSize = " & $iBufferSize, DllStructGetPtr($tStruct)) Local $aRet = DllCall($hDLL, "int:cdecl", "string_with_chr0", _ "ptr", DllStructGetPtr($tStruct), "int", $iBufferSize) $tStruct = 0 DllClose($hDLL) C++ code #include <iostream> using namespace std; extern "C" __declspec(dllexport) int string_with_chr0 (void* string_adress, int string_length) { string string_text (static_cast<char*>(string_adress), string_length); cout << "String size = " << string_text.size() << endl; cout << "String text = " << string_text << endl; return 0; } So far, so good. Scite Console shows correctly the output of C++ code This one-liner C++ code did a great job : string string_text (static_cast<char*>(string_adress), string_length); It allows to "convert" what points at string_adress memory to char* (it surely could be explained better). After all, C++ doesn't know anything about what type of data string_adress is pointing to, string_adress being only a pointer (void*) As it worked fine, then I thought : "why not trying a cast to Unicode wide characters (i.e. wchar_t*) and that's how the idea of Part 2 started. Part 2) UNICODE characters in the range 0-65535 Now that Chr(0) got its solution, let's replace Chr(0) with ChrW(1034) to see where it goes : AutoIt code (structure is now wchar) Local $hDLL = DllOpen(@ScriptDir & "\afac9c.dll") Local $sData = "0123" & ChrW(1034) & "5678" Local $iBufferSize = StringLen($sData) ; 9 characters Local $tStruct = DllStructCreate("wchar[" & $iBufferSize & "]") DllStructSetData($tStruct, 1, $sData) MsgBox(0, "$iBufferSize = " & $iBufferSize, DllStructGetPtr($tStruct)) Local $aRet = DllCall($hDLL, "int:cdecl", "wstring_with_unicode", _ "ptr", DllStructGetPtr($tStruct), "int", $iBufferSize) $tStruct = 0 DllClose($hDLL) C++ code (using wstring) #include <iostream> using namespace std; extern "C" __declspec(dllexport) int wstring_with_unicode (void* string_adress, int string_length) { std::wstring string_text (static_cast<wchar_t*>(string_adress), string_length); cout << "String size = " << string_text.size() << endl; wcout << "String text = " << string_text << endl; std::wstring s4 = string_text.substr(4,1); // remember 1st char is at pos 0 wcout << "s4 = " << s4 << endl; if (s4 == L"\u040A") // 1034 dec { cout << "s4 OK" << endl; } std::wstring s8 = string_text.substr(8,1); // remember 1st char is at pos 0 wcout << "s8 = " << s8 << endl; if (s8 == L"\u0038") { cout << "s8 OK" << endl; } return 0; } ChrW(1034) is correctly found in the memory dump pic above (04*256 = 1024) + 0A (10) => decimal 1034 We notice that Scite Console output is incomplete : as soon as a Unicode character appears, Scite Console seems to stop displaying all further wcout found in C++ code (for example it didn't display wcout << "s4 = " or wcout << "s8 = ") Part 3) Just to make sure, let's try an alternate script with ChrW(1034), without using a structure. AutoIt code (no more structure, just a unicode wide character string passed to the dll) Local $hDLL = DllOpen(@ScriptDir & "\afac9d.dll") Local $sData = "0123" & ChrW(1034) & "5678" Local $iBufferSize = StringLen($sData) ; 9 characters Local $aRet = DllCall($hDLL, "int:cdecl", "wstring_with_unicode", _ "wstr", $sData, "int", $iBufferSize) DllClose($hDLL) C++ code #include <iostream> using namespace std; extern "C" __declspec(dllexport) int wstring_with_unicode (wchar_t* sbigdata, int string_length) { std::wstring string_text = sbigdata; cout << "String size = " << string_text.size() << endl; wcout << "String text = " << string_text << endl; std::wstring s4 = string_text.substr(4,1); // remember 1st char is at pos 0 wcout << "s4 = " << s4 << endl; if (s4 == L"\u040A") // 1034 dec { cout << "s4 OK" << endl; } std::wstring s8 = string_text.substr(8,1); // remember 1st char is at pos 0 wcout << "s8 = " << s8 << endl; if (s8 == L"\u0038") { cout << "s8 OK" << endl; } return 0; } Scite Console would show exactly the same truncated output than the pic in Part 2) Part 4) No more dll but a C++ console exe, showing the syntax of MessageBox when we need to display constants of variables (including wide char) The C++ MessageBox syntax isn't as easy as in AutoIt but at least it shows a way to display variables results while scripting a C++ console app or a C++ dll, it can help to debug (especially if you don't use a debugger) C++ code : #include <windows.h> // #include <string> #include <iostream> using namespace std; int MsgBox(int flag, const char* title, const char* text) { return MessageBox(NULL, text, title, flag); // NULL = no owner window } int MsgBoxW(int flag, const wchar_t* title, const wchar_t* text) { return MessageBoxW(NULL, text, title, flag); // NULL = no owner window } int main() { // 2 functions MsgBox() & MsgBoxW() match AutoIt MsgBox parameters passing order MsgBox(0, "1 - Title", "Text"); // 0 is MB_OK string title = "2 - Title"; int number = 2; int iret = MsgBox(MB_OKCANCEL | MB_ICONQUESTION, title.c_str(), ("Variable = " + to_string(number)).c_str()); if (iret == 2) { cout << "Cancel pressed" << endl; } MsgBoxW(0, L"3 - Wide title", L"Wide text"); // 0 is MB_OK wstring title4 = L"4 - Wide Title"; MsgBoxW(0, title4.c_str(), L"\u040A"); // 1034 dec wcout << L"\u040A" << endl; // nothing is displayed in my console wstring title5 = L"5 - Wide Title"; wstring var5 = L"\u040A"; MsgBoxW(0, title5.c_str(), var5.c_str()); wstring title6 = L"6 - Wide Title"; wstring var6 = var5; MsgBoxW(0, title6.c_str(), (L"Wide variable is: " + var6).c_str()); return 0; } Windows Console : "Cancel pressed" (if click on cancel in MessageBox2) The whole purpose of this post was to show that, not only OP's question about Chr(0) had a solution, but also the use of Scite Console while scripting a C++ dll (as long as it doesn't involve wide chars). If wide chars are required, then C++ MessageBox seems much more useful. Thanks to @jchd in this post, where he indicates how an AutoIt script can display Unicode chars in Scite Console, by encoding the script in UTF-8 format (through Scite File menu), then using this line to display the unicode character : ; script to be saved as UTF-8 (+++) ConsoleWrite(ChrW(1034) & @crlf) ; displays a bad question mark ? ConsoleWrite(BinaryToString(StringToBinary(ChrW(1034), 4), 1) & @crlf) ; works, thanks jchd ! Mods: if you think this whole thread should be placed in the C/C++ section, please don't hesitate Link to comment Share on other sites More sharing options...
jchd Posted June 16, 2022 Share Posted June 16, 2022 Yes, Windows consoles don't know how to deal with wide chars (UTF16-LE), only UTF8. This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now