seadoggie01 Posted January 23, 2021 Share Posted January 23, 2021 I recently added some rgb fans to my desktop and I thought it would be cool if I could control them. So I found the documentation here and starting working on what I hope will be a simple UDF. Unfortunately, I hit a snag with my second function: I don't understand SafeArrays. I read about them from LarsJ's various posts, but (like much of his writing) I failed to comprehend about half of his post. I'm trying to implement MLAPI_GetDeviceInfo, which (as I understand) accepts two pointers to safe arrays that haven't been filled out yet. I was hoping that I could do something like this: #include <SafeArray.au3> #include <Array.au3> Global __g_hMysicDLL = DLLOpen(@UserProfileDir & "\Downloads\Mystic_light_SDK\MysticLight_SDK.dll") Local $aRet = DllCall($__g_hMysicDLL, "int", "MLAPI_Initialize") If $aRet[0] <> 0 Then Exit ConsoleWrite("Failed to init" & @CRLF) ; Create an empty SafeArray of bstr -- DevType seems to be bstr Local $pDevType = SafeArrayCreateEmptyWr("bstr") ; Create an empty SafeArray of bstr -- LedCount seems to be int Local $pLedCount = SafeArrayCreateEmptyWr("int") $aRet = DllCall($__g_hMysicDLL, "int", "MLAPI_GetDeviceInfo", "ptr", $pDevType, "ptr", $pLedCount) If $aRet[0] <> 0 Then Exit ConsoleWrite("Failed to get device info" & @CRLF) ConsoleWrite("Success!" & @CRLF) _ArrayDisplay($aRet[1], "Dev Types") _ArrayDisplay($aRet[2], "LED Count") I thought initially that displaying the arrays was the issue, but the code exits silently and the exit code is -1073741783 and sometimes -1073741784... so I'm not sure where I went wrong. Do I need to provide a pointer to empty space and the dllcall will create the SafeArray for me to read there? All my code provided is Public Domain... but it may not work. Use it, change it, break it, whatever you want. Spoiler My Humble Contributions:Personal Function Documentation - A personal HelpFile for your functionsAcro.au3 UDF - Automating Acrobat ProToDo Finder - Find #ToDo: lines in your scriptsUI-SimpleWrappers UDF - Use UI Automation more Simply-erKeePass UDF - Automate KeePass, a password managerInputBoxes - Simple Input boxes for various variable types Link to comment Share on other sites More sharing options...
markyrocks Posted January 24, 2021 Share Posted January 24, 2021 what is a bstr? I'm pretty familiar with most types and thats a first. To create a ptr to fill the easiest way that I know is using a dll struct. obviously the struct needs to be big enough to hold the data being passed to it. Local $pDevType = DllStructCreate("char[1028]") ;this is suspect bc bstr? not sure if that stands for binary but not a type i'm aware of Local $pLedCount = DllStructCreate("int") $aRet = DllCall($__g_hMysicDLL, "int", "MLAPI_GetDeviceInfo", "ptr", DllStructGetPtr($pDevType), "ptr", DllStructGetPtr($pLedCount)) $dt=DllStructGetData($pDevType,1) $lc=DllStructGetData($pLedCount,1) no guarantees that this is error free. Spoiler "I Believe array math to be potentially fatal, I may be dying from array math poisoning" Link to comment Share on other sites More sharing options...
Earthshine Posted January 24, 2021 Share Posted January 24, 2021 It’s binary string as the name indicates My resources are limited. You must ask the right questions Link to comment Share on other sites More sharing options...
JockoDundee Posted January 24, 2021 Share Posted January 24, 2021 16 hours ago, markyrocks said: what is a bstr? I'm pretty familiar with most types and thats a first. https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr Code hard, but don’t hard code... Link to comment Share on other sites More sharing options...
LarsJ Posted January 24, 2021 Share Posted January 24, 2021 On 1/23/2021 at 6:04 AM, seadoggie01 said: I'm trying to implement MLAPI_GetDeviceInfo, which (as I understand) accepts two pointers to safe arrays I'm pretty sure MLAPI_GetDeviceInfo() directly returns two safearray pointers. You can use this code to display the information in the BSTRs in the $pDevType safearray: #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=y Opt( "MustDeclareVars", 1 ) #include "Variant.au3" #include "SafeArray.au3" ReadSafeArray( $pDevType ) Func ReadSafeArray( $pDevType ) ; SafeArray elements Local $iUBound SafeArrayGetUBound( $pDevType, 1, $iUBound ) If Not $iUBound Then Return ConsoleWrite( "SafeArrayGetUBound ERR" & @CRLF ) ConsoleWrite( "SafeArrayGetUBound = " & $iUBound & @CRLF ) ; SafeArray data Local $pArrayData SafeArrayAccessData( $pDevType, $pArrayData ) If Not $pArrayData Then Return ConsoleWrite( "SafeArrayAccessData ERR" & @CRLF ) ConsoleWrite( "SafeArrayAccessData OK" & @CRLF ) ; Read the BSTRs from the safearray ; In this case where the safearray is a safearray of BSTRs, array data is simply three pointers Local $tArrayData = DllStructCreate( "ptr[" & $iUBound & "]", $pArrayData ) ConsoleWrite( "$pBSTR1 = " & SysReadString( DllStructGetData( $tArrayData, 1, 1 ) ) & @CRLF ) ConsoleWrite( "$pBSTR2 = " & SysReadString( DllStructGetData( $tArrayData, 1, 2 ) ) & @CRLF ) ConsoleWrite( "$pBSTR3 = " & SysReadString( DllStructGetData( $tArrayData, 1, 3 ) ) & @CRLF ) ; Continue up to and including $iUBound + 1 ; Unaccess SafeArray data SafeArrayUnaccessData( $pDevType ) EndFunc Variant and SafeArray UDFs can be downloaded here. Demo code: expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=y Opt( "MustDeclareVars", 1 ) #include "Variant.au3" #include "SafeArray.au3" Global $pSafeArray WriteSafeArray() Func WriteSafeArray() ; Create SafeArray Local $tsaBound = DllStructCreate( $tagSAFEARRAYBOUND ) DllStructSetData( $tsaBound, "cElements", 3 ) DllStructSetData( $tsaBound, "lLbound", 0 ) $pSafeArray = SafeArrayCreate( $VT_BSTR, 1, $tsaBound ) If Not $pSafeArray Then Return ConsoleWrite( "SafeArrayCreate ERR" & @CRLF ) ConsoleWrite( "SafeArrayCreate OK" & @CRLF ) ; Create three BSTRs (basic strings) ; A BSTR is represented by a pointer indicating the memory location where data is stored Local $pBSTR1 = SysAllocString( "one" ) Local $pBSTR2 = SysAllocString( "two" ) Local $pBSTR3 = SysAllocString( "three" ) ; SafeArray data Local $pArrayData SafeArrayAccessData( $pSafeArray, $pArrayData ) If Not $pArrayData Then Return ConsoleWrite( "SafeArrayAccessData ERR" & @CRLF ) ConsoleWrite( "SafeArrayAccessData OK" & @CRLF ) ; Store the BSTRs in the safearray ; In this case where the safearray is a safearray of BSTRs, array data is simply three pointers Local $tArrayData = DllStructCreate( "ptr[3]", $pArrayData ) DllStructSetData( $tArrayData, 1, $pBSTR1, 1 ) DllStructSetData( $tArrayData, 1, $pBSTR2, 2 ) DllStructSetData( $tArrayData, 1, $pBSTR3, 3 ) ; Unaccess SafeArray data SafeArrayUnaccessData( $pSafeArray ) EndFunc ReadSafeArray() Func ReadSafeArray() Local $pDevType = $pSafeArray ; SafeArray data Local $pArrayData SafeArrayAccessData( $pDevType, $pArrayData ) If Not $pArrayData Then Return ConsoleWrite( "SafeArrayAccessData ERR" & @CRLF ) ConsoleWrite( "SafeArrayAccessData OK" & @CRLF ) ; Read the BSTRs from the safearray ; In this case where the safearray is a safearray of BSTRs, array data is simply three pointers Local $tArrayData = DllStructCreate( "ptr[3]", $pArrayData ) ConsoleWrite( "$pBSTR1 = " & SysReadString( DllStructGetData( $tArrayData, 1, 1 ) ) & @CRLF ) ConsoleWrite( "$pBSTR2 = " & SysReadString( DllStructGetData( $tArrayData, 1, 2 ) ) & @CRLF ) ConsoleWrite( "$pBSTR3 = " & SysReadString( DllStructGetData( $tArrayData, 1, 3 ) ) & @CRLF ) ; Unaccess SafeArray data SafeArrayUnaccessData( $pDevType ) EndFunc Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
markyrocks Posted January 26, 2021 Share Posted January 26, 2021 (edited) I just wanted to post this just to show that the type isn't really super critical unless its a struct or something but even then at the end of the day its still 1s and 0s in there. The only downside that I came across messing with the following code was that autoit automatically allocates 4 bytes if you pull a byte out of memory. It may change based on what version of autoit your' using but don't quote me on that. The following just mimics the way a function would fill a pointer which is just a memcpy. Then it demonstrates that regardless of the type how to pull the data out. 1 byte can only hold a value between 0-255, which can then in turn be converted to binary, int, char or a string. now obviously if the data is bigger than 1 byte you can try combinations of different common sizes on different sections to pull out what you need but generally 1,2,4 are the most common. expandcollapse popup#include <WinAPI.au3> #include <Memory.au3> Global $size Main() func Main() $s=DllStructCreate("byte[1234]") DllStructSetData($s,1,Binary(104),1);pretend this is the data that will be passed from the function to our pointer..."bstr" DllStructSetData($s,1,Binary(101),2) DllStructSetData($s,1,Binary(108),3) DllStructSetData($s,1,Binary(108),4) DllStructSetData($s,1,Binary(111),5) $size=1234 $ss=DllStructCreate("char[1234]") ;allocate memory for our buffer...the type really doesn't matter as long as the size is big enough... $Dest_ptr=DllStructGetPtr($ss) $Source_ptr=DllStructGetPtr($s) ;get pointers $hprocess=0 $iWritten=0 $hprocess=_WinAPI_OpenProcess($PROCESS_ALL_ACCESS,false,@AutoItPID) if $hprocess then for $x=0 to $size-1 ;this is basically a memcopy which is how the buffer would be filled regardless _WinAPI_WriteProcessMemory($hprocess,$Dest_ptr,$Source_ptr,1,$iWritten) $Dest_ptr+=1 $Source_ptr+=1 Next ;start to pull the memory out, via creating a struct with a different tag... at the same pointer as the Dest_ptr bc its a bstr we'll do a byte type $Dest_ptr=DllStructGetPtr($ss) ;the pointer changed in the last operation so reset it dim $byteArray[$size] Local $byte for $x=1 to $size $sss=DllStructCreate("byte",$Dest_ptr) $byte=Binary(DllStructGetData($sss,1)) if Not int($byte) Then ExitLoop $byteArray[$x-1]=$byte $Dest_ptr+=1 Next Else ConsoleWrite("process failed to open") exit EndIf ConsoleWrite("as Binary (output as hex)"&@CRLF) PrintByteArrayAsBinary($byteArray) ConsoleWrite("as Binary (raw bits)"&@CRLF) PrintByteArrayBits($byteArray) ConsoleWrite("as ints"&@CRLF) PrintByteArrayAsInts($byteArray) ConsoleWrite("as chars"&@CRLF) PrintByteArrayAsChars($byteArray) ConsoleWrite("as a string "&@CRLF) PrintByteArrayAsString($byteArray) _WinAPI_CloseHandle($hprocess) EndFunc func PrintByteArrayAsBinary($byteArray) for $x=0 to $size-1 if Not $byteArray[$x] then ExitLoop ConsoleWrite($byteArray[$x]&@CRLF) Next EndFunc func PrintByteArrayAsInts($byteArray) for $x=0 to $size-1 if Not $byteArray[$x] then ExitLoop ConsoleWrite(int($byteArray[$x])&@CRLF) Next EndFunc func PrintByteArrayAsChars($byteArray) for $x=0 to $size-1 if Not $byteArray[$x] then ExitLoop ConsoleWrite(BinaryToString($byteArray[$x])) ConsoleWrite(@CRLF) Next EndFunc func PrintByteArrayAsString($byteArray) for $x=0 to $size-1 if Not $byteArray[$x] then ExitLoop ConsoleWrite(BinaryToString($byteArray[$x])) Next ConsoleWrite(@CRLF) EndFunc func PrintByteArrayBits($byteArray) for $x=0 to $size-1 for $y=0 to 7 if Not int($byteArray[$x]) then ExitLoop ConsoleWrite(checkbit($byteArray[$x],$y)) if $y=3 then ConsoleWrite(" ") Next if Not int($byteArray[$x]) then ExitLoop ConsoleWrite(@CRLF) Next EndFunc Func checkbit($bp,$bi) if $bp = BitOR($bp,BitShift(1,-7+$bi)) Then return 1 EndIf return 0 EndFunc ;~ output: ;~ as Binary (output as hex) ;~ 0x68000000 ;~ 0x65000000 ;~ 0x6C000000 ;~ 0x6C000000 ;~ 0x6F000000 ;~ as Binary (raw bits) ;~ 0110 1000 ;~ 0110 0101 ;~ 0110 1100 ;~ 0110 1100 ;~ 0110 1111 ;~ as ints ;~ 104 ;~ 101 ;~ 108 ;~ 108 ;~ 111 ;~ as chars ;~ h ;~ e ;~ l ;~ l ;~ o ;~ as a string ;~ hello Edited January 26, 2021 by markyrocks Spoiler "I Believe array math to be potentially fatal, I may be dying from array math poisoning" 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