pixelsearch Posted March 28, 2022 Share Posted March 28, 2022 (edited) Hi everybody, The following script shows how easy it is to pass an integer parameter by Reference from AutoIt and have it modified by a Dll : C++ code of the Dll : extern "C" __declspec(dllexport) int test (int* inumber) { *inumber = -12345; return 0; } AutoIt code : #include <Array.au3> $hDLL = DllOpen("test.dll") If $hDLL = - 1 Then Exit Msgbox(0, "DllOpen", "error occured") Local $iNumber = 6 $aRet = DllCall($hDLL, "int:cdecl", "test", "int*", $iNumber) ; <=== * after int If @error Then Exit Msgbox(0, "DllCall", "error " & @error) _ArrayDisplay($aRet, "$aRet") DllClose($hDLL) We see how $iNumber changed from 6 (before DllCall) to -12345 (after DllCall) I (naively) tried it for a string, thinking it could work same, with char* sstring in the dll [instead of int* inumber] and "str*", $sString in the DllCall [instead of int*, $iNumber] but nothing good happened, I couldn't return an altered string from the Dll Then I tried it with a Structure, which soon became too complicated (though I didn't fully experiment the Structure way), then I started to write this post So I would like to to ask : is there a simple way to return an altered string from a dll, in the same easy way than we just saw with the integer ? 2 more things : * I need the "return 0" from the C++ code (which will define $aRet[0]) because it's also used if an error is found during the Dll, then it will return 1, 2 etc... in case of errors. * The strings needing to be returned are @Jon's "text-encoding-detect" strings when everything works fine, like : "Encoding: Binary" or "Encoding: UTF-16 Big Endian" etc... Because I intend to create a dll from his unaltered C++ code and post it here (if he agrees). Then, from an AutoIt script, we could choose a folder and have all files of the folder checked, with an ArrayDisplay output presented like this, for example : File Encoding ====== ======== File 1 Binary File 2 UTF-16 Big Endian ... Now I'm thinking of another way to achieve this, without returning any string from the dll. We could, for example, use $aRet[0] for any possible Return, errors or not, let's say : $aRet[0] = 1 : issue in the dll (Jon got some Return's 1 when it goes wrong) $aRet[0] = 100 : this will correspond to "Encoding : Binary" $aRet[0] = 101 : this will correspond to "Encoding : UTF-16 Big Endian" etc... and the match will be done directly in AutoIt (i.e. the corresponding string matching the return value) so there will be no need to return any string from the dll ! This could be doable because (gladly) Jon's function is natively called for one file only, so the Return value matches the file just checked. But just curious and I'm re-asking : is there a simple way to return an altered string from a dll, in the same easy way than we saw with the integer ? Thanks Edited March 28, 2022 by pixelsearch a silly param in AutoIt code Link to comment Share on other sites More sharing options...
jchd Posted March 28, 2022 Share Posted March 28, 2022 The DllCall datatypes are: str for byte codepages strings (ANSI or UTF8) and wstr for Unicode (UTF16) strings, both null-terminated. 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 March 28, 2022 Author Share Posted March 28, 2022 (edited) 1 hour ago, pixelsearch said: and "str*", $sString in the DllCall Hi jchd, yes this is how I scripted it, but with a "*" after "str" to pass it by reference "str*" as indicated in the help file, topic DllCall. The star gave a good result for int* but not for str* $aRet = DllCall($hDLL, "int:cdecl", "test", "str*", $sString) Edited March 28, 2022 by pixelsearch Link to comment Share on other sites More sharing options...
jchd Posted March 28, 2022 Share Posted March 28, 2022 (edited) There is no * in my answer 😉 Nonetheless, there is a trap here: if you intend to "return" a string longer than what was allocated for passing in by modifying it on-place, bad things will occur. Edited March 28, 2022 by jchd 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 March 28, 2022 Author Share Posted March 28, 2022 (edited) Yes I noticed that lol But how will I pass it by reference without the star ? This is a part of the help file, DllCall : Add * to the end of another type to pass it by reference. For example "int*" passes a pointer to an "int" type. If I didn't add the star at the end of int, then my 1st example wouldn't work at all. Now if you're saying that a star is possible after "int*", "struct*" but never after "str", that's something new to me. The help file should really be amended in this case... to indicate the types where a star is allowed or not (added these last words after edit) Edited March 28, 2022 by pixelsearch added a last sentence Link to comment Share on other sites More sharing options...
jchd Posted March 28, 2022 Share Posted March 28, 2022 AutoIt uses Variants to hold your data, which isn't the form a C/C++ vanilla DLL expects. Fixed-size data (e.g. numeric values) cause no issue, but strings are a problem in this context, being variable-sized. DllCall does a lot of conversions in/out under your feet to insure the callee doesn't destroy AutoIt workspace memory. pixelsearch 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 March 28, 2022 Author Share Posted March 28, 2022 Thanks for the explanation ! Link to comment Share on other sites More sharing options...
jchd Posted March 28, 2022 Share Posted March 28, 2022 For the very same reason it's very slow and painful to pass arrays in/out to/from C, unfortunately. 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 March 28, 2022 Author Share Posted March 28, 2022 extern "C" __declspec(dllexport) int test2 (const char** oldstring) { const char* newstring = "after DllCall"; *oldstring = newstring; return 0; } #include <Array.au3> $hDLL = DllOpen("test2.dll") If $hDLL = - 1 Then Exit Msgbox(0, "DllOpen", "error occured") Local $sString = "there_was_nothing" $aRet = DllCall($hDLL, "int:cdecl", "test2", "str", $sString) If @error Then Exit Msgbox(0, "DllCall #1", "error " & @error) _ArrayDisplay($aRet, "$aRet without *") Local $sString = "there_was_nothing" $aRet = DllCall($hDLL, "int:cdecl", "test2", "str*", $sString) ; <==== * after str If @error Then Exit Msgbox(0, "DllCall #2", "error " & @error) _ArrayDisplay($aRet, "$aRet with *") DllClose($hDLL) Call me stubborn Link to comment Share on other sites More sharing options...
jchd Posted March 28, 2022 Share Posted March 28, 2022 (edited) Can you try with overwriting the string with a longer one? Also, what happened to the input string? "there" turns into "$0Àfe" ??? Edited March 28, 2022 by jchd 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 March 28, 2022 Author Share Posted March 28, 2022 (edited) 45 minutes ago, jchd said: Can you try with overwriting the string with a longer one? sorry for the delay, was looking football on l'equipe TV I sure can jchd, this is what shows with this AutoIt code : Local $sString = "short" $aRet = DllCall($hDLL, "int:cdecl", "test2", "str", $sString) If @error Then Exit Msgbox(0, "DllCall", "error " & @error) _ArrayDisplay($aRet, "$aRet without *") Local $sString = "short" $aRet = DllCall($hDLL, "int:cdecl", "test2", "str*", $sString) If @error Then Exit Msgbox(0, "DllCall", "error " & @error) _ArrayDisplay($aRet, "$aRet with *") No idea for the repeated mess without * but it's fine it seems to work with star. Maybe a good thing that I quoted Jon in an earlier post, he may be interested by the "non-star" mess Edit: oops, "a longer string" you asked ? But "there_was_nothing" was already longer than "after DllCall", that's why I tested now with a shorter one named "short". Ok, I'll try again with a much longer than "there_was_nothing" I tried again with : Local $sString = "this is a very long sentence indeed !" ... Local $sString = "this is a very long sentence indeed !" ... Edited March 28, 2022 by pixelsearch Link to comment Share on other sites More sharing options...
Nine Posted March 28, 2022 Share Posted March 28, 2022 Maybe I am totally wrong on this one. But I think the mess is made by the fact that you assign a newstring to oldstring and newstring get out of scope on return, gets garbage collected and is replaced by something. On the other hand when using * method, it may work but I would assume with memory leak. Since my days on C are very very far, it is probably a bad assumption. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
pixelsearch Posted March 28, 2022 Author Share Posted March 28, 2022 In fact it works too with 1 less line in C++ code ! extern "C" __declspec(dllexport) int test2 (const char** oldstring) { *oldstring = "abc"; return 0; } AutoIt code : Local $sString = "W" $aRet = DllCall($hDLL, "int:cdecl", "test2", "str", $sString) If @error Then Exit Msgbox(0, "DllCall", "error " & @error) _ArrayDisplay($aRet, "$aRet without *") ConsoleWrite("1 - " & $sString & @crlf) Local $sString = "W" $aRet = DllCall($hDLL, "int:cdecl", "test2", "str*", $sString) If @error Then Exit Msgbox(0, "DllCall", "error " & @error) _ArrayDisplay($aRet, "$aRet with *") ConsoleWrite("2 - " & $sString & @crlf) AutoIt console : 1 - W 2 - W >Exit code: 0 I notice that, without star, the garbage on the left pic appears always same (7 char. starting with $0Àf and ending with the hatted-Z) until $sString got 1 character more than the replacement string. For instance, in this example with a replacement string = "abc", no matter $sString = "" or "W" or "WW" or "WWW", garbage appears same (7 char) Now, when $sString got 1 character more than the replacement string (i.e. "WWW4" vs "abc"), then garbage displayed becomes 4 characters only : $0Àf When $sString got 2 characters more than the replacement string (i.e. "WWW45" vs "abc"), then garbage displayed is 5 characters : $0Àf5 And the pattern is found : "WWW456" vs "abc" would display $0Àf56 etc... "WWW45678901234567890" vs "abc" would display $0Àf5678901234567890 (all this just tested right now) Anyway, it's good to know something possibly came out from this str* thing. I tried a loop (200.000 times), calling the dll without star and didn't notice a memory leak meanwhile or after, we'll see... Link to comment Share on other sites More sharing options...
Andreik Posted March 28, 2022 Share Posted March 28, 2022 (edited) Why not simple like this? PS: maybe with some checks to prevent the overflows #include <windows.h> extern "C" { __declspec (dllexport) void change(char str[]) { strcpy(str, "This is my new string."); } } int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return 0; } Edited March 28, 2022 by Andreik pixelsearch 1 Link to comment Share on other sites More sharing options...
pixelsearch Posted March 28, 2022 Author Share Posted March 28, 2022 (edited) @Andreik: that's great, it works fine. Thanks ! I did well opening this thread, hoping someone would give a simple solution Do you think some precaution should be taken, concerning what's written in this link ? To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source. * edit1: you edited your post while I was typing, thinking too about overflows lol * edit2 : this is crazy. As soon as you google on "strcpy memory issue" you got dozen of links telling you how unsafe it can be if misused. Everything we try in C/C++ looks dangerous, especially when you're a C++ newbie like me ! Edited March 28, 2022 by pixelsearch Link to comment Share on other sites More sharing options...
Andreik Posted March 28, 2022 Share Posted March 28, 2022 That's true but I tested with a shorter and a longer string and seems to work fine. If we talk about plain C I assume that when you say a string you understand an array of null terminated chars but since I don't know exactly how AutoIt handle these things it would be safer to pass the length of the buffer for further checks and if it need to reallocate the buffer. Link to comment Share on other sites More sharing options...
pixelsearch Posted March 28, 2022 Author Share Posted March 28, 2022 ok thanks a lot Link to comment Share on other sites More sharing options...
boludoz Posted December 31, 2022 Share Posted December 31, 2022 How can I make it so that it only returns the arguments I want and not the ones I put in the function header? 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