Leaderboard
Popular Content
Showing content with the highest reputation on 06/01/2021 in all areas
-
Working with DllCall and DllStruct on a ZeroMQ UDF (Questions)
JockoDundee and one other reacted to TheXman for a topic
From the help file for the DllCall function: If a dll filename is given then the DLL is automatically loaded and then closed at the end of the call. In other words, if you use a DLL handle in your DllCalls, it doesn't need to open/close the DLL file for each DllCall. So if you are going to be doing multiple DllCalls, it's better to use a handle. Both ways work but one is more efficient if you are going to be doing multiple DllCalls using any given DLL file. Yes, I like explicitly tidying up as much as possible. The get_zmq_dll_handle() function, which is used by all of the DllCalls, gets and saves a global DLL handle upon its first successful invocation. Also upon the first successful invocation, it registers a function to close the handle upon exit of the script. That way, even if the script is prematurely ended, like with an EXIT statement, the DLL handle will still be explicitly closed. I do this for a lot of handles, like when I'm using SQLite or if I want to make sure that other global resources are freed before exiting the script. All subsequent invocation of get_zmq_dll_handle() just returns the saved global DLL handle. You are correct that it isn't required to close the handle because it will be closed anyway, but I always prefer explicit actions over implicit actions. Internally, there's no difference between a pointer and a handle. Symantically, there's a difference. A pointer is just that, it points to a specific address in memory. A handle is a pointer that points to a resource. So the way I think of it: All handles are pointers, but not all pointers are handles.2 points -
Virtual listviews are lightning fast and can handle millions of rows. Virtual listviews are of interest when you have to insert more than 10,000 rows. When there are less than 10,000 rows, the standard listviews are sufficiently rapid. See the section "Using standard listviews" below. In a virtual listview data are not stored directly in the listview. Data are stored in an array, a structure (DllStructCreate), a flat fixed-length record file, a database or similar. The listview only contains the rows which are visible depending on the height of the listview. See About List-View Controls in the MicroSoft documentation for more information. An array or a structure can be used for listviews with 10,000 - 100,000 rows. If there are more than 100,000 rows a fixed-length record file or a database seems to be the best solution, because they have low impact on memory usage. But you get nothing for free. The costs is that a part of the built-in features does not work, and you will have to implement these features yourself. Because data isn't stored in the listview the Set- and Get-functions to manipulate data doesn't work. You have to manipulate the data source directly. And sorting is not supported at all by virtual listviews. If you need sorting, a database seems to be the best solution in all cases, because sorting can be handled by the database. Below you'll find the following sections: Data stored in arrays Data stored in databases Data stored in fixed-length record files Sorting rows in a virtual listview $LVN_ODFINDITEM notifications Using standard listviews Updates Zip file Examples The next two sections shows how to use virtual listviews, when data are stored in arrays or databases. In first section data are stored in 3 arrays with 10,000/50,000/100,000 rows and 10 columns. In second section data are stored in 3 databases with 100,000/1,000,000/10,000,000 rows and 10 columns. Data stored in arrays For a virtual listview rows are displayed with $LVN_GETDISPINFO notifications and the $tagNMLVDISPINFO structure. Code for $LVN_GETDISPINFO messages in the WM_NOTIFY function can be implemented in this manner: Case $LVN_GETDISPINFOW Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then Local $sItem = $aItems[DllStructGetData($tNMLVDISPINFO,"Item")][DllStructGetData($tNMLVDISPINFO,"SubItem")] DllStructSetData( $tText, 1, $sItem ) DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) ) EndIf Run LvVirtArray.au3. It takes some time to create the arrays. But when the arrays are created, switching from one array to another (which means updating the listview) is instantaneous. Data stored in databases When data are stored in a database, $LVN_ODCACHEHINT notifications and the $tagNMLVCACHEHINT structure is used to insert the rows in an array cache before they are displayed with $LVN_GETDISPINFO messages. The $tagNMLVCACHEHINT structure is defined in this way: Global Const $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom;int iTo" Note that $tagNMLVCACHEHINT is not included in GuiListView.au3 or StructureConstants.au3. Code for $LVN_ODCACHEHINT messages in the WM_NOTIFY function can be implemented in this manner: Case $LVN_ODCACHEHINT Local $tNMLVCACHEHINT = DllStructCreate( $tagNMLVCACHEHINT, $lParam ), $iColumns $iFrom = DllStructGetData( $tNMLVCACHEHINT, "iFrom" ) Local $sSQL = "SELECT * FROM lvdata WHERE item_id >= " & $iFrom & _ " AND item_id <= " & DllStructGetData( $tNMLVCACHEHINT, "iTo" ) & ";" _SQLite_GetTable2d( -1, $sSQL, $aResult, $iRows, $iColumns ) $aResult is the array cache. The purpose of the cache is to limit the number of SELECT statements. When the listview is displayed for the first time, all visible rows (in this example about 20) have to be updated. In this case $aResult will contain 20 rows and 10 columns. 20 rows is also the maximum number of rows in $aResult. A virtual listview will never update more than the visible number of rows at one time. Code for $LVN_GETDISPINFO messages can be implemented in this way: Case $LVN_GETDISPINFOW Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then Local $iIndex = DllStructGetData( $tNMLVDISPINFO, "Item" ) - $iFrom + 1 If $iIndex > 0 And $iIndex < $iRows + 1 Then Local $sItem = $aResult[$iIndex][DllStructGetData($tNMLVDISPINFO,"SubItem")] DllStructSetData( $tText, 1, $sItem ) DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) ) EndIf EndIf The zip below contains a small GUI, CreateDB.au3, to create 3 SQLite databases with 100,000/1,000,000/10,000,000 rows. The databases will use about 10/100/1000 MB of diskspace, and the creation will take about ½/5/40 minutes (on an old XP). You must select a database and click a button to start the creation. If you get tired of waiting, you can cancel (checked for every 10,000 rows) the process and continue another time. The process will continue where it stopped. You can run the examples even though the databases might only contain 30,000/200,000/1,500,000 rows. You do not have to create all three databases. Run LvVirtDB.au3. Data stored in fixed-length record files (update 2015-04-01) Extracting data directly from a fixed-length record file by setting the file pointer to the current record and reading the required number of bytes is another example, where $LVN_ODCACHEHINT messages should be used to insert records in an array cache before they are displayed. Code for $LVN_ODCACHEHINT and $LVN_GETDISPINFO messages can be implemented as shown: Case $LVN_ODCACHEHINT Local $tNMLVCACHEHINT = DllStructCreate( $tagNMLVCACHEHINT, $lParam ) $iFrom = DllStructGetData( $tNMLVCACHEHINT, "iFrom" ) $iRows = DllStructGetData( $tNMLVCACHEHINT, "iTo" ) - $iFrom + 1 FileSetPos( $hFile, $iFrom * 12, 0 ) ; Each line is 10 chars + CR + LF $aCache = StringSplit( FileRead( $hFile, $iRows * 12 - 2 ), @CRLF, 3 ) The purpose of the cache is to limit the number of FileRead statements. Case $LVN_GETDISPINFOW Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then Local $iIndex = DllStructGetData( $tNMLVDISPINFO, "Item" ) - $iFrom If -1 < $iIndex And $iIndex < $iRows Then DllStructSetData( $tText, 1, $aCache[$iIndex] ) DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) DllStructSetData( $tNMLVDISPINFO, "TextMax", 10 ) ; Each line is 10 chars EndIf EndIf Run LvVirtFile.au3. A fixed-length record file with 10,000 records (LvVirtFile.txt) is included in the zip. I have tested this example on a 1,1 GB file and 100,000,000 rows. The listview responds immediately. The solution with a flat fixed-length record file is extremely fast. Much faster than a database. But also with very much limited functionality compared to a database. Sorting rows in a virtual listview (update 2015-04-01) Sorting is not supported at all by virtual listviews. If you want rows to be sorted, you have to feed the listview with the rows in sorted order. If the rows are stored in an array, you have to sort the array before you feed the listview. If you want to sort the rows by two or more columns, you have to store the rows in two or more arrays which are sorted for the current column. Or you have to create two or more indexes to handle the sorting. Sorting arrays and creating indexes is time consuming. If you need sorting, a database seems to be the best solution, because sorting can be handled by the database. Nevertheless, here's an example that stores 10,000/20,000/30,000 rows and 3 columns in arrays, and creates indexes to handle the sorting. The columns are strings, integers and floating point numbers, and indexes are calculated for all 3 columns. To be able to create the indexes as fast as possible, structures (DllStructCreate) are used to create the indexes. This is the function to create indexes for integers and floating point numbers. The function for strings is equivalent. $tIndex = DllStructCreate( "uint[" & $iRows & "]" ) Func SortNumbers( ByRef $aItems, $iRows, $iCol, $pIndex, $tIndex ) Local $k, $n, $lo, $hi, $mi, $gt HourglassCursor( True ) WinSetTitle( $hGui, "", "Virtual ListViews. Sort numbers: 0 rows" ) For $i = 0 To $iRows / 10000 - 1 $k = $i * 10000 For $j = 0 To 9999 $n = $aItems[$k+$j][$iCol] ; Binary search $lo = 0 $hi = $k + $j - 1 While $lo <= $hi $mi = Int( ( $lo + $hi ) / 2 ) If $n < $aItems[DllStructGetData($tIndex,1,$mi+1)][$iCol] Then $gt = 0 $hi = $mi - 1 Else $gt = 1 $lo = $mi + 1 EndIf WEnd ; Make space for the new value DllCall( $hKernel32Dll, "none", "RtlMoveMemory", "struct*", $pIndex+($mi+1)*4, "struct*", $pIndex+$mi*4, "ulong_ptr", ($k+$j-$mi)*4 ) ; Insert new value DllStructSetData( $tIndex, 1, $k+$j, $mi+1+$gt ) Next WinSetTitle( $hGui, "", "Virtual ListViews. Sort numbers: " & $k + 10000 & " rows" ) Next HourglassCursor( False ) WinSetTitle( $hGui, "", "Virtual ListViews (sorted)" ) EndFunc Run LvVirtArraySort.au3. It takes some time to create the arrays and indexes. But when everything is created, sorting by different columns and switching from one array to another is instantaneous. Because it's easy and fast to save/load a structure to/from a binary file, it may be advantageous to calculate the arrays and indexes in another script before the GUI is opened. $LVN_ODFINDITEM notifications (update 2015-04-01) Three notifications are important for virtual listviews. $LVN_GETDISPINFO (to get information about the rows to display in the listview) and $LVN_ODCACHEHINT (to store rows from a file or database in an array cache before they are displayed with $LVN_GETDISPINFO messages) are already mentioned above. The last is $LVN_ODFINDITEM, which is used to find a row when you press one or a few keys on the keyboard. Information from $LVN_ODFINDITEM is stored in the $tagNMLVFINDITEM structure. The codebox shows the code for $LVN_ODFINDITEM notifications: Case $LVN_ODFINDITEMW Local $tNMLVFINDITEM = DllStructCreate( $tagNMLVFINDITEM, $lParam ) If BitAND( DllStructGetData( $tNMLVFINDITEM, "Flags" ), $LVFI_STRING ) Then Return SearchText( DllStructGetData( $tNMLVFINDITEM, "Start" ), _ ; Start DllStructGetData( DllStructCreate( "wchar[20]", DllStructGetData( $tNMLVFINDITEM, "Text" ) ), 1 ) ) ; Text EndIf Start is the row where you start the search. Text contains the key presses to search for. You have to implement the search function (here SearchText) yourself. If the function finds a row, it should return the index of the row. If not, it should return -1. Run LvVirtArrayFind.au3. Using standard listviews (update 2015-04-01) If not more than 10,000 rows have to be inserted in a listview, a standard listview is sufficiently rapid. Because of speed you should use native (built-in) functions to fill the listview and not functions in GuiListView.au3 UDF. When the listview is filled, you can use all the functions in the UDF. This code shows how to quickly fill a listview with native functions: Func FillListView( $idLV, ByRef $aItems, $iRows ) Local $tLVITEM = DllStructCreate( $tagLVITEM ) Local $pLVITEM = DllStructGetPtr( $tLVITEM ), $k, $s DllStructSetData( $tLVITEM, "Mask", $LVIF_IMAGE ) ; Icon (or image) DllStructSetData( $tLVITEM, "SubItem", 0 ) ; First column HourglassCursor( True ) For $i = 0 To $iRows / 10000 - 1 $k = $i * 10000 For $j = 0 To 9999 ; Text $s = $aItems[$k+$j][0] For $l = 1 To 9 $s &= "|" & $aItems[$k+$j][$l] Next GUICtrlCreateListViewItem( $s, $idLV ) ; Add item and all texts ; Icon Select Case Mod( $k + $j, 3 ) = 0 DllStructSetData( $tLVITEM, "Image", 2 ) ; Icon index Case Mod( $k + $j, 2 ) = 0 DllStructSetData( $tLVITEM, "Image", 1 ) Case Else DllStructSetData( $tLVITEM, "Image", 0 ) EndSelect DllStructSetData( $tLVITEM, "Item", $k + $j ) ; Row GUICtrlSendMsg( $idLV, $LVM_SETITEMW, 0, $pLVITEM ) ; Add icon Next WinSetTitle( $hGui, "", "GUICtrlCreateListViewItem ListViews. Fills listview: " & $k + 10000 & " rows" ) Next HourglassCursor( False ) WinSetTitle( $hGui, "", "GUICtrlCreateListViewItem ListViews" ) EndFunc Run LvStandard.au3. LvStandardIni.au3 shows how to quickly load an inifile (LvStandardIni.ini, created with IniWriteSection) into a listview. Because an inifile is a small file (only the first 32767 chars are read) it should always be loaded into a standard listview. Updates Update 2015-03-24 Added two array-examples. An example (LvVirtArrayIcons.au3) that shows how to use checkboxes and icons, and an example (LvVirtArrayColors.au3) that shows how to draw every second row with a different background color. In this post you can find an example where all items are drawn with a random background color. Update 2015-04-01 Cleaned up code in previous examples. Added more examples as described above. Zip updated. UDF versions (2018-04-27) Over the past weeks, new display functions have been added to Data display functions based on virtual listviews, and new functions have been added to use the listviews as embedded GUI controls. All the functions work and are used in much the same way. Apart from the data source, the function parameters are the same for all functions. The display functions support a wide range of features, all specified via a single function parameter $aFeatures, which is the last parameter. The central code to handle $LVN_ODCACHEHINT and $LVN_GETDISPINFO notifications is very optimized code. First of all, the code is implemented through the subclassing technique. This means that messages are received directly from the operating system and not from AutoIt's internal message management code. Messages are returned again directly to the operating system and again without interference with AutoIt's internal message handling code. Next, the code is divided into different include files each taking care of a particular feature. That way, it's avoided that a lot of control statements makes the code slow. And it's enough to include the code that's actually used. One reason why so much work has been done in optimizing code and developing features is that these functions will also work as UDF versions for the examples here. It's far from a trivial task to develop UDF versions of examples like these. Since the first version of the display functions was created in this thread 2½ years ago and then has been continuously developed, it's obvious to use the functions as UDF versions of these examples. The following examples are implemented as UDF versions: Data stored in arrays Data stored in CSV files Data stored in SQLite databases Zip file Examples in zip: LvVirtArray.au3 - Data stored in arrays LvVirtArrayColors.au3 - Alternating row colors LvVirtArrayFind.au3 - $LVN_ODFINDITEM notifications LvVirtArrayIcons.au3 - Checkboxes and icons LvVirtArraySort.au3 - Sorting rows in a virtual listview LvVirtDB.au3 - Data stored in databases (use CreateDB.au3 to create DBs) LvVirtFile.au3 - Data stored in fixed-length record files LvStandard.au3 - Using standard listviews LvStandardIni.au3 - Load inifile into a listview The size of the zip is caused by a 118 KB txtfile, LvVirtFile.txt, used by LvVirtFile.au3, and a 28 KB inifile, LvStandardIni.ini, used by LvStandardIni.au3. Tested with AutoIt 3.3.10 on Windows 7 64 bit and Windows XP 32 bit. Should work on all AutoIt versions from 3.3.10 and all Windows versions. Virtual ListViews.7z Examples Examples based on virtual listviews. Array examples: A lot of rows and random background colors for each cell - This post in another thread Incremental search (update as you type) in a virtual listview - Post 29 Sorting arrays: Rows can be sorted by strings, integers, floats and checkboxes, checked rows in top - Post 48 File sources: A CSV-file with 100,000 rows and 10 columns is data source - Post 56 SQLite examples: Various issues related to the use of a database - Post 34, 35, 43 An example that shows a way to implement a search box - Post 411 point
-
@swoop Since it appears that you are really taking the time to learn, I will put my little sample script below (with its output). Ordinarily, I would wait to see some actual effort or for an explicit request. Keep in mind that this is just one way, my way. As with any language, there's usually many ways to say the same thing. The sample script has terse documentation, but hopefully enough to help understand what each block of code is doing. I am hiding it behind the "Show Hidden Contents" banner in case you would rather not be tempted to see it while browsing the topic.1 point
-
My first steps would be: 1. Right click on an empty space on the desktop 2. New AutoIt v3 Script 3. Right Click on the created new file 4. Edit 5. Paste a simple example like this and save #include <File.au3> #include <MsgBoxConstants.au3> Local $sFind = "д" Local $sReplace = "d" Local $sFileName = "test.txt" Local $iRetval = _ReplaceStringInFile($sFileName, $sFind, $sReplace) If $iRetval = -1 Then MsgBox($MB_SYSTEMMODAL, "ERROR", "The pattern could not be replaced in file: " & $sFileName & " Error: " & @error) Exit Else MsgBox($MB_SYSTEMMODAL, "INFO", "Found " & $iRetval & " occurances of the pattern: " & $sFind & " in the file: " & $sFileName) EndIf 6. Create a text file in same location as the script: test.txt д some text д more text д 7. Return to the SciTe Editor 8. Place the cursor on the name of some function and press F1 for HELP File (_ReplaceStringInFile in the example above) 9. Press F5 for running the script 10. Repeat again and again: HELP FILE / simple examples for functions / Test ...1 point
-
Just set the structure to 0 (not the pointers) : $msg = 0 ; this frees the msg struct $data = 0 ; this frees the data struct1 point
-
By the way, you should not get caught up with creating or using the callback function in the zmq_msg_init_data() API. It is optional. Since you are creating the data struct, you can either free the resources yourself, or if it is a local variable, it will be freed when the function it is in is done. In AutoIt, most local resources are freed when there are no more references to them. Therefore, when the function that the API call is in is finished, the data struct's memory will be freed also. I actually created a script to test it, along with about 4 or 5 other ZeroMQ APIs and it works as described and expected. I'm off to the gym right now but if you would like to see the test script, then show me what you have done and I will show you the test script later this afternoon (in a few hours) when I return.1 point
-
Correct Correct again Correct Sort of. "data" is a named member of the struct (not really a property as such - but it can be thought of that way when using dot-notation to access struct members. The same can be done using DllStructGetData/DllStructSetData, but I prefer the dot-notation when possible).1 point
-
@TheXman I have been studying the CryptoNG UDF and the HttpApi UDF. Thanks again for the suggestion and help. I want to clarify if I understand how DllStructs are used in AutoIt for working with external DLLs. In the help file about DllStructCreate: https://www.autoitscript.com/autoit3/docs/functions/DllStructCreate.htm the description reads as follows: DllStructCreate Creates a C/C++ style structure to be used in DllCall. DllStructCreate ( Struct [, Pointer] ) Parameters Struct A string representing the structure to create (See Remarks). Pointer [optional] If supplied the struct will not allocate memory but use the pointer supplied. Return Value Success: a variable for use with DllStruct calls. Failure: sets the @error flag to non-zero. @error: 1 = Variable passed to DllStructCreate was not a string. 2 = There is an unknown Data Type in the string passed. 3 = Failed to allocate the memory needed for the struct, or Pointer = 0. 4 = Error allocating memory for the passed string. When we have an existing struct created by another DLL, we don't need to create that struct again in memory. But it is important to use the DllStructCreate with the optional pointer parameter in order to work with this "external" struct in AutoIt. The variable returned from DllStructCreate is used by DllStruct and other DllCall related functions to deal with an unknown pre-existing struct. Such functions as: DllCall, DllStructGetData, DllStructGetPtr, DllStructGetSize, DllStructSetData, IsDllStruct. I refer to specific DllStructCreate examples in your UDF's for my current understanding: From the HTTPAPI.au3: Func _HTTPAPI_HttpSendHttpResponse($hRequestQueue, $iRequestId, $iStatusCode, $sReason, $sBody) _DebugOut(@CRLF & "Function: HttpSendHttpResponse") Local $aResult[0] Local $pKnownHeader = Null Local $iFlags = 0 Local $tResponse = DllStructCreate($__HTTPAPI_gtagHTTP_RESPONSE_V2), _ $tCachePolicy = DllStructCreate($__HTTPAPI_gtagHTTP_CACHE_POLICY), _ $tLoggedData = DllStructCreate($__HTTPAPI_gtagHTTP_LOG_FIELDS_DATA), _ $tDataChunk = DllStructCreate($__HTTPAPI_gtagHTTP_DATA_CHUNK_FROM_MEMORY), _ $tReason = __HTTPAPI_CreateStringBuffer($sReason), _ $tBody = __HTTPAPI_CreateStringBuffer($sBody), _ $tContentType = __HTTPAPI_CreateStringBuffer("text/html"), _ $tContentLength = __HTTPAPI_CreateStringBuffer(String(DllStructGetSize($tBody))), _ $tHeader = "" ;Init response $tResponse.MajorVersion = 1 $tResponse.MinorVersion = 1 $tResponse.StatusCode = $iStatusCode $tResponse.pReason = DllStructGetPtr($tReason) $tResponse.ReasonLength = DllStructGetSize($tReason) $tResponse.LogDataType = $__HTTPAPI_HttpLogDataTypeFields ;Add known header(s) to response $pKnownHeader = DllStructGetPtr($tResponse, "KnownHeaders") + ($__HTPPAPI_HttpHeaderContentType * $__HTTPAPI_HTTP_KNOWN_HEADER_SIZE) $tHeader = DllStructCreate($__HTTPAPI_gtagHTTP_KNOWN_HEADER, $pKnownHeader) $tHeader.pRawValue = DllStructGetPtr($tContentType) $tHeader.RawValueLength = DllStructGetSize($tContentType) The specific line 1240: $tHeader = DllStructCreate($__HTTPAPI_gtagHTTP_KNOWN_HEADER, $pKnownHeader) I think that means the $tHeader struct is not created nor allocated in memory. We're just creating a struct variable to work with the struct. $pKnownHeader is a pointer to a pre-existing struct (in memory). We are creating $tHeader DLLStruct variable that contains information about the existing struct, which we know has the structure defined by $__HTTPAPI_gtagHTTP_KNOWN_HEADER. This $tHeader variable allows for us to use DllStruct functions to call and manipulate data in the memory location referred by $pKnownHeader. To apply the same idea to my ZeroMQ Dll struct code, if the ZeroMQ DLL functions create existing message structs and gives me back pointers, then I can use the DllStructCreate to do the same as you've done above. To make the message structs available for use in AutoIt via DllStrut and DllCall functions. That's also what's happening in the CryptoNG when DllStructCreate is used in the __CryptoNG_BCryptDecrypt function. From the CryptoNG.au3: Func __CryptoNG_BCryptDecrypt($sAlgorithmId, $xData, $hEncryptionKey, $bResultIsText = True) Local $tInputBuffer = "", _ $tOutputBuffer = "", _ $tIVBuffer = "", _ $tByteBuffer = "", _ $tUlong = "" Local $iBlockLength = 0, _ $iStatusCode = 0, _ $iError = 0, _ $iOutputLength = 0 Local $aResult[0] Local $vDecryptedData = "" Local $xIV = Binary("") _DebugOut(@CRLF & "Function: __CryptoNG_BCryptDecrypt()") _DebugOut("$sAlgorithmId = " & $sAlgorithmId) _DebugOut("$xData = " & $xData) ;Get length of key $tByteBuffer = __CryptoNG_BCryptGetProperty($hEncryptionKey, $CNG_BCRYPT_KEY_LENGTH) If @error Then Return SetError(1, 0, "") $tUlong = _WinAPI_CopyStruct($tByteBuffer, "ulong value") ;If this is a block cipher (not a stream cipher) If $sAlgorithmId <> $CNG_BCRYPT_RC4_ALGORITHM Then ;Get length of block $tByteBuffer = __CryptoNG_BCryptGetProperty($hEncryptionKey, $CNG_BCRYPT_BLOCK_LENGTH) If @error Then Return SetError(1, 0, "") $tUlong = _WinAPI_CopyStruct($tByteBuffer, "ulong value") $iBlockLength = $tUlong.value _DebugOut("$iBlockLength = " & $iBlockLength) ;Create initialization vector (IV) buffer and set its default value (0x000102...) $xIV = Binary("") For $i = 0 To $iBlockLength - 1 $xIV &= Binary(Chr($i)) Next $tIVBuffer = DllStructCreate(StringFormat("byte data[%i]", $iBlockLength)) $tIVBuffer.data = $xIV _DebugOut("IV = " & $tIVBuffer.data) EndIf The specific line 3422, the DllStructCreate is creating a new DllStruct variable $tIVBuffer: $tIVBuffer = DllStructCreate(StringFormat("byte data[%i]", $iBlockLength)) A DllStruct variable $tByteBuffer is returned from __CryptoNG_BCryptGetProperty: $tByteBuffer = __CryptoNG_BCryptGetProperty($hEncryptionKey, $CNG_BCRYPT_BLOCK_LENGTH) A copy of that struct a created as $tUlong. I'm not entirely sure why _WinAPI_CopyStruct is used here. Does this function turn the DllStruct into a WinAPI struct format? I think CopyStruct is just a WinAPI call to copy the stuct at the memory location specified by $tByteBuffer. But isn't $tByteBuffer a DllStruct variable? $tUlong = _WinAPI_CopyStruct($tByteBuffer, "ulong value") Then $iBlockLength uses the ulong value of $tUlong. $iBlockLength = $tUlong.value It appears that DllStructCreate for $tIVBuffer uses $iBlockLength as a length for data[?]. $tIVBuffer = DllStructCreate(StringFormat("byte data[%i]", $iBlockLength)) $tIVBuffer.data = $xIV Also I see this reference in __CryptoNG_BCryptGetProperty on line 4880: _DebugOut("$tBuffer = " & $tBuffer.data) There is a .data property used for the DllStruct variable. What is contained in .data? The actual binary data of the struct in memory? Is there a list of other properties that can be accessed from a DllStruct directly? Generally, is my understanding of both examples above correct? I'm trying to understand what's going on, rather than mimicking the code. Again thanks for the help. I'm still studying both UDF's. They are so well organized and written. I especially like how the HTTPAPI API organizes the structs in a global header section. ;======================== ; STRUCTURES ;======================== ;Global HHTP Version Structure Global $__HTTPAPI_gtagHTTP_VERSION = _ "struct;" & _ "ushort MajorVersion;" & _ "ushort MinorVersion;" & _ "endstruct;" ;Global HHTPAPI Version Structure and Constants Global $__HTTPAPI_gtagHTTPAPI_VERSION = _ "struct;" & _ "ushort HttpApiMajorVersion;" & _ "ushort HttpApiMinorVersion;" & _ "endstruct;" And structs within structs: Global $__HTTPAPI_gtagHTTP_DATA_CHUNK_FROM_FRAGMENT_CACHE_EX = _ $__HTTPAPI_gtagHTTP_DATA_CHUNK & _ "struct;" & _ "ushort FragmentNameLength;" & _ ;in bytes not including the NUL "ptr pFragmentName;" & _ ;wstr "endstruct;" Also, I saw the data alignment techniques here: Global $__HTTPAPI_gtagHTTP_DATA_CHUNK = _ "struct;" & _ "int DataChunkType;" & _ "endstruct;" & _ (@AutoItX64 ? "" : "ptr;") ;Union alignment issue found & fixed by Danyfirex1 point
-
TheXman, Just as an aside, thanks for the clear explanations. I learn a lot from your posts on DLLcalls and structs generally. M231 point
-
Why is a window not activated by a partial title?
JockoDundee reacted to Jos for a topic
Yeap. Think we are done here.1 point -
The one thing I liked about AutoIt, and most scripting languages, is that you don't have to compile it before you can run it. You just run the code, and if there's an error, it's easy to fix it and run it to test it again. There's no waiting for the compiler to run, no need for anything else to happen, they just run. The second best thing I love about AutoIt is that it's case insensitive for variables and function names. I know a lot of people cringe when they see that, but too bad, I like it. Also, no stupid line endings like in a C/C++ program, I mean seriously, what is the semi colon for? What semi-literate programmer ever uses a run on line of code, and why allow it in the first place?1 point
-
AutoIt is a pretty good all-rounder, generally being capable of doing most things, and far speedier to get up & running than other languages in that regard, though not speedier when it comes to process execution, which is one of its few downfalls, but which rarely matters normally. At the end of the day, you should use the right tool for the right job, but if your Toolbox only contains AutoIt, you are still looking damn good and cooking with fire in 95%+ instances.1 point