tukangusil7 Posted April 16, 2018 Share Posted April 16, 2018 (edited) Consider the following example: Local $tsData Local $sData $tsData = DllStructCreate("WCHAR[8]") DllStructSetData($tsData, 1, "123" & ChrW(0) & ChrW(0) & "678") $sData = DllStructGetData($tsData, 1) MsgBox(0, $sData, StringLen($sData)) The value of $sData from the above example will be "123". Is there a way to make $sData copies the all characters from the array of WCHARs? Perhaps by making use the RtlMoveMemory function (if possible) to copy the contents of WCHARs directly to $sData, but the problem is how to allocate a certain length for $sData and get a pointer to it. Sorry, I'm a newbie in AutoIt world. Edited April 16, 2018 by tukangusil7 Link to comment Share on other sites More sharing options...
jchd Posted April 17, 2018 Share Posted April 17, 2018 Nul bytes in a string are treated as string termination in a certain number of cases and DllStructGetData is one of them. You might expect that overlaying a ushort[8] DllStrucct above $tsData would solve the problem by allowing you to retrieve the whole ushort array with DllStructGetData. Unfortunately this doesn't work and you only fetch the first ushort of the array if you don't specify an element index. You can still fetch all the elements in a For loop. So yes copying the memory is likely to will work better. tukangusil7 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...
JohnOne Posted April 17, 2018 Share Posted April 17, 2018 I tried a for loop unsuccessfully, I suspect the problem lies with DllstructSetData and the null char. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
JohnOne Posted April 17, 2018 Share Posted April 17, 2018 I suppose the next step is to ponder how you are getting the data and if you can do it differently. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
tukangusil7 Posted April 17, 2018 Author Share Posted April 17, 2018 (edited) Inspired by jchd's statement, one way that I have just found to solve the problem is by doing the following steps: Define the array of WCHARs as an array of BYTEs. Call DllStructGetData() to get the bytes. In this case, DllStructGetData() will store the bytes as a binary variant. Call BinaryToString() to convert the binary variant to string. By doing so, the final string copies the whole data including the null characters. See the code below. However, any better approach will be appreciated. #include <Array.au3> Func Test() Local $tsData Local $binData Local $sData ; Just for an example, ; $tsData is set to "123" & ChrW(0) & ChrW(0) & "678" $tsData = DllStructCreate("BYTE[16]") DllStructSetData($tsData, 1, 49, 1) ; 49 is code for "1" DllStructSetData($tsData, 1, 50, 3) ; 50 is code for "2" DllStructSetData($tsData, 1, 51, 5) ; 51 is code for "3" DllStructSetData($tsData, 1, 00, 7) ; ChrW(0) DllStructSetData($tsData, 1, 00, 9) ; ChrW(0) DllStructSetData($tsData, 1, 54, 11) ; 54 is code for "6" DllStructSetData($tsData, 1, 55, 13) ; 55 is code for "7" DllStructSetData($tsData, 1, 56, 15) ; 56 is code for "8" $binData = DllStructGetData($tsData, 1) ; The array of bytes becomes a Binary variant $sData = BinaryToString($binData, $SB_UTF16LE) ; Converts the binary variant to string ; Since MsgBox() cannot be used to verify a string containing null characters, in order to ; verify whether $sData contains the whole string including the null characters, I convert ; $sData to an array of Unicode code points. $abtData = StringToASCIIArray($sData) ; $abtData holds the code units contained in $sData _ArrayDisplay($abtData, StringLen($sData)) EndFunc Test() The background story to this question is that I'm creating a wrapper function for NtQueryValueKey(). If we choose KEY_VALUE_FULL_INFORMATION struct to hold the result of this function, the Name member of KEY_VALUE_FULL_INFORMATION struct will contain the specified value name plus the value data. Both information is contained in one string. To make this even more complicated, if the value being queried is of type REG_MULTI_SZ, the value data part will be a sequence of null-terminated strings. Edited April 27, 2018 by tukangusil7 Link to comment Share on other sites More sharing options...
JohnOne Posted April 17, 2018 Share Posted April 17, 2018 I could be wrong here, but is wchar size dependant on some conditions, including OS? I mean not always 2 bytes. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
jchd Posted April 17, 2018 Share Posted April 17, 2018 It's OK, WCHAR is a 16-bit entity. 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...
tukangusil7 Posted April 22, 2018 Author Share Posted April 22, 2018 (edited) OK, since my proposal in the bug tracker was declined, I want to share my UDF that converts an array of bytes in a struct to a string. < StructByteArrayToString.au3 > expandcollapse popup#include-once #include <StringConstants.au3> Opt("MustDeclareVars", 1) ;--------------------------------------------------------------------------------------------------- ; Purpose: Converts an array of bytes in a struct to a string. The array of bytes is returned by a ; call to an API function that informs the length of the bytes that has been written to the array. ; Parameters: ; $paiBytes [in]: A pointer to an array of bytes in an element of a struct. The array of bytes is ; assumed to be an array of UTF-16 Little Endian code units. For example, to get a pointer to ; the array of bytes in the 1st element of the following struct, ; $taiBuffStr = DllStructCreate("BYTE[1024]") ; set $paiBytes parameter to DllStructGetPtr($taiBuffStr, 1). ; $iBytesLen [in]: The actual length of the bytes in the array. This actual bytes length is given ; by the corresponding API function. ; $bIncludeNullTerminator [in,opt]: Specifies whether the returned string will include a null ; terminator, if any, in the source string. If this parameter is set to False (default) and the ; source string is a registry value data of type $REG_MULTI_SZ, the last two null terminators ; of the source string are excluded from retrieval. ; Return: String ; - Success: The corresponding string. ; - Failure: ""; @error flag is set to error code. ; Background: When DllStructGetData() retrieves a WCHAR array that contains null characters, the ; returned string is truncated at the first encountered null character. Fortunately, there is a ; workaround to this problem, that is by doing the following steps: ; 1. Define the WCHAR array as a BYTE array; ; 2. Call DllStructGetData() to get the bytes. In this case, DllStructGetData() will store the ; bytes as a binary variant. ; 3. Call BinaryToString() to convert the binary variant to string. ; Author: Sayyid Ibnu Husein Alatas ; Last Updated on 22 April 2018 ;--------------------------------------------------------------------------------------------------- Func StructByteArrayToString($paiBytes, $iBytesLen, $bIncludeNullTerminator = 0) Local Const $ciSizeOfWChar = 2 Local $tiLastCharCode Local $iLastCharCode Local $taiBytes Local $bvStr If ($paiBytes = Null) Or ($iBytesLen <= 0) Then Return SetError(1, 0, "") If Not $bIncludeNullTerminator Then ; Grab the last character code unit from the array of bytes $tiLastCharCode = DllStructCreate("WORD[1]", $paiBytes + $iBytesLen - $ciSizeOfWChar) $iLastCharCode = DllStructGetData($tiLastCharCode, 1) ; If the last character is a null terminator, exclude it from retrieval If $iLastCharCode = 0 Then $iBytesLen -= $ciSizeOfWChar ; If the second-last character is also a null terminator, exclude it too from retrieval. ; Actually this is intended for registry value data of type $REG_MULTI_SZ. If $iBytesLen >= (2 * $ciSizeOfWChar) Then $tiLastCharCode = DllStructCreate("WORD[1]", $paiBytes + $iBytesLen - $ciSizeOfWChar) $iLastCharCode = DllStructGetData($tiLastCharCode, 1) If $iLastCharCode = 0 Then $iBytesLen -= $ciSizeOfWChar EndIf EndIf ; $iLastCharCode = 0 EndIf ; Not $bIncludeNullTerminator ; Retrieve the bytes and return it as a string $taiBytes = DllStructCreate("BYTE[" & $iBytesLen & "]", $paiBytes) $bvStr = DllStructGetData($taiBytes, 1) ; Take the bytes data as a binary variant Return BinaryToString($bvStr, $SB_UTF16LE) ; Return the binary variant as a string EndFunc ; StructByteArrayToString ;=================================================================================================== < TestStructByteArrayToString.au3 > #include <Array.au3> #include "StructByteArrayToString.au3" Opt("MustDeclareVars", 1) ;--------------------------------------------------------------------------------------------------- Func Test() Local Const $ciSizeOfWChar = 2 Local $taiBuffStr = DllStructCreate("BYTE[1024]") Local $sStr = "123" & ChrW(0) & ChrW(0) & "678" & ChrW(0) Local $bvStr = StringToBinary($sStr, $SB_UTF16LE) DllStructSetData($taiBuffStr, 1, $bvStr) Local $paiBytes = DllStructGetPtr($taiBuffStr, 1) Local $sResult = StructByteArrayToString($paiBytes, StringLen($sStr) * $ciSizeOfWChar, False) Local $aiBytes = StringToASCIIArray($sResult) _ArrayDisplay($aiBytes) EndFunc ;=================================================================================================== Test() Good luck! Edited April 22, 2018 by tukangusil7 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