Jump to content

Recommended Posts

So first things first the example in the help file for _WinApi_Enum_Windows has an error

;_ArrayDisplay($aResult, "_WinAPI_EnumWindows", Default, Default, Default, Default, "#|Handle|Class|Title|Text|Process")
  Should Be
  _ArrayDisplay($aResult, "_WinAPI_EnumWindows", Default, Default, Default, "Handle|Class|Title|Text|Process")

Next is a bit of helpful info on LPCSTR in a callback function it needs  to be passed as a PTR

DllCallbackRegister($sFUNCT, $sRETURN, "ptr")

Finally on to my question

I'd want to call EnumPropsEX and pass a string through lparam + append to it rather than declaring anything globally

I can Come up with two ways to do this The second it a lot more code but possibly safer but the first way I think Should do

1. From a bit of testing It seems AutoIt won't overflow a DllStruct?

2. Are strings passed through DLL call guaranteed to be 'an ANSI string (a minimum of 65536 chars is allocated)' as the Helpfile clearly states?

#include <Array.au3>
#include <WinAPI.au3>
Example()

Func Example()
    Local $aWindows = _WinAPI_EnumWindows()
    Local $aResult[$aWindows[0][0]][6]
    For $i = 1 To $aWindows[0][0]
        $aResult[$i - 1][0] = "0x" & Hex($aWindows[$i][0], 8)
        $aResult[$i - 1][1] = $aWindows[$i][1]
        $aResult[$i - 1][2] = WinGetTitle($aWindows[$i][0])
        $aResult[$i - 1][3] = WinGetText($aWindows[$i][0])
        $aResult[$i - 1][4] = WinGetProcess($aWindows[$i][0])
        $aResult[$i - 1][5] = _ArrayToString(EnumProps($aWindows[$i][0]), ", ", 1)
    Next
    _ArrayDisplay($aResult, "_WinAPI_EnumWindows", Default, Default, Default, "Handle|Class|Title|Text|Process|Properties")
EndFunc   ;==>Example

Func EnumProps($hWnd, $vDLL = 'user32.dll')
    ; Create callback function.
    Local $iErr = 0
    Local $aProps[1] = [0]
    Local $hCb = DllCallbackRegister('_PropEnumProcEx', 'int', 'hwnd;ptr;handle;ptr')
    ; Call EnumPropsEx
    Local $aRet = DllCall($vDLL, 'int', 'EnumPropsEx', 'HWND', $hWnd, 'ptr', DllCallbackGetPtr($hCb), 'str', "")
    If @error Or Not $aRet[0] Then
        $iErr = @error
        ConsoleWrite("EnumProps Error:" & $iErr & @CRLF)
    ElseIf $aRet[3] <> "" Then
        $aProps = StringSplit($aRet[3], ";")
    EndIf
    DllCallbackFree($hCb)

    Return SetError($iErr, 0, $aProps)
EndFunc   ;==>EnumProps

Func _PropEnumProcEx($hWnd, $sProp, $hData, $pStr)
    Local $iSzStr = _WinAPI_StringLenA($sProp) + 1 ; + Null Char
    If $iSzStr > 1 Then
        Local $tProp = DllStructCreate('char[' & $iSzStr & ']', $sProp)
        Local $tRetn = DllStructCreate('char[65535]', $pStr)
        DllStructSetData($tRetn, 1, DllStructGetData($tRetn, 1) & DllStructGetData($tProp, 1) & ";")
    EndIf
    Return 1
EndFunc   ;==>_PropEnumProcEx
;--------------------------------------------------------------------------------------------------------------
Func EnumProps2($hWnd, $iSzBuffer = 4096, $vDLL = 'user32.dll')
    ; Create callback function.
    Local $iErr = 0
    Local $sProps
    Local $aProps[1] = [0]
    Local $hCb = DllCallbackRegister('_PropEnumProcEx', 'int', 'hwnd;ptr;handle;ptr')
    Local $tProps = DllStructCreate('int;int;char[' & $iSzBuffer & ']')
    DllStructSetData($tProps, 1, $iSzBuffer) ;BufferSz
    DllStructSetData($tProps, 2, $iSzBuffer) ;BufferRemaining
    ; Call EnumPropsEx
    Local $aRet = DllCall($vDLL, 'int', 'EnumPropsEx', 'HWND', $hWnd, 'ptr', DllCallbackGetPtr($hCb), 'ptr', DllStructGetPtr($tProps))
    If @error Or Not $aRet[0] Then
        $iErr = @error
        DllStructSetData($tProps, 2, 0)
    EndIf
    DllCallbackFree($hCb)

    $sProps = DllStructGetData($tProps, 3)

    If DllStructGetData($tProps, 2) > 0 Then
        If $sProps <> "" Then
            $aProps = StringSplit(StringTrimRight($sProps, 1), ";")
        EndIf
    Else
        If Not $iErr Then $iErr = 6 ;buffer overflow
        Return SetError($iErr, -DllStructGetData($tProps, 2), $aProps)
    EndIf
    Return $aProps
EndFunc   ;==>EnumProps2

Func _PropEnumProcEx2($hWnd, $sProp, $hData, $ptProp)
    Local $iSzStr = _WinAPI_StringLenA($sProp) + 1
    Local $tProp = DllStructCreate('char[' & $iSzStr & ']', $sProp)

    If $iSzStr > 1 Then
        Local $sRet = DllStructGetData($tProp, 1)
        Local $iSzBuffer = DllStructGetData(DllStructCreate('int', $ptProp), 1)
        Local $tRetn = DllStructCreate('int;int;char[' & $iSzBuffer & ']', $ptProp)
        DllStructSetData($tRetn, 2, DllStructGetData($tRetn, 2) - $iSzStr)
        If DllStructGetData($tRetn, 2) > 0 Then
            DllStructSetData($tRetn, 3, DllStructGetData($tRetn, 3) & $sRet & ";")
        EndIf
    EndIf
    Return 1
EndFunc   ;==>_PropEnumProcEx2

 

Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By UEZ
      I'm searching for a way to set an icon for a system menu entry in the console window. I can add / remove entries but I didn't find a way to set an icon for the entry I made.
      Example:
      #AutoIt3Wrapper_Change2CUI=y #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <GuiMenu.au3> #include <WindowsConstants.au3> Global $id_Test = 5000 Global $hConsole = HWnd(DllCall("kernel32.dll", "hwnd", "GetConsoleWindow")[0]) If Not $hConsole Then Exit HotKeySet("{ESC}", "_Exit") Global $hSysmenu = _GUICtrlMenu_GetSystemMenu($hConsole) Global $iCount = _GUICtrlMenu_GetItemCount ($hSysmenu) _GUICtrlMenu_InsertMenuItem($hSysmenu, $iCount, "Test", $id_Test) _GDIPlus_Startup() $hBitmap_GDI = _GDIPlus_BitmapCreateFromMemory(_Test(), True) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hBitmap_GDI = ' & $hBitmap_GDI & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $hBmp1 = _WinAPI_CreateSolidBitmap($hConsole, 0xFF0000, 16, 16) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hBmp1 = ' & $hBmp1 & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $hBmp2 = _WinAPI_CreateSolidBitmap($hConsole, 0x00FF00, 16, 16) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hBmp2 = ' & $hBmp2 & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console ;ConsoleWrite(_GUICtrlMenu_SetItemBmp($hSysmenu, $id_Test, $hBitmap_GDI, False) & @CRLF) ConsoleWrite(_GUICtrlMenu_SetItemBitmaps($hSysmenu, $id_Test, $hBmp1, $hBmp2, False) & ", " & @error & @CRLF) ;_GUICtrlMenu_SetItemBmp($hSysmenu, $id_Test, 8, False) ;set the default close icon _GDIPlus_Shutdown() Do Sleep(1000) Until False Func _Exit() ConsoleWrite("Bye..." & @CRLF) _GUICtrlMenu_DeleteMenu ($hSysmenu, $id_Test, False) _WinAPI_DeleteObject($hBitmap_GDI) _WinAPI_DeleteObject($hBmp1) _WinAPI_DeleteObject($hBmp2) Exit EndFunc ;Code below was generated by: 'File to Base64 String' Code Generator v1.20 Build 2020-06-05 Func _Test($bSaveBinary = False, $sSavePath = @ScriptDir) Local $Test $Test &= 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA3XAAAN1wFCKJt4AAADKElEQVQ4yz2RT2gcdRTHP7+Z36y7yzZZdvJv22i0rBpiAwnWCMZrUCGIBxEvpQSEHAQhePLkyUKg6Em9iZCcahH0pFYxkIqiIdHKYmPUUHcDmU2TuJnZzc7s/H7PQ5M8ePAu7/M+X56y1hKGYY+IOEDqOI6TzWY1gFIKEcF1XRzHUWmaJnF8bHBy5pfbnz9fb0hBh2F4bm5ubjWKogudTqdVqVT0/Py853kehUKBQqHA2tqaVKtVfenS2P6HH396PDri9D9+cdC/8dkXNW2t9fb29spRFPmtVqtULBaVMYZ8Pk82m8X3farVKjdv3qCn+FbpnFuXfNpQkkwlX33z3RtaKYXW2mqtcV1XtNZks9kzQCaTIeNp4sSh8rAnzSe0HO5bt1arHR51y79pEcEYo05Aylp7OqOUIk0TRp+aYO5Ki3B3VR3s70pictzZGlC5jHW0UgprLVEU4Xke29vbLCwsoLXGcRRxYjk/2MtLz2X4/tvbaO3y9XoPlUe7CI7VAMYYPM+jXC5jrcUYAwipUeSzHhV/k59+bFK5OMytOxco9ezQTQ2A4ujoqDQ+Ph4sLS2JiNiDgwM5PDyQ3SCQ/5ptubv6rsy9XJIfvnxbNv/8W+7d+9deu/aeTE9PB2EYljSAiKje3l7SNCUIAkDQXp77f3zE4uJ1Xnv9KoWRK+zs1DlfHiCXy2OtBcA5AdDpdHBdl4F+n77BEdz2z3zw/iKvvHqVZ194h0wmz0B/Ca094jjmtE4NEBFarRa7jfvkHgqp/rrKxOQzjF6+wtY/u4g9Jo5TfL+EiGCtxVqLFhGUUhhjsNZgrcvqrU948rFhKlNvEkUdtNvBoFEqPVtUSqGUQiulaDabtNttPC/D5t3fqTU0Y5dfpNFogFhEOLsaxzHtdpsgCNT6+rrSSZIwOztrhoeH' $Test &= 'qdfrRmutJp6e4q+tKsbYs3in7+7r65OhoSE9MzNjkiRBt9ttkiRxjTHkcjl3bGxMPYhjSdP0rLvdLt1uF9d1BcDzPHdyclL0yspKuLGxcT0IgkeKxaINgsADXBFxAefEQB4ImNT3/W4Yhk6z2awtLy9H/wPnrsNEnFPl4QAAAABJRU5ErkJggg==' Local $bString = _WinAPI_Base64Decode($Test) If @error Then Return SetError(1, 0, 0) $bString = Binary($bString) If $bSaveBinary Then Local Const $hFile = FileOpen($sSavePath & "\AutoSave_16x16_04.png", 18) If @error Then Return SetError(2, 0, $bString) FileWrite($hFile, $bString) FileClose($hFile) EndIf Return $bString EndFunc ;==>_Test Func _WinAPI_Base64Decode($sB64String) Local $aCrypt = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryA", "str", $sB64String, "dword", 0, "dword", 1, "ptr", 0, "dword*", 0, "ptr", 0, "ptr", 0) If @error Or Not $aCrypt[0] Then Return SetError(1, 0, "") Local $bBuffer = DllStructCreate("byte[" & $aCrypt[5] & "]") $aCrypt = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryA", "str", $sB64String, "dword", 0, "dword", 1, "struct*", $bBuffer, "dword*", $aCrypt[5], "ptr", 0, "ptr", 0) If @error Or Not $aCrypt[0] Then Return SetError(2, 0, "") Return DllStructGetData($bBuffer, 1) EndFunc ;==>_WinAPI_Base64Decode  
      You must compile and run it to see the menu entry in the console window.

       
      Any idea?
    • By UEZ
      Here another approach to check if a script was already started using atoms and semaphores.
       
      Atom:
      #include <MsgBoxConstants.au3> Global $iSingleton = Singleton() If Not $iSingleton Then Exit MsgBox($MB_TOPMOST, "Singleton Test", "Process is already running!") EndIf MsgBox($MB_TOPMOST, "Singleton Test", "Singleton atom initialized: " & $iSingleton) Singleton_Delete($iSingleton) ; #FUNCTION# ==================================================================================================================== ; Name ..........: Singleton ; Description ...: Checks if the script has been started already. ; Syntax ........: Singleton([$sOccurrenceName = @ScriptFullPath]) ; Parameters ....: $sOccurrenceName - [optional] a string value. Default is @ScriptFullPath. ; Return values .: If the function succeeds, the return value is the newly created atom or 0 else error is set and false is returned. ; Author ........: UEZ ; Modified ......: ; Remarks .......: If Singleton finds the atom it will return 0 and the atom token will be set to extended macro. It can be used to get the atom string using _WinAPI_AtomGlobalGetName. ; Related .......: ; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalfindatomw ; https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globaladdatomw ; Example .......: No ; =============================================================================================================================== Func Singleton($sOccurrenceName = @ScriptFullPath) Local $iFind = _WinAPI_AtomGlobalFind($sOccurrenceName) If @error Then Return SetError(1, 0, False) If $iFind Then Return SetExtended($iFind, 0) Local $iAtom = _WinAPI_AtomGlobalAdd($sOccurrenceName) If @error Then Return SetError(2, 0, False) Return $iAtom EndFunc ;==>Singleton ; #FUNCTION# ==================================================================================================================== ; Name ..........: Singleton_Delete ; Description ...: Deletes the atom generated by the first started script. ; Syntax ........: Singleton_Delete($iAtom) ; Parameters ....: $iAtom - an integer value which was generated by Singleton ; Return values .: True if successful else false. ; Author ........: UEZ ; Modified ......: ; Remarks .......: Don't forget to call Singleton_Delete before first started script ends. ; Related .......: ; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globaldeleteatom ; Example .......: No ; =============================================================================================================================== Func Singleton_Delete($iAtom) _WinAPI_AtomGlobalDelete($iAtom) If @error Then Return SetError(1, 0, False) Return True EndFunc ;==>Singleton_Delete ;internal functions Func _WinAPI_AtomGlobalFind($sAtomString) Local $aReturn = DllCall("kernel32.dll", "short", "GlobalFindAtomW", "wstr", $sAtomString) If @error Then Return SetError(1, 0, -1) Return $aReturn[0] EndFunc ;==>_WinAPI_AtomGlobalFind Func _WinAPI_AtomGlobalAdd($sAtomString) Local $aReturn = DllCall("kernel32.dll", "short", "GlobalAddAtomW", "wstr", $sAtomString) If @error Then Return SetError(1, 0, -1) Return $aReturn[0] EndFunc ;==>_WinAPI_AtomGlobalAdd Func _WinAPI_AtomGlobalDelete($nAtom) Local $aReturn = DllCall("kernel32.dll", "short", "GlobalDeleteAtom", "short", $nAtom) If @error Then Return SetError(1, 0, -1) Return $aReturn[0] = 0 EndFunc ;==>_WinAPI_AtomGlobalDelete Func _WinAPI_AtomGlobalGetName($nAtom, $iBufferSize = 512) Local $tBufferAtom = DllStructCreate("wchar name[" & $iBufferSize & "]") Local $aReturn = DllCall("kernel32.dll", "uint", "GlobalGetAtomNameW", "short", $nAtom, "struct*", $tBufferAtom, "int", $iBufferSize) If @error Or Not $aReturn[0] Then Return SetError(1, 0, -1) Return $tBufferAtom.name EndFunc ;==>_WinAPI_AtomGlobalGetName  
      Semaphore:
      #include <MsgBoxConstants.au3> #include <WinAPIError.au3> Global $iSingleton = Singleton("&]8h/x87</htFV4-K*&.b.w~") If Not $iSingleton Then Exit MsgBox($MB_TOPMOST, "Singleton Test", "Process is already running!") EndIf MsgBox($MB_TOPMOST, "Singleton Test", "Singleton Semaphore initialized: " & $iSingleton) ; #FUNCTION# ==================================================================================================================== ; Name ..........: Singleton ; Description ...: Checks if the script has been started already. ; Syntax ........: Singleton($sOccurrenceName) ; Parameters ....: $sOccurrenceName - a string value which will be used to create the semaphore handle. ; Return values .: True if Singleton started the first time. False if script was already started ; Author ........: UEZ ; Modified ......: ; Remarks .......: The system closes the handle automatically when the process terminates. The semaphore object is destroyed when its last handle has been closed. ; Related .......: ; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsemaphorea ; Example .......: No ; =============================================================================================================================== Func Singleton($sOccurrenceName) If StringLen($sOccurrenceName) > 260 Then $sOccurrenceName = StringLeft($sOccurrenceName, 260) Local $aReturn = DllCall("kernel32.dll", "handle", "CreateSemaphoreA", "ptr", Null, "long", 0, "long", 1, "str", $sOccurrenceName) If @error Or Not $aReturn[0] Then Return SetError(1, 0, -1) Return SetExtended($aReturn[0], $aReturn[0] And _WinAPI_GetLastErrorMessage() = "The operation completed successfully.") EndFunc ;==>Singleton  
      Just start the script twice to see if it works.
      The disadvantage of using atoms is that atoms have a memory that means when your app is crashing or you forgot to delete the atom then the atom does still have the $sOccurrenceName saved and thus Singleton will not work if you use the same same value for $sOccurrenceName.
      With semaphore you don't have this issue.
       
      Thanks to jj2007 and SARG.
    • By BlueSkyMemory
      Hello guys! I'm a rookie in AutoIt lol.
      I've tried to looking up in MSDN and the UDFs, but it can only get the GUID of a usual partition and with the GUID to control it. Now I have no ways😥.
      Thanks a lot for your help!
    • By IndianSage
      Hi,
      My AutoIt script is as folllows:
      ;use for calling function add2NosA in dll ;Local $vNo1 = 33 ;Local $vNo2 = 11 ;use for calling function sortNos in dll Local $vNo1 = [11,7,9] Local $vNo2 = [1,3,2] ; _ArrayDisplay($vNo1, "vNo1 display") ; _ArrayDisplay($vNo2, "vNo2 display") ;Local $hWnd = DllOpen("E:\CV-Dell-1\autoit3\myComObj1.dll") Local $hWnd = ObjCreate("myComObj1.clsMath") if (@error) Then MsgBox (0, "Error", "Error1 = " & @error) Exit EndIf ;function call method - DllCall with function name ;Local $aRes = DllCall($hWnd, "int", "addNosA", "int", $vNo1, "int", $vNo2) ;Local $aRes = DllCall($hWnd, "Ptr", "sortNos", "Array", $vNo1, "Array", $vNo2) ;function call method - $hWnd.<function name> ;Local $aRes = $hWnd.add2NosA($vNo1, $vNo2) ; this works fine with ObjCreate Local $aRes = $hWnd.sortNos($vNo1, $vNo2) if (@error) Then MsgBox (0, "Error", "Error2 = " & @error) DllClose($hWnd) Exit EndIf ;use appropriate msgbox ;MsgBox(0,"Result", "Result = " & $vNo1[0]) MsgBox(0,"Result", "Result = " & $aRes) _ArrayDisplay($vNo1, "vNo1 display") _ArrayDisplay($aRes , "aRes display") DllClose($hWnd) My VB.Net - ClassLibrary - Dll - COM obj is as follows - has 2 functions - add2NosA and sortNos:
      <ComClass(clsMath.ClassId, clsMath.InterfaceId, clsMath.EventsId)> Public Class clsMath Public Const ClassId As String = "3A42F85E-24C8-4BAA-91B5-AE56C4683C13" Public Const InterfaceId As String = "D99D7C79-2BA7-4A33-B7BC-9B7F19FDF828" Public Const EventsId As String = "CA128AC4-580C-4112-9EAD-8D1599E3F37A" Public Sub New() MyBase.New() End Sub Public Function add2NosA(ByVal no1 As Integer, ByVal no2 As Integer) As Integer Return (no1 + no2) End Function Public Sub sortNos(ByRef no1 As Array, ByRef no2 As Array) Array.Sort(no1) no2 = no1 End Sub End Class  Over all I tried various 8 options mentioned in the attached Excel file - with only 1 combination working.
      Overall could not make Array returned capture in AutoIt script. 
      Can someone help please?
      Thanks in  advance.
      Options-Tried-Matrix-Results.xlsx
    • By IndianSage
      I have create a function in FreeBasic like below:
      Extern "Windows-MS" Type tA f1 As Integer f2 As Integer End Type Public Function _switchOrder(ByVal no1 As Integer, ByVal no2 As Integer) As tA Export Dim result As Integer Dim taa As tA taa.f1 = no2 taa.f2 = no1 Return taa End Function End Extern Caller AutoIt code is:
      #include <MsgBoxConstants.au3> Global Const $sTag_ftdi_version_info="struct; int no1a; int no2a; endstruct" Local $aRet=DllCall("Math1.dll","Ptr","_switchOrder", "Int", 10, "Int", 30) ;MsgBox (0,"",@error & "-" & $aRet[0] & "-" & $aRet[1]& "-" & $aRet[2]) Local $t_ftdi_version_info=DllStructCreate($sTag_ftdi_version_info,$aRet[0]) MsgBox (0,"msg1=",@error & "---" & $aRet[0] & "-" & $aRet[1]& "-" & $aRet[2]) ;Local $retData1 = DllStructGetData($t_ftdi_version_info,"",1) Local $retData1 = DllStructGetData($t_ftdi_version_info,"no1a") MsgBox (0,"msg2=",@error & "--" & $retData1) ;Local $retData1 = DllStructGetData($t_ftdi_version_info,"",2) Local $retData1 = DllStructGetData($t_ftdi_version_info,"no2a") MsgBox (0,"msg2=",@error & "--" & $retData1) ;ConsoleWrite(DllStructGetData($t_ftdi_version_info,"",2) & "--" & @error) ;ConsoleWrite(DllStructGetData($t_ftdi_version_info,"no2a") & @CRLF) ;ConsoleWrite(DllStructGetData($tversion_str,1) & @CRLF) Getting error 2 for DllStructGetData or it give Close Application AutoIt popup message. 
      Certainly DllCall is not returning pointer to the Structure in $aRet[0] hence issue.
      Can someone help me fix this please?
      Thanks in advance.
       
       
×
×
  • Create New...