Jump to content

WMCDIPC ( x32/x64, user/admin, self triggering, slow WM_COPYDATA IPC )


Go to solution Solved by argumentum,

Recommended Posts

Posted (edited)

The example:

Spoiler
#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=y
#AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
#AutoIt3Wrapper_Run_Au3Stripper=y ; or not
#Au3Stripper_Parameters=/rm /sv /rsln /pe
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#cs ----------------------------------------------------------------------------
 AutoIt Version: 3.3.16.1
#ce ----------------------------------------------------------------------------

;~ #RequireAdmin ; with or without or mixed

#include <WMCDIPC.au3> ; that's the name I came up with
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPIError.au3>

Global $hGui, $idEdit, $g_DebugStr = "", $iGuiCount = WinList("WMCDIPC-example")[0][0]
If $iGuiCount > 20 Then Exit

If StringInStr($CmdLineRaw, "/AsSender") Then Exit ThaGui("AsSender")
ThaGui("AsReceiver")

Func ThaGui($sActAs)
    If WinExists("WMCDIPC-example-AsReceiver") Then $sActAs = "AsSender" ; ..in case you to load more times
    Local $iSleep = 0, $iS = 40, $iW = 950, $iH = 220, $iT = $iS + ($iGuiCount * ($iH + $iS)), $iL = $iS
    #forceref $iSleep
    If @DesktopHeight < ($iH * ($iGuiCount + 2)) Then
        $iT = $iS + ($iGuiCount * $iS)
        $iL = $iT ; use this if the GUIs don't fit in the monitor
    EndIf

    $hGui = GUICreate("WMCDIPC-example-" & $sActAs, $iW, $iH, $iL, $iT, _
            BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX, $WS_THICKFRAME, $WS_TABSTOP), _
            BitOR($WS_EX_TOPMOST, $WS_EX_WINDOWEDGE)) ; ..or use your own GUI. WM_COPYDATA needs a GUI.
    GUISetFont(10, 400, 0, "Terminal")
    $idEdit = GUICtrlCreateEdit("..just a sec..", 0, 0, $iW, $iH)
    GUICtrlSetResizing(-1, $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKTOP + $GUI_DOCKBOTTOM)
    GUISetState()

;~  Opt("GUIOnEventMode", 1)
;~  $iSleep = 100
;~  GUISetOnEvent($GUI_EVENT_CLOSE, ExitScript) ; just in case you GUIOnEventMode = 1

    ; these lines are all you need + the IPC user function

    WMCDIPC_PrintCallback(myConsoleWrite) ; You'd set something like this for debug. Not really necessary.
    ;           WMCDIPC_PrintCallback() returns the current function.
    ;           WMCDIPC_PrintCallback(Default) resets it back to the default handler "ConsoleWrite()".
    ;           WMCDIPC_PrintCallback("") to disable it.
    ;           When compiled it is automatically disabled, unless later declared by user.

    WMCDIPC_MSGFLT_AllAllowed() ; to get msg from every level, elevated or not.
;~  WMCDIPC_AdlibTime(10) ; default is 20 mSec but, have your fun ?. Look at "TimerDiff($aDataArray[$eWMCDIPC_TimerInit])" for hints.
;~  WMCDIPC_AdlibFunc("") ; process the messages in the loop. It does respond faster than Adlib when using GUIOnEventMode=0 ( as in this example )
;~  WMCDIPC_AdlibFunc(My_IPC_Func) ; process the messages in this function ; don't set as string, must be the func name for AdlibRegister() to work.
    WMCDIPC_AdlibRegister(My_IPC_Func, 10) ; this alternate function is the same as the above two func, all in one.
    WMCDIPC_Register() ; register the message handler
    myConsoleWrite('> WMCDIPC_AdlibFunc = ' & (StringLen(FuncName(WMCDIPC_AdlibFunc())) = "" ? '""' : FuncName(WMCDIPC_AdlibFunc()) & '()') & _
            ' and GUIOnEventMode = ' & Opt("GUIOnEventMode") & @CRLF) ; debug ?

    ; This section will load senders ( to call it something ) to make some chatter among them.
    Local $sBase = @AutoItExe
    If Not WinExists("WMCDIPC-example-AsSender") Then
        For $n = 1 To 2
            Sleep(100)
            If Not WMCDIPC_Compiled() Then $sBase = StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1)) & (Mod($n, 2) ? "autoit3_x64.exe" : "autoit3.exe")
;~          ShellExecute($sBase, '"' & @ScriptFullPath & '" /AsSender', "", (Mod($n, 2) ? "" : "RunAs")) ; to test as admin
            ShellExecute($sBase, '"' & @ScriptFullPath & '" /AsSender')
        Next
    EndIf

    If $sActAs = "AsSender" Then
        Sleep(500)
        WMCDIPC_Send($hGui, WinGetHandle("WMCDIPC-example-AsReceiver"), 5, "Yellow there !")
    EndIf

    While 1
;~      If $iSleep Then Sleep($iSleep) ; if "GUIOnEventMode = 1", set $iSleep to maybe 100
;~      If WMCDIPC_MsgData()[0] Then My_IPC_Func() ; must declare WMCDIPC_AdlibFunc("") to run in the loop
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                myCloseThemAll() ; Tell the other scripts to exit.
                GUIDelete()
                Return
        EndSwitch
    WEnd
EndFunc   ;==>ThaGui

Func My_IPC_Func()
    Local $aDataArray = WMCDIPC_MsgData() ; will AdlibUnRegister() and get the message data
    Local Enum $eWMCDIPC_Adlib, $eWMCDIPC_receiver, $eWMCDIPC_iMsg, $eWMCDIPC_sender, $eWMCDIPC_int, $eWMCDIPC_string, _
            $eWMCDIPC_TimerDiff, $eWMCDIPC_TimerInit, $eWMCDIPC_MsgCounter, $eWMCDIPC_CaughtCounter, $eWMCDIPC_UBound
    ; these are repeated here due to Au3Stripper

    ; --------- your code here ------8<---------
    Local $sStr = (@AutoItX64 ? "64bit" : "32bit") & " / " & (IsAdmin() ? "Admin" : "User") & ' level  -  ( UDF ver.: ' & WMCDIPC_Version() & ' )' & @CRLF & @CRLF
    $sStr &= "-   receiver >" & $aDataArray[$eWMCDIPC_receiver] & '<' & @CRLF
    $sStr &= "-       iMsg >0x" & Hex($aDataArray[$eWMCDIPC_iMsg], 4) & '<' & @CRLF
    $sStr &= "-     sender >" & $aDataArray[$eWMCDIPC_sender] & '<' & @CRLF
    $sStr &= "-       data >0x" & Hex($aDataArray[$eWMCDIPC_int], 4) & '< ' & ($aDataArray[$eWMCDIPC_int] = 0xFADE ? "the other script failed to act on this" : (Mod($aDataArray[$eWMCDIPC_int], 5) ? "" : " will return ""sup !""")) & @CRLF
    $sStr &= "-     string >" & $aDataArray[$eWMCDIPC_string] & '<' & @CRLF & @CRLF
    $sStr &= "- MsgHandler >" & $aDataArray[$eWMCDIPC_TimerDiff] & '< time spent receiving' & @CRLF
    $sStr &= "- MsgHandler >" & TimerDiff($aDataArray[$eWMCDIPC_TimerInit]) & '< time it took to get here' & @CRLF
    $sStr &= "- MsgHandler >" & $aDataArray[$eWMCDIPC_MsgCounter] & '< Incoming messages count' & @CRLF        ; These two should
    $sStr &= "- MsgHandler >" & $aDataArray[$eWMCDIPC_CaughtCounter] & '< Messages caught count' & @CRLF ; be the same count.
    $sStr &= @CRLF
    $g_DebugStr &= $sStr
    GUICtrlSetData($idEdit, $g_DebugStr) ; if "not Mod(number,5)" send data back. is just an idea for the example.
    If Not Mod($aDataArray[$eWMCDIPC_int], 5) Then WMCDIPC_send($aDataArray[$eWMCDIPC_receiver], $aDataArray[$eWMCDIPC_sender], 6, "sup !")
    If $aDataArray[$eWMCDIPC_int] = 7 Then Exit ; This line, will save you a click or two and close it for you  =)
    ; --------- your code here ------>8---------

    Sleep(200) ; to create a busy state for the demo and return "busy"
    ;Note: "$aDataArray[$eWMCDIPC_int] = 64222" is returned to the sender when is busy/unable to act on the message received,
    ; hence "64222" ( 0xFADE as in fade away ) is reserved by the UDF.

    WMCDIPC_MsgData(1) ; at the end to allow a next message
EndFunc   ;==>My_IPC_Func

Func myConsoleWrite($sStr) ; You'd code something like this for debug. Not really necessary.
    ConsoleWrite($sStr)
    $g_DebugStr &= $sStr
    GUICtrlSetData($idEdit, $g_DebugStr)
EndFunc   ;==>myConsoleWrite

Func myCloseThemAll() ; ..thought it'd be nice to close one and close them all.
    Local $n, $aArray = WinList("WMCDIPC-example")
    For $n = 1 To $aArray[0][0]
        If $aArray[$n][1] = $hGui Then ContinueLoop
        WMCDIPC_Send($hGui, $aArray[$n][1], 7, "Bye bye")
    Next
    Sleep(100) ; if in the loop instead of addlib, it may need a delay
EndFunc   ;==>myCloseThemAll

Func ExitScript()
    myCloseThemAll() ; Tell the other scripts to exit.
    Exit
EndFunc   ;==>ExitScript

The UDFish:

Spoiler
#AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7
#include-once ; #include <WMCDIPC.au3>

#Au3Stripper_Off

Func WMCDIPC_Compiled() ; for debug ?. Don't know if is worth it but will not hurt anyone
    Local Static $bIsCompiled = (@AutoItExe = @ScriptFullPath)
    Return $bIsCompiled
EndFunc   ;==>WMCDIPC_Compiled

Global Enum $eWMCDIPC_Adlib, $eWMCDIPC_receiver, $eWMCDIPC_iMsg, $eWMCDIPC_sender, $eWMCDIPC_int, $eWMCDIPC_string, $eWMCDIPC_TimerDiff, $eWMCDIPC_TimerInit, $eWMCDIPC_MsgCounter, $eWMCDIPC_CaughtCounter, $eWMCDIPC_UBound
Global Const $_g__WMCDIPC_tagCOPYDATA = 'ulong_ptr dwData;dword cbData;ptr lpData'
Global Const $_g__WMCDIPC_WM_COPYDATA = 0x004A, $_g__WMCDIPC_MSGFLT_ALLOW = 1
Global $_g__WMCDIPC_tData, $_g__WMCDIPC_tBuffer, $_g__WMCDIPC_AdlibTime = 20 ; mSec
Global $_g__WMCDIPC_Version = "2.1.1", $_g__WMCDIPC_message[$eWMCDIPC_UBound] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Global $_g__WMCDIPC_AdlibFunc = WMCDIPC_UserAdlibFuncExample ; example of the func that would do whatever you need done
Global $_g__WMCDIPC_hPrintCallback = (WMCDIPC_Compiled() ? "" : ConsoleWrite)


Func WMCDIPC_Version() ; just in case there are future versions
    Return $_g__WMCDIPC_Version
EndFunc   ;==>WMCDIPC_Version

Func WMCDIPC_PrintCallback($hPrintCallback = Null)
    Switch $hPrintCallback
        Case "" ; disable it
            $_g__WMCDIPC_hPrintCallback = ""
        Case Default ; ConsoleWrite
            $_g__WMCDIPC_hPrintCallback = ConsoleWrite
        Case Null
        Case Else ; your own "ConsoleWrite" function
            If IsFunc($hPrintCallback) Then
                $_g__WMCDIPC_hPrintCallback = $hPrintCallback
            Else
                __WMCDIPC_Print('"WMCDIPC.au3" (' & @ScriptLineNumber & ") : WMCDIPC_PrintCallback: the func was not found !!!" & @CRLF)
                SetError(1)
            EndIf
    EndSwitch
    Return $_g__WMCDIPC_hPrintCallback
EndFunc   ;==>WMCDIPC_PrintCallback

Func WMCDIPC_MsgData($iDone = 0) ; data back and forth via this function
    Local $iFuncsCurrRegistered = -1
    If $iDone Then
        $_g__WMCDIPC_message[$eWMCDIPC_Adlib] = 0
    Else
        $iFuncsCurrRegistered = ($_g__WMCDIPC_AdlibFunc = "" ? -2 : AdlibUnRegister(FuncName($_g__WMCDIPC_AdlibFunc)))
    EndIf
    Return SetError(0, $iFuncsCurrRegistered, $_g__WMCDIPC_message)
EndFunc   ;==>WMCDIPC_MsgData

Func WMCDIPC_Register() ; register it to receive messages
    Local $iWarning = 0
    If Opt("GUIOnEventMode") And Not IsFunc($_g__WMCDIPC_AdlibFunc) Then
        __WMCDIPC_Print('"WMCDIPC.au3" (' & @ScriptLineNumber & ") : WMCDIPC_Register: GUIOnEventMode without a func !!!" & @CRLF)
        $iWarning = 1
    ElseIf Opt("GUIOnEventMode") And $_g__WMCDIPC_AdlibFunc = WMCDIPC_UserAdlibFuncExample Then
        __WMCDIPC_Print('"WMCDIPC.au3" (' & @ScriptLineNumber & ") : WMCDIPC_Register: GUIOnEventMode without a user func !!!" & @CRLF)
        $iWarning = 2
    EndIf
    Local $iRet = GUIRegisterMsg($_g__WMCDIPC_WM_COPYDATA, WMCDIPC_MsgHandler)
    Return SetError(Not $iRet, $iWarning, $iRet)
EndFunc   ;==>WMCDIPC_Register

Func WMCDIPC_AdlibFunc($function = Default) ; function to handle the message received
    If $function <> Default Then
        If StringLen($function) Then
            __WMCDIPC_Print('"WMCDIPC.au3" (' & @ScriptLineNumber & ") : WMCDIPC_AdlibFunc: FunName as string !!!" & @CRLF)
            SetError(3)
        EndIf
        If IsFunc($function) = 1 Then
            $_g__WMCDIPC_AdlibFunc = $function
        ElseIf $function = "" Then
            $_g__WMCDIPC_AdlibFunc = ""
            If Opt("GUIOnEventMode") Then
                __WMCDIPC_Print('"WMCDIPC.au3" (' & @ScriptLineNumber & ") : WMCDIPC_AdlibFunc: GUIOnEventMode=1 !!!" & @CRLF)
                SetError(2) ; flag that it will fail ? v2.1.1 ?
            EndIf
        Else
            SetError(1)
        EndIf
    EndIf
    Return $_g__WMCDIPC_AdlibFunc
EndFunc   ;==>WMCDIPC_AdlibFunc

Func WMCDIPC_AdlibTime($iTimeInMSec = Default) ; AdlibRegister's, time to trigger. 20 mSec worked fine on my PC.
    ; Note: the time parameter should be used carefully to avoid CPU load. ( from the help file )
    If Int($iTimeInMSec) > 0 Then
        $_g__WMCDIPC_AdlibTime = Int($iTimeInMSec)
    ElseIf Int($iTimeInMSec) < 1 Then
        __WMCDIPC_Print('"WMCDIPC.au3" (' & @ScriptLineNumber & ") : WMCDIPC_AdlibTime: time needs a positive integer of X mSec !!!" & @CRLF)
        Return SetError(1)
    EndIf
    Return $_g__WMCDIPC_AdlibTime
EndFunc   ;==>WMCDIPC_AdlibTime

Func WMCDIPC_AdlibRegister($function = Default, $iTimeInMSec = Default)
    Local $newFunc, $newTime, $iError = 0
    If $function <> Default Then
        $newFunc = WMCDIPC_AdlibFunc($function)
        If @error Then $iError += 1
    EndIf
    If $iTimeInMSec <> Default Then
        $newTime = WMCDIPC_AdlibTime($iTimeInMSec)
        If @error Then $iError += 2
    EndIf
    Return SetError($iError, $newTime, $newFunc)
EndFunc   ;==>WMCDIPC_AdlibRegister

Func WMCDIPC_MSGFLT_AllAllowed() ; to have user and admin level interaction, if that is what you need
    If IsAdmin() And Not __WMCDIPC_WinAPI_ChangeWindowMessageFilterEx(0, $_g__WMCDIPC_WM_COPYDATA, $_g__WMCDIPC_MSGFLT_ALLOW) Then Return SetError(1)
EndFunc   ;==>WMCDIPC_MSGFLT_AllAllowed

Func WMCDIPC_Send($hSender, $hReciever, $iMsg, $sMsg)
    If Not IsHWnd($hReciever) Then Return SetError(1, 0, False)
    If StringStripWS($sMsg, 8) = '' Then Return SetError(2, 0, False)
    If Not IsInt($iMsg) Then $iMsg = 0
    $_g__WMCDIPC_tBuffer = DllStructCreate('wchar cdata[' & StringLen($sMsg) + 1 & ']')
    DllStructSetData($_g__WMCDIPC_tBuffer, 'cdata', $sMsg)
    $_g__WMCDIPC_tData = DllStructCreate($_g__WMCDIPC_tagCOPYDATA)
    DllStructSetData($_g__WMCDIPC_tData, 'dwData', $iMsg)
    DllStructSetData($_g__WMCDIPC_tData, 'cbData', DllStructGetSize($_g__WMCDIPC_tBuffer))
    DllStructSetData($_g__WMCDIPC_tData, 'lpData', DllStructGetPtr($_g__WMCDIPC_tBuffer))
    __WMCDIPC_SendMessage($hReciever, $_g__WMCDIPC_WM_COPYDATA, $hSender, DllStructGetPtr($_g__WMCDIPC_tData))
    Return Not @error
EndFunc   ;==>WMCDIPC_Send

Func WMCDIPC_MsgHandler($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg
    Local $iBusy = 0, $hTimer = TimerInit()
    $_g__WMCDIPC_message[$eWMCDIPC_MsgCounter] += 1
    $_g__WMCDIPC_tData = DllStructCreate($_g__WMCDIPC_tagCOPYDATA, $lParam)
    $_g__WMCDIPC_tBuffer = DllStructCreate('wchar cdata[' & DllStructGetData($_g__WMCDIPC_tData, 'cbData') / 2 & ']', DllStructGetData($_g__WMCDIPC_tData, 'lpData'))
    Local $iInt = DllStructGetData($_g__WMCDIPC_tData, 'dwData'), $sStr = DllStructGetData($_g__WMCDIPC_tBuffer, 'cdata')
    If $_g__WMCDIPC_message[$eWMCDIPC_Adlib] Then ; return to sender a busy signal and time spent since last message caught
        $iBusy = 1
        WMCDIPC_Send($hWnd, $wParam, 0xFADE, Round(TimerDiff($_g__WMCDIPC_message[$eWMCDIPC_TimerInit])) & " (mSec Busy)")
    Else
        $_g__WMCDIPC_message[$eWMCDIPC_receiver] = $hWnd ; Self GUI
        $_g__WMCDIPC_message[$eWMCDIPC_iMsg] = $iMsg
        $_g__WMCDIPC_message[$eWMCDIPC_sender] = $wParam ; Sender's GUI
        $_g__WMCDIPC_message[$eWMCDIPC_int] = $iInt
        $_g__WMCDIPC_message[$eWMCDIPC_string] = $sStr
        $_g__WMCDIPC_message[$eWMCDIPC_TimerDiff] = TimerDiff($hTimer)
        $_g__WMCDIPC_message[$eWMCDIPC_TimerInit] = $hTimer
        $_g__WMCDIPC_message[$eWMCDIPC_CaughtCounter] += 1
        $_g__WMCDIPC_message[$eWMCDIPC_Adlib] = ($_g__WMCDIPC_AdlibFunc = "" ? 1 : AdlibRegister(FuncName($_g__WMCDIPC_AdlibFunc), $_g__WMCDIPC_AdlibTime))
        ; Note: The adlib function should be kept simple as during this time the main script is paused. ( from the help file )
    EndIf
    __WMCDIPC_Print('"WMCDIPC.au3" (' & @ScriptLineNumber & ") : WMCDIPC_MsgHandler (" & $_g__WMCDIPC_message[$eWMCDIPC_CaughtCounter] & "/" & _
            $_g__WMCDIPC_message[$eWMCDIPC_MsgCounter] & "):  Timer: " & Round(TimerDiff($_g__WMCDIPC_message[$eWMCDIPC_TimerInit])) & _
            " mSec ( Busy: " & $iBusy & " )" & @TAB & '0x' & Hex($iInt, 4) & @TAB & $sStr & @CRLF)
    Return 'GUI_RUNDEFMSG'
EndFunc   ;==>WMCDIPC_MsgHandler

Func __WMCDIPC_Print($sText)
    If $_g__WMCDIPC_hPrintCallback = "" Then Return
    If IsFunc($_g__WMCDIPC_hPrintCallback) Then $_g__WMCDIPC_hPrintCallback($sText)
EndFunc   ;==>__WMCDIPC_Print


#Region from UDFs

Func __WMCDIPC_SendMessage($hWnd, $iMsg, $wParam = 0, $lParam = 0, $iReturn = 0, $wParamType = "wparam", $lParamType = "lparam", $sReturnType = "lresult") ; same as SendMessage()
    Local $aCall = DllCall("user32.dll", $sReturnType, "SendMessageW", "hwnd", $hWnd, "uint", $iMsg, $wParamType, $wParam, $lParamType, $lParam)
    If @error Then Return SetError(@error + 10, @extended, "")
    If $iReturn >= 0 And $iReturn <= 4 Then Return $aCall[$iReturn]
    Return $aCall
EndFunc   ;==>__WMCDIPC_SendMessage

Func __WMCDIPC_WinAPI_ChangeWindowMessageFilterEx($hWnd, $iMsg, $iAction) ; same as _WinAPI_ChangeWindowMessageFilterEx()
    Local $tCFS, $aCall
    If $hWnd And (__WMCDIPC_WinAPI_GetVersion() > 6.0) Then
        Local Const $tagCHANGEFILTERSTRUCT = 'dword cbSize; dword ExtStatus'
        $tCFS = DllStructCreate($tagCHANGEFILTERSTRUCT)
        DllStructSetData($tCFS, 1, DllStructGetSize($tCFS))
        $aCall = DllCall('user32.dll', 'bool', 'ChangeWindowMessageFilterEx', 'hwnd', $hWnd, 'uint', $iMsg, 'dword', $iAction, 'struct*', $tCFS)
    Else
        $tCFS = 0
        $aCall = DllCall('user32.dll', 'bool', 'ChangeWindowMessageFilter', 'uint', $iMsg, 'dword', $iAction)
    EndIf
    If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, 0)
    Return SetExtended(DllStructGetData($tCFS, 2), 1)
EndFunc   ;==>__WMCDIPC_WinAPI_ChangeWindowMessageFilterEx

Func __WMCDIPC_WinAPI_GetVersion() ; same as _WinAPI_GetVersion()
    Local Const $tagOSVERSIONINFO = "struct;dword OSVersionInfoSize;dword MajorVersion;dword MinorVersion;dword BuildNumber;dword PlatformId;wchar CSDVersion[128];endstruct"
    Local $NUMBER_DOUBLE = 3, $tOSVI = DllStructCreate($tagOSVERSIONINFO)
    DllStructSetData($tOSVI, 1, DllStructGetSize($tOSVI))
    Local $aCall = DllCall('kernel32.dll', 'bool', 'GetVersionExW', 'struct*', $tOSVI)
    If @error Or Not $aCall[0] Then Return SetError(@error, @extended, 0)
    Return Number(DllStructGetData($tOSVI, 2) & "." & DllStructGetData($tOSVI, 3), $NUMBER_DOUBLE)
EndFunc   ;==>__WMCDIPC_WinAPI_GetVersion

#EndRegion from UDFs

#Region example ( and default handler )

Func WMCDIPC_UserAdlibFuncExample() ; example of what to do with the data received
    Local $aDataArray = WMCDIPC_MsgData() ; "WMCDIPC_MsgData()" will AdlibUnRegister() and get the message data

    ; --------- your code here ------8<---------
    Local $sStr = (@AutoItX64 ? "64bit" : "32bit") & " / " & (IsAdmin() ? "Admin" : "User") & ' ( UDF ver.: ' & WMCDIPC_Version() & ' )' & @CRLF & @CRLF
    $sStr &= "-   receiver >" & $aDataArray[$eWMCDIPC_receiver] & '<' & @CRLF
    $sStr &= "-       iMsg >0x" & Hex($aDataArray[$eWMCDIPC_iMsg], 4) & '<' & @CRLF
    $sStr &= "-     sender >" & $aDataArray[$eWMCDIPC_sender] & '<' & @CRLF
    $sStr &= "-       data >" & $aDataArray[$eWMCDIPC_int] & '< ' & Mod($aDataArray[$eWMCDIPC_int], 2) & @CRLF
    $sStr &= "-     string >" & $aDataArray[$eWMCDIPC_string] & '<' & @CRLF & @CRLF
    $sStr &= "- MsgHandler >" & $aDataArray[$eWMCDIPC_TimerDiff] & '< time spent receiving' & @CRLF
    $sStr &= "- MsgHandler >" & TimerDiff($aDataArray[$eWMCDIPC_TimerInit]) & '< time it took to get here' & @CRLF
    $sStr &= "- MsgHandler >" & $aDataArray[$eWMCDIPC_MsgCounter] & '< Messages in count' & @CRLF
    $sStr &= "- MsgHandler >" & $aDataArray[$eWMCDIPC_CaughtCounter] & '< Messages caught count' & @CRLF
    $sStr &= @CRLF
    If Not WMCDIPC_Compiled() Then ConsoleWrite((WMCDIPC_Compiled() ? '@@ Debug' : '"WMCDIPC.au3"') & ' (' & @ScriptLineNumber & ') : ' & $sStr)
    ; --------- your code here ------>8---------

    WMCDIPC_MsgData(1) ; "WMCDIPC_MsgData(1)" at the end to allow a next message
EndFunc   ;==>WMCDIPC_UserAdlibFuncExample

#EndRegion example ( and default handler )

#Au3Stripper_On

The back story
I put together "Win 11 - My own border color" and looking at the logs I've found that I had a handle leak. The leak got fixed but I wanted ( out of OCD ? ) to have the script report on it's status. Ok, easy enough, I'll IPC the request. But I don't wanna have it in the main loop, constantly asking "are we there yet ?, are we there yet ?,  ..." .
I could not find a copy'n'paste UDF, that did that I wanted to have, so I had to code it 🥲
Now you can copy'n'paste it ;)

How does it work:
When WM_COPYDATA gets a message, it puts the data in a global array that gets accessed by any user function triggered by AdlibRegister() after X mSec.
You can set the AdlibRegister() time with WMCDIPC_AdlibTime(). Without a parameter it will return the current value.
Can set the user function with WMCDIPC_AdlibFunc()**. Without a parameter it will return the current value. The UDF has notes that will hint it's use.

Hope you find it useful.

Edit: This is v2.0 ( yey ! )
** there now is a WMCDIPC_AdlibRegister(func,time) that can do that too.
This version allows running all Au3Stripper arguments, so that's good.
Added WMCDIPC_PrintCallback() to handle the one line of debug in the UDF.
Also added a return in case the script is already busy running in Adlib, therefore unable to process the IPC request right there and then. The int return is "0xFADE" and the string has how many mSec it's been busy. Giving the user a chance to know it "FADEd away" and formulate a resend or what not.
Since is a new version, added WMCDIPC_Version(), just in case of a future one.
But all in all, I think that this UDF is complete and needs no other functionality for the scenario it would be used at.

Edit: This is v2.1 ( wow ! )
Added in the loop. Why ?. Well, the project that I wrote this for is GUIOnEventMode=1. Having the "are we there yet ?" is much slower given that a long Sleep() is common in that option.
But the example I posted is GUIOnEventMode=0. It does use GUIGetMsg() to handle messages and CPU usage so, why not have the trigger right there. So that's what I added in this version. And obviously responds much faster than scheduling an Adlib.

Edit: ..and this is v2.1.1 ( child proofing ? )
I was thinking that it would be nice to tell, the new to this UDF, that a set of choices would not work ( not as extreme as in MsgBox_Extn() but, something ).
Also to run ControlViewer just in case of an "oops".

Spoiler

image.thumb.png.3f87b54499533afedbc39a52f0cb6f68.png

where you can select a script, press DEL, and process close it, if something went wrong. ( and I use it a lot :lol: )
So there: for all those that should be sleeping at 3 AM but want to code and screw up, because the brain is sleeping regardless of will.

Edited by argumentum
v2.1.1

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted

Thanks @argumentum , I am quite sure I will have a deeper look into this 👌 .

Best regards
Sven

==> AutoIt related: 🔗 Organization AutoIt Community🔗 GitHub, 🔗 Discord Server, 🔗 Cheat Sheet🔗 autoit-webdriver-boilerplate

Spoiler

🌍 Au3Forums

🎲 AutoIt (en) Cheat Sheet

📊 AutoIt limits/defaults

💎 Code Katas: [...] (comming soon)

🎭 Collection of GitHub users with AutoIt projects

🐞 False-Positives

🔮 Me on GitHub

💬 Opinion about new forum sub category

📑 UDF wiki list

✂ VSCode-AutoItSnippets

📑 WebDriver FAQs

👨‍🏫 WebDriver Tutorial (coming soon)

  • Solution
Posted (edited)

hmmm, .. v2.1.1 ( child roof )
( ..am the child most of the times when I screw up something obvious )


..when I do something wrong in SQLite it tells me what and where.
Most users don't add error checking so having a console warning is quite helpful.

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

  • 11 months later...

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
×
×
  • Create New...