Pipeline DLL - die einfachste Art der Prozess-Kommunikation

  • Hi!

    Ich habe mir (da ich oft mit Multi-Instanzen von AutoIt Programmen arbeite) eine kleine DLL geschrieben, welche die Kommunikation zwischen den Prozessen so einfach wie möglich macht. Die DLL nutzt die Windowseigene Mailslot-Pipeline und enthält sonst nichts, bis auf viele Error-Handlings.

    Das einzige was ihr zur Inbetriebnahme braucht ist die DLL, die ihr per "regsvr32" im System registrieren müsst. Ihr könnt sie jederzeit wieder entfernen (Parameter /u). Einige Virenscanner mögen vielleicht anschlagen, weil die DLL mit mpress komprimiert wurde.

    Die DLL wird objektorientiert angesprochen und bietet genau 4 Befehle, die alle in diesem Beispiel enthalten sind. In diesem Test-Skript kommuniziert der Prozess mit sich selbst. ^^ . Push und Pop mögen den Eindruck eines Stacks machen, sind aber willkürlich gewählte Namen. Die Daten können wie und wann man will gesendet werden.

    [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit][autoit][/autoit][autoit]

    $oShare = ObjCreate("Pipeline.Pipe")
    ConsoleWrite("!> " & @error & @LF)

    [/autoit][autoit][/autoit][autoit]

    $oShare.CreateSlot ; Erstellt einen Slot, der für die aktuelle PID alle Anfragen abhört

    [/autoit][autoit][/autoit][autoit]

    GUICreate("Test", 200, 55)
    GUISetOnEvent(-3, "quit")
    $hInput = GUICtrlCreateInput("Data to send...", 5, 5, 190, 21)
    $hSend = GUICtrlCreateButton("Send", 5, 31, 190, 20)
    GUICtrlSetOnEvent(-1, "_send")
    GUISetState()

    [/autoit][autoit][/autoit][autoit]

    While Sleep(10)
    $Data = $oShare.Pop ; Empfängt alle Daten, die an diesen Prozess übergeben werden
    If $Data <> "" Then ConsoleWrite("!> Data: " & $Data & @LF)
    WEnd

    [/autoit][autoit][/autoit][autoit]

    Func _send()
    $oShare.Push(GUICtrlRead($hInput), @AutoItPID) ; Sendet Daten. Hier an den selben Prozess zu Testzwecken.
    ; Für andere Prozesse einfach eine andere PID einsetzen.
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func quit()
    $oShare.DestroySlot ; Slot schließen
    Exit
    EndFunc

    [/autoit]
  • Zeigst du uns bitte auch noch den Source Code der DLL? :D

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • @m-obi Besser? Weiß ich nicht, ich denke einfacher.

    @YXO Für die Kommunikation zwischen zwei Prozessen. Du hast Beispielsweise 2 AutoIt Programme, die nebeneinander laufen. Dann kannst du zwei Aufgaben gleichzeitig ausführen und die Skripte trotzdem noch kommunizieren lassen, z.B. zum Austausch von Variablen-Werten ^^

    BugFix Einen gewissen Sinn hat es ja schon, denn die Daten ordnen sich hintereinander tortzdem in einer Art Stack-Form an, wenn mehrere Daten gleichzeitig gesendet werden.

    UEZ Klar, aber kompilieren denke ich kann das hier keiner (da fehlt der teure Compiler ^^ ). Aber ich schreibs heute Abend dazu - erwartet aber keine Wunder im Code :P

  • Welchen Fehler gibt regsvr? (Komprimierung ist beim Kompilieren Standard - ist wie mit UPX, ich kann aber eine umkomprimierte Version hinzufügen)

  • Der Vollständigkeit halber. So würde das aussehen mit der NamedPipes.au3.

    Spoiler anzeigen
    [autoit]

    #include <NamedPipes.au3>

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global $sPipeName = "\\.\pipe\virtual01"
    Global $BUFFER_SIZE = 4096
    Global $TIMEOUT = 1000
    Global $hPipe
    Global $OVERLAPPED_Struct = DllStructCreate($tagOVERLAPPED)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Create a named pipe
    $hPipe = _NamedPipes_CreateNamedPipe( _
    $sPipeName, _ ; Pipe name
    2, _ ; The pipe is bi-directional
    2, _ ; Overlapped mode is enabled
    0, _ ; No security ACL flags
    1, _ ; Data is written to the pipe as a stream of messages
    1, _ ; Data is read from the pipe as a stream of messages
    0, _ ; Blocking mode is enabled
    1, _ ; Maximum number of instances
    $BUFFER_SIZE, _ ; Output buffer size
    $BUFFER_SIZE, _ ; Input buffer size
    0, _ ; Client time out
    0) ; Default security attributes

    [/autoit] [autoit][/autoit] [autoit]

    GUICreate("Test", 200, 55)
    GUISetOnEvent(-3, "quit")
    $hInput = GUICtrlCreateInput("Data to send...", 5, 5, 190, 21)
    $hSend = GUICtrlCreateButton("Send", 5, 31, 190, 20)
    GUICtrlSetOnEvent(-1, "_send")
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While Sleep(10)
    $Data = _ReadMessage($hPipe) ; Empfängt alle Daten, die an diesen Prozess übergeben werden
    If $Data <> "" Then ConsoleWrite("!> Data: " & $Data & @LF)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _ReadMessage($hHandle)
    Local $sData = _MailSlotRead($hHandle, $BUFFER_SIZE, 1)
    If $sData Then
    _NamedPipes_DisconnectNamedPipe($hHandle)
    _NamedPipes_ConnectNamedPipe($hHandle, DllStructGetPtr($OVERLAPPED_Struct))
    Return $sData
    EndIf
    EndFunc ;==>_ReadMessage

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ;===============================================================================
    ;
    ; Name...........: _MailSlotRead
    ; Description ...: Reads messages from the specified mailslot.
    ; Syntax.........: _MailSlotRead ($hMailSlot , $iSize [, $iMode])
    ; Parameters ....: $hMailSlot - Mailslot handle
    ; $iSize - The number of bytes to read.
    ; $iMode - Reading mode.
    ; Can be: 0 - read binary
    ; 1 - read ANSI
    ; 2 - read UTF8
    ; Return values .: Success - Returns read data
    ; - Sets @extended to number of read bytes
    ; - Sets @error to 0
    ; Special: Sets @error to -1 if specified buffer to read to is too small.
    ; Failure - Returns empty string and sets @error:
    ; |1 - DllCall() to ReadFile failed.
    ; |2 - GetLastError function or call to it failed.
    ; |3 - ReadFile function failed. @extended will be set to the return value of the GetLastError function.
    ; Author ........: trancexx
    ; Modified.......:
    ; Link ..........; http://msdn.microsoft.com/en-us/library/aa365467(VS.85).aspx
    ; http://msdn.microsoft.com/en-us/library/ms679360(VS.85).aspx
    ;
    ;==========================================================================================
    Func _MailSlotRead($hMailSlot, $iSize, $iMode = 0)
    Local $tDataBuffer = DllStructCreate("byte[" & $iSize & "]")
    Local $aCall = DllCall("kernel32.dll", "int", "ReadFile", _
    "ptr", $hMailSlot, _
    "ptr", DllStructGetPtr($tDataBuffer), _
    "dword", $iSize, _
    "dword*", 0, _
    "ptr", 0)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Then Return SetError(1, 0, "")

    [/autoit] [autoit][/autoit] [autoit]

    If Not $aCall[0] Then
    Local $aLastErrorCall = DllCall("kernel32.dll", "int", "GetLastError")
    If @error Then Return SetError(2, 0, "")
    If $aLastErrorCall[0] = 122 Then ; ERROR_INSUFFICIENT_BUFFER
    Return SetError(-1, 0, "")
    Else
    Return SetError(3, $aLastErrorCall[0], "")
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $vOut

    [/autoit] [autoit][/autoit] [autoit]

    Switch $iMode
    Case 1
    $vOut = BinaryToString(DllStructGetData($tDataBuffer, 1))
    Case 2
    $vOut = BinaryToString(DllStructGetData($tDataBuffer, 1), 4)
    Case Else
    $vOut = DllStructGetData($tDataBuffer, 1)
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(0, $aCall[4], $vOut)
    EndFunc ;==>_MailSlotRead

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ;===============================================================================
    ;
    ; Name...........: _MailSlotWrite
    ; Description ...: Writes message to the specified mailslot.
    ; Syntax.........: _MailSlotWrite ($sMailSlotName , $vData [, $iMode])
    ; Parameters ....: $hMailSlot - Mailslot name
    ; $vData - Data to write.
    ; $iMode - Writing mode.
    ; Can be: 0 - write binary
    ; 1 - write ANSI
    ; 2 - write UTF8
    ; Return values .: Success - Returns the number of written bytes
    ; - Sets @error to 0
    ; Failure - Returns empty string and sets @error:
    ; |1 - CreateFileW function or call to it failed.
    ; |2 - WriteFile function or call to it failed.
    ; |3 - Opened mail slot handle could not be closed.
    ; |4 - WriteFile function or call to it failed and additionally opened mail slot handle could not be closed.
    ; Author ........: trancexx
    ; Modified.......:
    ; Link ..........; http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
    ; http://msdn.microsoft.com/en-us/library/aa365747(VS.85).aspx
    ; http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
    ;
    ;==========================================================================================
    Func _MailSlotWrite($sMailSlotName, $vData, $iMode = 0)
    Local $aCall = DllCall("kernel32.dll", "ptr", "CreateFileW", _
    "wstr", $sMailSlotName, _
    "dword", 0x40000000, _ ; GENERIC_WRITE
    "dword", 1, _ ; FILE_SHARE_READ
    "ptr", 0, _
    "dword", 3, _ ; OPEN_EXISTING
    "dword", 0, _ ; SECURITY_ANONYMOUS
    "ptr", 0)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or $aCall[0] = -1 Then Return SetError(1, 0, 0)

    [/autoit] [autoit][/autoit] [autoit]

    Local $hMailSlotHandle = $aCall[0]
    Local $bData

    [/autoit] [autoit][/autoit] [autoit]

    Switch $iMode
    Case 1
    $bData = StringToBinary($vData, 1)
    Case 2
    $bData = StringToBinary($vData, 4)
    Case Else
    $bData = $vData
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    Local $iBufferSize = BinaryLen($bData)

    [/autoit] [autoit][/autoit] [autoit]

    Local $tDataBuffer = DllStructCreate("byte[" & $iBufferSize & "]")
    DllStructSetData($tDataBuffer, 1, $bData)

    [/autoit] [autoit][/autoit] [autoit]

    $aCall = DllCall("kernel32.dll", "int", "WriteFile", _
    "ptr", $hMailSlotHandle, _
    "ptr", DllStructGetPtr($tDataBuffer), _
    "dword", $iBufferSize, _
    "dword*", 0, _
    "ptr", 0)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or Not $aCall[0] Then
    $aCall = DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hMailSlotHandle)
    If @error Or Not $aCall[0] Then Return SetError(4, 0, 0)
    Return SetError(2, 0, 0)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $iOut = $aCall[4]

    [/autoit] [autoit][/autoit] [autoit]

    $aCall = DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hMailSlotHandle)
    If @error Or Not $aCall[0] Then Return SetError(3, 0, $iOut)

    [/autoit] [autoit][/autoit] [autoit]

    Return $iOut
    EndFunc ;==>_MailSlotWrite

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _send()
    _MailSlotWrite($sPipeName, GUICtrlRead($hInput), 1)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func quit()
    _NamedPipes_DisconnectNamedPipe($hPipe)
    _NamedPipes_DisconnectNamedPipe($sPipeName)
    Exit
    EndFunc

    [/autoit]
  • Hey minx,

    gute DLL, einfache Handhabung und läuft gut. Aber ich habe nun Folgendes problem: Ich habe ein Skript das auf verschiedenen Computern laufen soll. Und dass deine DLL auf allen benötigt wird. Ich habe versucht es über einen Run versuch am Start des Skriptes versucht die DLL zu registrieren:

    [autoit]

    Run('regsvr32 /i X:xxx\Pipeline.dll')

    [/autoit]


    Das funktioniert aber nicht auf allen PC's bei meinem Laptop mit WIN 8 geht das aber bei WIN 7 gehts nicht also habe ich versucht eine universelle version zu suchen und will nun über DllOpen() die DLL öffnen und dann die Funktionen ausführen etc. dafür müsste ich aber wissen wie deine Funktionen aufgerufen werden bzw. wissen wie die DLL aussieht, das Funktioniert aber auch nicht :( Könntest du mir da vlt. helfen?

  • Nur zwecks der Vollständigkeit:
    Trancexx hat eine Mailslot UDF geschrieben, die ohne eigene DLL auskommt und direkt mit Windows arbeitet.

  • So wie ich das verstehe, nutzt die Pipeline UDF die "windowseigene Mailslot-Pipeline" (siehe Post 1). Das macht trancexx's UDF auch, aber ohne zusätzliche DLL.
    Das war's, was ich mitteilen wollte.