Jump to content
Sign in to follow this  
timmy2

Need help using WM_CopyData to pass values

Recommended Posts

timmy2

The following is a script from Eukalyptus that plays an audio file and displays an FFT Visualization. Let's call it the "Child".

My goal is to be able to close it AND to send volume-level change commands from a Parent program (script farther below). I'm trying to use WM_CopyData for IPC but it's not working for me. Part of my problem is I'm unsure about what's needed to initialize WM_CopyData in the Parent program -- if this is even necessary.  I realize I could use the MailSlot UDF for this but would like to give WM_CopyData a go first, based on Guinness's recommendation. Once I get WM_CopyData working I might even try to use it to close the Child program.

Other issues I'm unsure about are:

1. can I send decimal values via WM_CopyData_Send() ?  (BASS_SetVolume() needs values between 0 and 1)

2. at the receiving end in the Child am I using the proper variable type and format for BASS_SetVolume()?

 

"Child" (must be compiled and named "FFT-Viz-WM_CopyData" so Parent can run it)

#AutoIt3Wrapper_UseX64=n

#include "Bass.au3"
#include "BassExt.au3"
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include 'WM_COPYDATA.au3'

Opt("MustDeclareVars", 1)

_WM_COPYDATA_SetID('MyUniqueID')  ; set ID for WM_CopyData


Global $sFile = FileOpenDialog("Open...", "..\audiofiles", "playable formats (*.MP3;*.MP2;*.MP1;*.OGG;*.WAV;*.AIFF;*.AIF)")
If @error Or Not FileExists($sFile) Then Exit

Global $iWidth = 522
Global $iHeight = 170

Global $hGui = GUICreate("FFT", $iWidth, $iHeight, -1, -1, BitOR($WS_SYSMENU, $WS_POPUP))
GUISetOnEvent($GUI_EVENT_CLOSE, "_EXIT")
_GDIPlus_Startup()
Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui)
Global $hBmp_Buffer = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
Global $hGfx_Buffer = _GDIPlus_ImageGetGraphicsContext($hBmp_Buffer)
_GDIPlus_GraphicsSetSmoothingMode($hGfx_Buffer, 2)

Global $hBrush = _CreateFFTBrush(5, 5, $iWidth - 10, $iHeight - 10)

GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GUISetState()

_BASS_Startup()
_BASS_EXT_Startup()
_BASS_Init(0, -1, 44100, 0, "")

Global $hStream = _BASS_StreamCreateFile(False, $sFile, 0, 0, $BASS_SAMPLE_FLOAT)
Global $aFFT = _BASS_EXT_CreateFFT(128, 5, 5, $iWidth - 10, $iHeight - 10, 1, True)

_BASS_ChannelPlay($hStream, True)

Local $iControlID = _WM_COPYDATA_Start($hGui) ; Start the communication process.
Global $iTimer = TimerInit()
While _BASS_ChannelIsActive($hStream)
    If TimerDiff($iTimer) > 20 Then

        Switch GuiGetMsg()
            Case -3    ; allows Parent program to use WinClose to close this program.
                ExitLoop
            Case $iControlID   ; if the Parent program sends a volume change value via WM_CopyData
                Local $volumelevel = _WM_COPYDATA_GetData()
                _BASS_SetVolume($volumelevel)
                Beep(1000, 100)  ; for testing purposes to see if this Case ever gets triggered
        EndSwitch

        $iTimer = TimerInit()
        _GDIPlus_GraphicsClear($hGfx_Buffer, 0xFF110022)

        _BASS_EXT_ChannelGetFFT($hStream, $aFFT, 2)
        If Not @error Then DllCall($ghGDIPDll, "int", "GdipFillPolygon", "handle", $hGfx_Buffer, "handle", $hBrush, "ptr", $aFFT[0], "int", $aFFT[1], "int", "FillModeAlternate")

        _GDIPlus_GraphicsDrawImage($hGraphics, $hBmp_Buffer, 0, 0)
    EndIf
WEnd
_Exit()



Func _CreateFFTBrush($iX, $iY, $iWidth, $iHeight)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    Local $hBrush_FFT = _GDIPlus_LineBrushCreate(0, 0, 0, $iHeight, 0, 0, 3)
    Local $aColors[5][2] = [[4]]
    $aColors[1][0] = 0xFFFF0000
    $aColors[1][1] = 0
    $aColors[2][0] = 0xFFFFAA00
    $aColors[2][1] = 0.25
    $aColors[3][0] = 0xFF00AAFF
    $aColors[3][1] = 0.5
    $aColors[4][0] = 0xFF00AAFF
    $aColors[4][1] = 1
    _GDIPlus_LineBrushSetPresetBlend($hBrush_FFT, $aColors)

    Local $hBrush_LED = _GDIPlus_LineBrushCreate(0, 0, 0, 4, 0xAA000000, 0x00000000, 0)

    _GDIPlus_GraphicsFillRect($hContext, 0, 0, $iWidth, $iHeight, $hBrush_FFT)
    _GDIPlus_GraphicsFillRect($hContext, 0, 0, $iWidth, $iHeight, $hBrush_LED)
    _GDIPlus_BrushDispose($hBrush_LED)
    _GDIPlus_BrushDispose($hBrush_FFT)
    _GDIPlus_GraphicsDispose($hContext)

    Local $hBrush = _GDIPlus_TextureCreate($hBitmap)
    _GDIPlus_BitmapDispose($hBitmap)

    DllCall($ghGDIPDll, "uint", "GdipTranslateTextureTransform", "hwnd", $hBrush, "float", $iX, "float", $iY, "int", 0)

    Return $hBrush
EndFunc   ;==>_CreateFFTBrush



Func WM_PAINT($hWnd, $uMsgm, $wParam, $lParam)
    _GDIPlus_GraphicsDrawImage($hGraphics, $hBmp_Buffer, 0, 0)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_PAINT

; #FUNCTION# ====================================================================================================================
; Author ........: Authenticity
; Modified.......: UEZ
; ===============================================================================================================================
Func _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $iPixelFormat = $GDIP_PXF32ARGB, $iStride = 0, $pScan0 = 0)
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", $iStride, "int", $iPixelFormat, "ptr", $pScan0, "handle*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    If $aResult[0] Then Return SetError(10, $aResult[0], 0)

    Return $aResult[6]
EndFunc   ;==>_GDIPlus_BitmapCreateFromScan0


; #FUNCTION# ====================================================================================================================
; Author ........: Authenticity
; Modified.......: UEZ
; ===============================================================================================================================
Func _GDIPlus_LineBrushCreate($nX1, $nY1, $nX2, $nY2, $iARGBClr1, $iARGBClr2, $iWrapMode = 0)
    Local $tPointF1, $tPointF2, $aResult
    $tPointF1 = DllStructCreate("float;float")
    $tPointF2 = DllStructCreate("float;float")
    DllStructSetData($tPointF1, 1, $nX1)
    DllStructSetData($tPointF1, 2, $nY1)
    DllStructSetData($tPointF2, 1, $nX2)
    DllStructSetData($tPointF2, 2, $nY2)
    $aResult = DllCall($ghGDIPDll, "int", "GdipCreateLineBrush", "struct*", $tPointF1, "struct*", $tPointF2, "uint", $iARGBClr1, "uint", $iARGBClr2, "int", $iWrapMode, "handle*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    If $aResult[0] Then Return SetError(10, $aResult[0], 0)

    Return $aResult[6]
EndFunc   ;==>_GDIPlus_LineBrushCreate


; #FUNCTION# ====================================================================================================================
; Author ........: Authenticity
; Modified.......: UEZ
; ===============================================================================================================================
Func _GDIPlus_LineBrushSetPresetBlend($hLineGradientBrush, $aInterpolations)
    Local $iI, $iCount, $tColors, $tPositions, $aResult
    $iCount = $aInterpolations[0][0]
    $tColors = DllStructCreate("uint[" & $iCount & "]")
    $tPositions = DllStructCreate("float[" & $iCount & "]")
    For $iI = 1 To $iCount
        DllStructSetData($tColors, 1, $aInterpolations[$iI][0], $iI)
        DllStructSetData($tPositions, 1, $aInterpolations[$iI][1], $iI)
    Next
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetLinePresetBlend", "handle", $hLineGradientBrush, "struct*", $tColors, "struct*", $tPositions, "int", $iCount)
    If @error Then Return SetError(@error, @extended, False)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)

    Return True
EndFunc   ;==>_GDIPlus_LineBrushSetPresetBlend


; #FUNCTION# ====================================================================================================================
; Author ........: Authenticity
; Modified.......: UEZ
; ===============================================================================================================================
Func _GDIPlus_TextureCreate($hImage, $iWrapMode = 0)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateTexture", "handle", $hImage, "int", $iWrapMode, "handle*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    If $aResult[0] Then Return SetError(10, $aResult[0], 0)

    Return $aResult[3]
EndFunc   ;==>_GDIPlus_TextureCreate



Func _Exit()
    _BASS_StreamFree($hStream)
    _BASS_Free()

    _WM_COPYDATA_Shutdown()

    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGfx_Buffer)
    _GDIPlus_BitmapDispose($hBmp_Buffer)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_Shutdown()
    Exit
EndFunc   ;==>_Exit

And here's the Parent program, which you can run from SciTE.

#include "ExtMsgBox.au3"
#Include <WinAPIEx.au3>
#include 'WM_COPYDATA.au3'

;_WM_COPYDATA_SetID('MyUniqueIDC')  ; NOT SURE IF I NEED THIS

;Local $iControlID = _WM_COPYDATA_Start(Default) ; Start the communication process. NOT SURE IF I NEED THIS

$wPID = run ("FFT-Viz-WM_CopyData.exe")

sleep(2000)

_ExtMsgBox(0,0,"","press enter to reduce volume",0,1,1)
_WM_COPYDATA_Send(.2)  ;can WM_CopyData send values like this or must they be strings?


_ExtMsgBox(0,0,"","press enter to raise volume",0,1,1)
_WM_COPYDATA_Send(1)

_ExtMsgBox(0,0,"","press enter to exit",0,1,1)

$aData = _WinAPI_EnumProcessWindows ($wPID)
ConsoleWrite($aData[1][0] & @LF)
Sleep(2000)
$result = WinClose($aData[1][0])
ConsoleWrite ("winclose issued! Result = " & $result & @LF)
sleep (2000)

;_WM_COPYDATA_Shutdown()  ;NOT SURE IF I NEED THIS

Exit

Share this post


Link to post
Share on other sites
UEZ

Can you try this:

 

Main.au3

#AutoIt3Wrapper_UseX64=n
#include "ExtMsgBox.au3"
#include <WindowsConstants.au3>

GUIRegisterMsg($WM_COPYDATA, '_WM_COPYDATA')
$TITLE_RECEIVER = 'FFT_Child_Window'
$wPID = Run("Child.exe")

Sleep(2000)

_ExtMsgBox(0, 0, "", "press enter to reduce volume", 0, 1, 1)
_SendData(WinGetHandle($TITLE_RECEIVER), 0.1)

_ExtMsgBox(0, 0, "", "press enter to raise volume", 0, 1, 1)
_SendData(WinGetHandle($TITLE_RECEIVER), 0.5)

_ExtMsgBox(0, 0, "", "press enter to exit", 0, 1, 1)

_SendData(WinGetHandle($TITLE_RECEIVER), -1)

Sleep(2000)

Exit

Func _SendData($hWnd, $sData)
    Local $tCOPYDATA, $tMsg

    $tMsg = DllStructCreate('char[' & StringLen($sData) + 1 & ']')
    DllStructSetData($tMsg, 1, $sData)
    $tCOPYDATA = DllStructCreate('dword;dword;ptr')
    DllStructSetData($tCOPYDATA, 2, StringLen($sData) + 1)
    DllStructSetData($tCOPYDATA, 3, DllStructGetPtr($tMsg))
    $Ret = DllCall('user32.dll', 'lparam', 'SendMessage', 'hwnd', $hWnd, 'int', $WM_COPYDATA, 'wparam', 0, 'lparam', DllStructGetPtr($tCOPYDATA))
    If (@error) Or ($Ret[0] = -1) Then
        Return 0
    EndIf
    Return 1
EndFunc   ;==>_SendData

Func _WM_COPYDATA($hWnd, $msgID, $wParam, $lParam)

    Local $tCOPYDATA = DllStructCreate('dword;dword;ptr', $lParam)
    Local $tMsg = DllStructCreate('char[' & DllStructGetData($tCOPYDATA, 2) & ']', DllStructGetData($tCOPYDATA, 3))

    Return 0
EndFunc   ;==>_WM_COPYDATA

Child.au3

#AutoIt3Wrapper_UseX64=n

#include "Bass.au3"
#include "BassExt.au3"
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1)


Global $sFile = FileOpenDialog("Open...", "", "playable formats (*.MP3;*.MP2;*.MP1;*.OGG;*.WAV;*.AIFF;*.AIF)", 3)
If @error Or Not FileExists($sFile) Then Exit

Global $iWidth = 522
Global $iHeight = 170

_GDIPlus_Startup()
Global $hGui = GUICreate("FFT_Child_Window", $iWidth, $iHeight, -1, -1, BitOR($WS_SYSMENU, $WS_POPUP))
GUISetState()

Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui)
Global $hBmp_Buffer = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
Global $hGfx_Buffer = _GDIPlus_ImageGetGraphicsContext($hBmp_Buffer)
_GDIPlus_GraphicsSetSmoothingMode($hGfx_Buffer, 2)

Global $hBrush = _CreateFFTBrush(5, 5, $iWidth - 10, $iHeight - 10)

Global $sMsg

_BASS_Startup()
_BASS_EXT_Startup()
_BASS_Init(0, -1, 44100, 0, "")

Global $hStream = _BASS_StreamCreateFile(False, String($sFile), 0, 0, $BASS_SAMPLE_FLOAT)
If Not $hStream Then _Exit()
Global $aFFT = _BASS_EXT_CreateFFT(128, 5, 5, $iWidth - 10, $iHeight - 10, 1, True)

_BASS_ChannelPlay($hStream, True)

Global $dummy = GUICtrlCreateDummy()

GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GUIRegisterMsg($WM_COPYDATA, '_WM_COPYDATA')

While _BASS_ChannelIsActive($hStream)
    Switch GUIGetMsg()
        Case -3, $dummy ; allows Parent program to use WinClose to close this program.
            ExitLoop
    EndSwitch

    _GDIPlus_GraphicsClear($hGfx_Buffer, 0xFF110022)

    _BASS_EXT_ChannelGetFFT($hStream, $aFFT, 2)
    If Not @error Then DllCall($ghGDIPDll, "int", "GdipFillPolygon", "handle", $hGfx_Buffer, "handle", $hBrush, "ptr", $aFFT[0], "int", $aFFT[1], "int", "FillModeAlternate")

    _GDIPlus_GraphicsDrawImage($hGraphics, $hBmp_Buffer, 0, 0)
WEnd

_Exit()

Func _WM_COPYDATA($hWnd, $msgID, $wParam, $lParam)
    Local $tCOPYDATA = DllStructCreate('dword;dword;ptr', $lParam)
    Local $tMsg = DllStructCreate('char[' & DllStructGetData($tCOPYDATA, 2) & ']', DllStructGetData($tCOPYDATA, 3))

    $sMsg = DllStructGetData($tMsg, 1)
    Switch $sMsg
        Case 0.0 To 1.0
            _BASS_SetVolume($sMsg)
        Case -1
            GUICtrlSendToDummy($Dummy)
    EndSwitch
    Return 0
EndFunc   ;==>_WM_COPYDATA

Func _CreateFFTBrush($iX, $iY, $iWidth, $iHeight)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    Local $hBrush_FFT = _GDIPlus_LineBrushCreate(0, 0, 0, $iHeight, 0, 0, 3)
    Local $aColors[5][2] = [[4]]
    $aColors[1][0] = 0xFFFF0000
    $aColors[1][1] = 0
    $aColors[2][0] = 0xFFFFAA00
    $aColors[2][1] = 0.25
    $aColors[3][0] = 0xFF00AAFF
    $aColors[3][1] = 0.5
    $aColors[4][0] = 0xFF00AAFF
    $aColors[4][1] = 1
    _GDIPlus_LineBrushSetPresetBlend($hBrush_FFT, $aColors)

    Local $hBrush_LED = _GDIPlus_LineBrushCreate(0, 0, 0, 4, 0xAA000000, 0x00000000, 0)

    _GDIPlus_GraphicsFillRect($hContext, 0, 0, $iWidth, $iHeight, $hBrush_FFT)
    _GDIPlus_GraphicsFillRect($hContext, 0, 0, $iWidth, $iHeight, $hBrush_LED)
    _GDIPlus_BrushDispose($hBrush_LED)
    _GDIPlus_BrushDispose($hBrush_FFT)
    _GDIPlus_GraphicsDispose($hContext)

    Local $hBrush = _GDIPlus_TextureCreate($hBitmap)
    _GDIPlus_BitmapDispose($hBitmap)

    DllCall($ghGDIPDll, "uint", "GdipTranslateTextureTransform", "hwnd", $hBrush, "float", $iX, "float", $iY, "int", 0)

    Return $hBrush
EndFunc   ;==>_CreateFFTBrush

Func WM_PAINT($hWnd, $uMsgm, $wParam, $lParam)
    _GDIPlus_GraphicsDrawImage($hGraphics, $hBmp_Buffer, 0, 0)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_PAINT

; #FUNCTION# ====================================================================================================================
; Author ........: Authenticity
; Modified.......: UEZ
; ===============================================================================================================================
Func _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $iPixelFormat = $GDIP_PXF32ARGB, $iStride = 0, $pScan0 = 0)
    Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", $iStride, "int", $iPixelFormat, "ptr", $pScan0, "handle*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    If $aResult[0] Then Return SetError(10, $aResult[0], 0)

    Return $aResult[6]
EndFunc   ;==>_GDIPlus_BitmapCreateFromScan0


; #FUNCTION# ====================================================================================================================
; Author ........: Authenticity
; Modified.......: UEZ
; ===============================================================================================================================
Func _GDIPlus_LineBrushCreate($nX1, $nY1, $nX2, $nY2, $iARGBClr1, $iARGBClr2, $iWrapMode = 0)
    Local $tPointF1, $tPointF2, $aResult
    $tPointF1 = DllStructCreate("float;float")
    $tPointF2 = DllStructCreate("float;float")
    DllStructSetData($tPointF1, 1, $nX1)
    DllStructSetData($tPointF1, 2, $nY1)
    DllStructSetData($tPointF2, 1, $nX2)
    DllStructSetData($tPointF2, 2, $nY2)
    $aResult = DllCall($ghGDIPDll, "int", "GdipCreateLineBrush", "struct*", $tPointF1, "struct*", $tPointF2, "uint", $iARGBClr1, "uint", $iARGBClr2, "int", $iWrapMode, "handle*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    If $aResult[0] Then Return SetError(10, $aResult[0], 0)

    Return $aResult[6]
EndFunc   ;==>_GDIPlus_LineBrushCreate


; #FUNCTION# ====================================================================================================================
; Author ........: Authenticity
; Modified.......: UEZ
; ===============================================================================================================================
Func _GDIPlus_LineBrushSetPresetBlend($hLineGradientBrush, $aInterpolations)
    Local $iI, $iCount, $tColors, $tPositions, $aResult
    $iCount = $aInterpolations[0][0]
    $tColors = DllStructCreate("uint[" & $iCount & "]")
    $tPositions = DllStructCreate("float[" & $iCount & "]")
    For $iI = 1 To $iCount
        DllStructSetData($tColors, 1, $aInterpolations[$iI][0], $iI)
        DllStructSetData($tPositions, 1, $aInterpolations[$iI][1], $iI)
    Next
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetLinePresetBlend", "handle", $hLineGradientBrush, "struct*", $tColors, "struct*", $tPositions, "int", $iCount)
    If @error Then Return SetError(@error, @extended, False)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)

    Return True
EndFunc   ;==>_GDIPlus_LineBrushSetPresetBlend


; #FUNCTION# ====================================================================================================================
; Author ........: Authenticity
; Modified.......: UEZ
; ===============================================================================================================================
Func _GDIPlus_TextureCreate($hImage, $iWrapMode = 0)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateTexture", "handle", $hImage, "int", $iWrapMode, "handle*", 0)
    If @error Then Return SetError(@error, @extended, 0)
    If $aResult[0] Then Return SetError(10, $aResult[0], 0)

    Return $aResult[3]
EndFunc   ;==>_GDIPlus_TextureCreate

Func _Exit()
    _BASS_StreamFree($hStream)
    _BASS_Free()

    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hGfx_Buffer)
    _GDIPlus_BitmapDispose($hBmp_Buffer)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_Shutdown()
    Exit
EndFunc   ;==>_Exit

Compile Child.au3 and start Main.au3. Both scripts must be compiled as x86 because of Bass.dll and WM_COPYDATA code.

Br,

UEZ

Edited by UEZ
  • Like 1

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
guinness

You should mention UEZ that your version will only work in AutoIt 32-bit.


UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Share this post


Link to post
Share on other sites
UEZ

@guinness: done.

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
guinness

I did provide a version of WM_COPYDATA that works compiled as x86 and x64 in the form of a manageable UDF. The OP PM'd me earlier today in which I offered help, but they decided to seek advice from the Forum instead.

It seems you have completed the task. Thanks.

Edited by guinness

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Share this post


Link to post
Share on other sites
UEZ

I saw your UDF but I've choosen Yashied's WM_COPYDATA example because it was faster for me to implement it for the code in post #1.

timmy2 can change it to your UDF if he wants but bass.dll is not working as x64 code.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
timmy2

I see that UEZ and Guinness have replied to my post but I've been offline working on a noob-compatible demonstration of the WM_CopyData function, to test my rudimentary understanding of it and to share it. Requires Guinness' WM_CopyData UDF (also provided below). Now that I understand it to this extent I hope I can get it to work with my FFT Visualizer and its test Parent.  :sweating:

"WM_Child.exe"

;"WM_Child" script to demonstrate WM_CopyData function by Guinness
;compile as WM_Child.exe so WM_Parent can run it

#include <Constants.au3>
#include 'WM_COPYDATA.au3'

_WM_COPYDATA_SetID('MyProgUniqueID') ; Create a unique ID.
Local $iWM_COPYDATA = _WM_COPYDATA_Start(Default) ; Start the _WM_COPYDATA message. The first parameter can be your GUI, otherwise it will create a hidden one.
Local $sWM_COPYDATA = ''

HotKeySet("{ESC}","_Exit")

Local $sText = "WM_Child is ready and waiting for a message." & @LF & @LF & "IPC Message: "
SplashTextOn ("WM_Child",$sText,300,200, 0,0,4)

While 1
    Switch GUIGetMsg()
        Case $iWM_COPYDATA ; If the message from the WM_Parent is picked up.
            $sWM_COPYDATA = _WM_COPYDATA_GetData()  ; Get message from WM_Parent
            Switch $sWM_COPYDATA
                Case "Quit"  ; received if user clicked Cancel button
                    _Exit()
                Case "xxx"  ; received if user enterd nothing
                    $sWM_COPYDATA = "(nothing entered)"
            EndSwitch

            ControlSetText ("WM_Child","","Static1", $sText & $sWM_COPYDATA)
    EndSwitch
WEnd

Func _Exit()
    _WM_COPYDATA_Shutdown()  ; shutdown WM_COPYDATA
    SplashOff()
    Exit
EndFunc

WM_Parent

;"WM_Parent" script to demonstrate WM_CopyData function by Guinness
;requires WM_Child.exe present in same folder

#include <Constants.au3>
#include 'WM_COPYDATA.au3'

If FileExists ("WM_Child.exe") then
    Run("WM_Child.exe")
Else
    Beep(300,200)
    SplashTextOn("ERROR","WM_Child.exe not found!",300,75)
    Sleep(2000)
    _Exit()
EndIf

WinWait ("WM_Child")

_WM_COPYDATA_SetID('MyProgUniqueID') ; Create a unique ID.
_WM_COPYDATA_Start(Default) ; Start the _WM_COPYDATA message for the parent script as well. This will grab details about the Child script if it's already running.

While 1

    $sMessage = InputBox("WM_Parent", "Enter value to send to Child: " & @LF & @LF & "(or Cancel to close all)")
    If @Error Then _Exit()
    If $sMessage = "" then $sMessage = "xxx"  ; if user just presses Enter still send something
    _WM_COPYDATA_Send($sMessage) ; Send IPC message

WEnd


Func _Exit()
    _WM_COPYDATA_Send("Quit") ; Send IPC message
    _WM_COPYDATA_Shutdown()  ; Close process
    Exit
EndFunc

Get WM_COPYDATA.au3 UDF >here.

Edited by timmy2

Share this post


Link to post
Share on other sites
timmy2

93fb.jpg Ack!

Thank you, UEZ, these scripts work great!  I have specific questions about your code because you didn't use Guinness' WM_CopyData UDF so I'm back in uncharted territory. I sure hope you'll answer them, because your working scripts (versus my non-working scripts) are quite tempting.  However, I would like to fully understand them, not simply use them.

First, though, If I inadvertently used code intended for 64-bit that was pure keyboard monkey behavior. I don't have the 64b AutoIt installed nor do I want to create any 64b scripts yet. As far as I know my previous post is 32-bit so the few elements of Guinness' UDF that I used must be 32-bit compatible. My impression about BASS is that it is also 32-bit, which must be what you mean by, "bass.dll is not working as x64 code."


Your Parent Script

The most noticeable aspect of your IPC solution, besides not using an external UDF, is there's no ID established before the Parent can send messages addressed to the Child. I assume you accomplish the same thing in the following two lines of code. Please explain in simple, almost-layman terms what each line does, because the Help file explanation of GUIRegisterMsg relies on understanding "Windows Message ID's", which is not in the average AutoIt Beginners lexicon. (Any time a definition relies on understanding the definition of something else equally as advanced, pushes my stack one level too deep.)

GUIRegisterMsg($WM_COPYDATA, '_WM_COPYDATA')$sTITLE_RECEIVER = 'FFT_Child_Window'

Maybe I even understand why you don't need an ID: you already know the Child's Window Title so a simple WinGetHandle provides Child's handle to your own _SendData() function. I assume Yashied's WM_CopyData implementation doesn't need a _Start or _Shutdown, either. Nice, I guess... (I doubt Guinness included them for grins -- he must've had a reason).

I understand why you ditched my use of the WinAPIEx UDF, _WinAPI_EnumProcessWindows, and WinClose: because the Parent is able to close the Child at the end using IPC.


Your Child script.

I started with a very recent post by Eukalyptus of his FFT Visualizer for the Autoit 3.3.8.1, so I'm very curious about any changes you made to it besides changing IPC-related commands.

As in the Parent, you use no ID, _Start or _Shutdown commands.

I'm curious about the line you added just after starting up BASS. (Does it cause an exit if the sound file reaches the end?)

If Not $hStream Then _Exit()  ;  WHAT DOES THIS ACCOMPLISH?

You also added the following line:

Global $dummy = GUICtrlCreateDummy()

... which creates a Dummy control you use later in the pivotal "_WM_COPYDATA function. I've never used this before but maybe the Help file Example will demonstrate its usefulness.


Where it really gets interesting to me (and therefore needs your explanation) is in Eukalyptus' main While/WEnd loop, which I believe displays the FFT visualization. In his latest implementation he added...

Global $iTimer = TimerInit()While _BASS_ChannelIsActive($hStream)    If TimerDiff($iTimer) > 20 Then...    $iTimer = TimerInit()EndIf

which did not exist in his original demonstration script. You removed his new timer-related code. Why?


Also, you left in my code for using WinClose in the parent to close the Child program, but you no longer use WinClose in your Parent script.

Switch GUIGetMsg()        Case -3, $dummy ; allows Parent program to use WinClose to close this program.            ExitLoop    EndSwitch

Can this Switch statement be removed from the Parent script?


Even more significant to me is I thought I would need to look for IPC messages (_WM_COPYDATA_GetData()) inside the main While/WEnd loop, but you don't do it. In fact -- and this is really what puzzles me -- you make volume level changes in a new _WM_COPYDATA function that I don't see referred to anywhere else in your Child script? Being the noob that I am, this qualifies as magic.

Please, UEZ, explain how volume control messages are received and handled.

Also, how does a value of -1 sent via IPC from the Parent interrupt the Child's While/WEnd loop, and then use GUICtrlSendToDummy() to go to the _Exit function? Try to keep your explanation in near-layman terminology so I can really understand what's going on here.

Edited by timmy2

Share this post


Link to post
Share on other sites
guinness

Your post with my UDF demonstrates you understanding of how the UDF works. So I see you now have to implement this into your application, which only you can do really.

Edited by guinness

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Share this post


Link to post
Share on other sites
UEZ

I don't have the 64b AutoIt installed

That's not true. If have AutoIt installed then automatically the x64 files are installed, too. Just look in the AutoIt dir and look for *_x64.* files.

 

 

My impression about BASS is that it is also 32-bit, which must be what you mean by, "bass.dll is not working as x64 code."

When you compile your code as x64 executable and call the bass.dll then probably you code will crash because bass.dll is not x64 compatible. When you start Child.au3 you will have noticed the output:

!Bass.dll is for 32bit only!
Run/compile Script at 32bit

 

 

Your Parent Script

GUIRegisterMsg($WM_COPYDATA, '_WM_COPYDATA')

$sTITLE_RECEIVER = 'FFT_Child_Window'

Using GUIRegisterMsg is a technique to initiate a callback to your function. That means whenever a trigger from the operating system is sent regarding the WM_*  message id you can check it in your function. Here it is done in _WM_COPYDATA function.

As you can see in the variable name the function _SendData uses the GUI name 'FFT_Child_Window' to send information. It would make sense to use here a more unique name rather than a standard name. I didn't test what will happen when more than 1 GUI exits with the same name.

guinness' UDF is based on Yashied's original code but completely redesigned to use it as an UDF.

 

I understand why you ditched my use of the WinAPIEx UDF, _WinAPI_EnumProcessWindows, and WinClose: because the Parent is able to close the Child at the end using IPC.

Because it is not needed anymore. The closure of the child process is also done using WM_COPYDATA.

 

 

If Not $hStream Then _Exit()  ;  WHAT DOES THIS ACCOMPLISH?

This is only a check whether _BASS_StreamCreateFile returns an handle otherwise something went wrong loading the audio file, e.g. corrupted, etc.

 

 

 

I used this function to send the exit trigger to GUIGetMsg(). There is no need in Main.au3 to close the GUI.

 

Switch GUIGetMsg()        

Case -3, $dummy ; allows Parent program to use WinClose to close this program.            

ExitLoop    

EndSwitch

 

-3 is needed only when you want to close the child GUI using the ESC key or by WinClose function. But the GUIGetMsg check is needed for GUICtrlSendToDummy($Dummy)!

 

 

Global $iTimer = TimerInit()While _BASS_ChannelIsActive($hStream)    If TimerDiff($iTimer) > 20 Then...    $iTimer = TimerInit()EndIf

 

Using this timer function causes high CPU load and I cannot see any purpose to use a timer in this loop.

 

 

Please, UEZ, explain how volume control messages are received and handled.

 

The main script sends its first "command" to the child process using this command:

_SendData(WinGetHandle($TITLE_RECEIVER), 0.1)

That means the child process will receive the value 0.1 _WM_COPYDATA function. There, if the sent value is a proper one, it will decide what to do.

$sMsg = DllStructGetData($tMsg, 1)
    Switch $sMsg
        Case 0.0 To 1.0
            _BASS_SetVolume($sMsg)
        Case -1
            GUICtrlSendToDummy($Dummy)
    EndSwitch

We assume that values from 0 to 1 are related to the sound volume. If the child process receives a -1 then the closure of the child process will be initiated by sending the dummy trigger. This will cause the GUIGetMsg to recive the $dummy value which will exit the loop and thus call the _Exit function.

 

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
BrewManNH

Just as an FYI, BASS is available as a set of 64bit dlls .

http://www.un4seen.com/bass.html


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites
UEZ

Right BrewManNH, I forgot to mention it that also x64 DLL are available.

Thx,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


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
Sign in to follow this  

  • Similar Content

    • tatane
      By tatane
      Hi,
      I would like to send an array from a script to a another. This array has 1000 rows and 4 columns with this kind of data :
      1st row  =     528  ;  31  ;   HOSTNAME|1|02:45:47|abcdefgh|username|5   ;   old
      2nd row = ...
      What IPC should I use ?
       
       
    • argumentum
      By argumentum
      I was in need of an IPC (Interprocess communication) between system, admin and user levels, and ended up writing this UDF to suit my wantings.
      Hope you find it useful too.
      Works from WinXP/Server2003 to the now current Win10/Server2016.
      It communicates between any mix of x32, x64, Admin, User.

      In the zip file, there is the UDF and an example: FMIPC(v0.2018.04.04).zip
      Special thanks to @RTFC for the help in the support forum   
    • argumentum
      By argumentum
      There is this topic on Examples about IPC. My question is: What is the best IPC to work with between a script running as SYSTEM level, User level, and Administrator level to interact with each other ? 
      Thanks
    • JohnWIlling
      By JohnWIlling
      IPC_IO.AU3
      I am in the need for a simple synchronous Client/Server communication.  I found several examples and references to various kinds of Inter-Process Communications such as TCP, Named Pipes, Mail Slots, Shared Memory, Memory Mapped Files, and simple Files.  I wanted to see what the best solutions would be.  I began developing a library and slowly began adding each of the IPC methods and ended up with a library with a very simple synchronous “ASCII” API where the application can choose which method to use at startup.
      For the Server side, a Server app must initialize communication by calling:
      Func InitConnection($cType = $cDefaultType, $ResourceName = "", $bBlock = $cDefaultBlocking, $fSleepFunc = "", $iBufSize = $DEFAULT_BUFSIZE)
      The optional arguments allow the app to specify the connection type (such as: $cNamedPipe, $cFile, $cTCP, $cSharedMem, $cMailSlot), a value for the resource name (such as the file, named pipe name, TCP port number, etc.), the communication buffer size, and a callback function for when the “read” is waiting for data.
      A “File Descriptor” is returned and must be used in the future API calls.
      The Server side must then call:
      Func StartConnection($iFD)
      This call waits for a Client to connect.  The Server then calls:
                      Func ReadData($iFD, ByRef $sData)
      To read a Request from the Client and then calls:
                      Func WriteData($iFD, ByRef $sData)
      To send the reply back to the Client.
      When communication with the Client is done, the Server app will call:
      Func StopConnection($iFD)
      When the Server app is done with the communications it will call:
      Func EndConnection($iFD)
       
      For the Client side, a Client app must open the communication by calling:
      Func OpenConnection($cType = $cDefaultType, $ResourceName = "", $bBlock = $cDefaultBlocking, $fSleepFunc = "", $iBufSize = $DEFAULT_BUFSIZE)
      The optional arguments allow the app to specify the connection type (such as: $cNamedPipe, $cFile, $cTCP, $cSharedMem, $cMailSlot), a value for the resource name (such as the file, named pipe name, TCP port number, etc.), the communication buffer size, and a callback function for when the “read” is waiting for data.
      A “File Descriptor” is returned and must be used in the future API calls.
      The Client side then send a request to the Server app by calling:
                      Func WriteData($iFD, ByRef $sData)
      To read a Response from the Server by calling:
                      Func ReadData($iFD, ByRef $sData)
      To end the connection to the Server by calling:
      Func CloseConnection($iFD)
       
      Within the IPC_IO.AU3 library, each IPC method is ether:
      ·         “stream” based where data is read/written by calling _WinAPI_ReadFile/TCPRecv or _WinAPI_WriteFile/ TCPSend
      ·         “direct” based for Shared memory where the Client reads the data directly from the Server App’s memory and the Server directly reads the Client App’s memory
      In processing a request, the “ReadData” process starts by checking if data is ready to be read by calling the routine: “ReadStart”, then it reads in the size of the request by calling “ReadSize”, it then reads in the Ascii Request by calling “ReadBuffer”, then the sequence is completed by calling “ReadEnd”. 
      The Write Process follows the same sequence with “WriteData” calling “WriteStart”, “WriteSize”, “WriteBuffer”, “WriteEnd”.
       
      Results
      My testing showed that the performance of sending and receiving of a 10k file took:
      ·         "Shared Memory" was the fastest, at 0.007468 Sec
      ·         “Named Pipes” at 0.015954
      ·         “Mail Slots” at 0.016427
      ·         “File Based” at 0.270287
      ·         “TCP” at 0.994884
       
      IPC_IO.au3
      Client.au3
      Server.au3
    • dubi
      By dubi
      Hi,


       
      Background: i have a number of instances of the same application that I want to automate in parallel.

      Unfortunately, I cannot completely automate these instances in the background. So, from time to time these instances need to have the focus so that I can interact with the controls via “send” directly.

      Each of the application instances is controlled by a au3 complied script. Each script (called with a parameter) manages the automation of the respective application-instance. Each of the (complied) script (instances) is called by a (central) front end with a gui. The front end controls if the “focus” is available to do the “send” and “mouseclick” modifications. The central front end either allows a child to have the focus or prevents it to get the focus (in which case the child will wait and checks again). The code for the front end is included. Apologies for the lengthy explanation.


      #RequireAdmin #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <EditConstants.au3> #include <GUIEdit.au3> #include <ScrollBarConstants.au3> #include <Array.au3> Global Const $APF_ALLOWMULTILINE = 1 Global Const $APF_RIGHTALIGN = 6 Global Const $APF_RIGHTALIGNCOL = 2 Global Const $APF_RIGHTALIGNDATA = 4 Global Const $APF_PRINTROWNUM = 8 Global Const $APF_DEFAULT = $APF_PRINTROWNUM Global $PID[9], $FocusAvailable = True, $previousEditMsg Global $PID_waiting[0][2], $logfile $logfile = "D:\MultiInstance\Logfiles\FrontEnd.txt" If FileExists($logfile) Then FileDelete($logfile) #Region ### START Koda GUI section ### Form= $hGui_1 = GUICreate("Instanzenmanager", 493, 1226, 1807, 93) $grpInst1 = GUICtrlCreateGroup(" 1 ", 8, 8, 233, 121) $btnPause01 = GUICtrlCreateCheckbox("Pause", 16, 64, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $tbnStop01 = GUICtrlCreateCheckbox("Stop", 16, 96, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnMin01 = GUICtrlCreateCheckbox("Minimize", 72, 64, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnWdh01 = GUICtrlCreateCheckbox("Restore", 144, 64, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStart01 = GUICtrlCreateCheckbox("Start", 16, 32, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateGroup("", -99, -99, 1, 1) $grpInst3 = GUICtrlCreateGroup(" 3 ", 8, 136, 233, 121) $btnPause03 = GUICtrlCreateCheckbox("Pause", 16, 192, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $tbnStop03 = GUICtrlCreateCheckbox("Stop", 16, 224, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnMin03 = GUICtrlCreateCheckbox("Minimize", 72, 192, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnWdh03 = GUICtrlCreateCheckbox("Restore", 144, 192, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStart03 = GUICtrlCreateCheckbox("Start", 16, 160, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateGroup("", -99, -99, 1, 1) $grpInst2 = GUICtrlCreateGroup(" 2 ", 248, 8, 233, 121) $btnPause02 = GUICtrlCreateCheckbox("Pause", 256, 64, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $tbnStop02 = GUICtrlCreateCheckbox("Stop", 256, 96, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnMin02 = GUICtrlCreateCheckbox("Minimize", 312, 64, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnWdh02 = GUICtrlCreateCheckbox("Restore", 384, 64, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStart02 = GUICtrlCreateCheckbox("Start", 256, 32, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateGroup("", -99, -99, 1, 1) $grpInst4 = GUICtrlCreateGroup(" 4 ", 248, 136, 233, 121) $btnPause04 = GUICtrlCreateCheckbox("Pause", 256, 192, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $tbnStop04 = GUICtrlCreateCheckbox("Stop", 256, 224, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnMin04 = GUICtrlCreateCheckbox("Minimize", 312, 192, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnWdh04 = GUICtrlCreateCheckbox("Restore", 384, 192, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStart04 = GUICtrlCreateCheckbox("Start", 256, 160, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUICtrlSetBkColor(-1, 0x00FF00) $Edit1 = GUICtrlCreateEdit("", 8, 720, 473, 497) $btnPauseAll = GUICtrlCreateCheckbox("Pause all", 8, 656, 474, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStopAll = GUICtrlCreateCheckbox("Stop all", 7, 688, 474, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 CheckGuiMsg() FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & "CheckGuiMsg" & @CRLF) CheckClientMessages() FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & "CheckClientMessages" & @CRLF) WEnd Func CheckGuiMsg() $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $btnStart01 AddTextToEdit("Starting Instance 1") $PID[0] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 1", @ScriptDir, Default, 3) Case $btnStart02 AddTextToEdit("Starting Instance 2") $PID[1] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 2", @ScriptDir, Default, 3) Case $btnStart03 AddTextToEdit("Starting Instance 3") $PID[2] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 3", @ScriptDir, Default, 3) Case $btnStart04 AddTextToEdit("Starting Instance 4") $PID[3] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 4", @ScriptDir, Default, 3) Case $btnPause01 AddTextToEdit("Send Pause to Instance 1") StdinWrite($PID[0], "Pause") Case $btnPause02 StdinWrite($PID[1], "Pause") Case $btnPause03 StdinWrite($PID[2], "Pause") Case $btnPause04 StdinWrite($PID[3], "Pause") Case $tbnStop01 StdinWrite($PID[0], "Stop") Case $tbnStop02 StdinWrite($PID[1], "Stop") Case $tbnStop03 StdinWrite($PID[2], "Stop") Case $tbnStop04 StdinWrite($PID[3], "Stop") Case $btnPauseAll AddTextToEdit(@CRLF & "************Pause All not yet implemented**************" & @CRLF) Case $btnStopAll AddTextToEdit(@CRLF & "************Stop All not yet implemented***************" & @CRLF) EndSwitch EndFunc ;==>CheckGuiMsg Func CheckClientMessages() For $i = 0 To 3 FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & $i & @CRLF) Local $a = TimerInit() $p = $PID[$i] $streamRead = StdoutRead($p) If $streamRead <> "" Then Switch $streamRead Case StringInStr($streamRead, "Focus Needed") > 0 If $FocusAvailable Then $FocusAvailable = False StdinWrite($p, "Focus Granted") Else EndIf Case StringInStr($streamRead, "Release Focus") > 0 StdinWrite($p, "Release Focus Received") $FocusAvailable = True Case Else EndSwitch EndIf FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & $i & " " & round(TimerDiff($a),2) & @CRLF) Next EndFunc ;==>CheckClientMessages Func AddTextToEdit($text) If $previousEditMsg <> $text Then $previousEditMsg = $text GUICtrlSetData($Edit1, GUICtrlRead($Edit1) & @YEAR & "." & @MON & "." & @MDAY & " - " & @HOUR & ":" & @MIN & ":" & @SEC & "> " & $text & @CRLF) _GUICtrlEdit_Scroll($Edit1, $SB_SCROLLCARET) EndIf EndFunc ;==>AddTextToEdit



      My issue now is that the mechanism with with StdoutRead and StdinWrite is not efficient at all. The more instances I start the slower it gets. This is not just a bit slower (like a fraction of a second), but to the degree that the front end is not responding at all any longer (with 3 instances handling).

      So my questions are:

      1.       Is there a flaw in my implementation with StdoutRead and StdinWrite? (note that all works fine with 1 and also (slower) with 2 instances running) but actually breaks down with 3 instances running.

      2.       Can I optimize the currently used implementation so that I can control 30+ instances?

      3.       What other implementation do you see suitable for this approach?

      a.       I have already tried it with communication through files but observed that this is not sufficiently reliable with multiple instances.

      b.       Is Named Pipes a more performant approach (I am a bit scared of the effort to learn and implement this)

      c.       Any other method?


       
      Many thanks in advance

      -dubi





×