Hilfe bei named pipes oder andere Lösung?

  • Hallo Leute,
    als erstes mal eine Beschreibung meines Problems. Ich bin dabei, ein Backup Tool zu schreiben, was prinzipiell dazu in der Lage sein soll, Backups von FTP, SFTP und lokalen Dateien zu machen. Das ist ja alles kein Problem. Ich habe mir vorgenommen, dass ganze im schönen alten Konsolen-Stil zu machen. Da AutoIt da eher etwas beschränkt ist, habe ich also die console.au3 UDF aus dem englischen Forum verwendet. Das Problem an der UDF ist, dass die cin()-Funktion das Script solange pausiert, bis die Enter-Taste in der Konsole gedrückt wird. Das ist allerdings nicht in meinem Interesse, also musste ich eine Lösung finden. Über die coproc UDF, bis hin zu Thread-Funktion habe ich alles versucht durchzuexerzieren, bis ich endlich, in der guten alten Microsoft Hilfe auf Interprocess communication Möglichkeiten gestoßen bin. Ziemlich weit oben das "piping". Da viel mir ein, ah ja, da hat Autoit ja schon was... und nun sitze ich da und komme nicht weiter. Ich musste mein Script schon in einen Processor (das Main-Script, welches die ganzen Jobs verarbeiten soll) und die Konsole (das Programm, welches eigentlich nur die Eingaben des Users verarbeitet und gegebenenfalls an den Processor weiterleiten soll) geteilt, daher benötige ich auch einen effektiven Weg, die beiden Prozesse kommunizieren zu lassen. Envget/set Funktionen erzielen nicht den gewünschten Effekt, warum auch immer gibt es, wenn das eine Programm etwas in eine Variable setzt bei dem anderen keine Antwort, die Variable ist leer. Temporäre Dateien zu erstellen ist auch keine Option, bei großen Datenmengen dauert mir das Schreiben und lesen zu lange und vor allem ist der Datenverkehr abhörbar. Nicht das er das auf anderen Wegen nicht auch wäre, aber da jedenfalls deutlich einfacher. Nunja, lange Rede kurzer Sinn, ich hänge bei den Pipes fest. Hier also die beiden Teile, die ich bisher geschrieben habe (jeweils die Funktion pipe_initialize() vor dem Main-Script aufrufen).

    Processor:

    Spoiler anzeigen


    dim const $pbufsize =4096
    dim const $pipename = "\\.\\pipe\\mcbackup"
    dim const $ptimeout =5000
    dim const $error_io_pending =997
    dim const $error_pipe_connected =535
    dim $boverlap = dllstructcreate($tagoverlapped)
    dim $poverlap = dllstructgetptr($boverlap)
    dim $cstate, $pipe
    func pipe_initialize()
    global $pevent = _winapi_createevent()
    if $pevent =0 then
    msgbox(64, "MCBackup - Error", "Couldn't initialize event for interprocess communication. Please contact www.software@satoprogs.de with the following Error details:" & @crlf & @tab & "Errorcode: " & _winapi_getlasterror() & @crlf & @tab & "Error-Message: " & _winapi_getlasterrormessage())
    mcb_shutdown()
    endif
    dllstructsetdata($boverlap, "hEvent", $pevent)
    $pipe = _namedpipes_createnamedpipe($pipename, _
    2, _
    2, _
    0, _
    1, _
    1, _
    0, _
    1, _
    $pbufsize, _
    $pbufsize, _
    $ptimeout, _
    0)
    if $pipe =-1 then
    msgbox(64, "MCBackup - Error", "Initialization of Pipe for the interprocess communication failed. Please contact software@satoprogs.de with the following Error-Information. " & @crlf & @tab & "Error-Code: " & _winapi_getlasterror() & @crlf & @tab & "Error-Message: " & _winapi_getlasterrormessage())
    mcb_shutdown()
    else
    pipe_connect()
    endif
    endfunc
    func ReadMsg()
    local $pbuf, $tbuf, $iRead, $bSuccess
    $tbuf = dllstructcreate("char Text[" & $pbufsize & "]")
    $pbuf = dllstructgetptr($tbuf)
    $bSuccess = _winapi_ReadFile($pipe, $pbuf, $pbufsize, $iRead, $poverlap)
    if not $bSuccess and ($iRead <> 0) then
    if not _winapi_getoverlappedresult($pipe, $poverlap, $iRead, true) then
    pipe_reconnect()
    return
    else
    $bsuccess = _winapi_readfile($pipe, $pbuf, $pbufsize, $iRead, $poverlap)
    if not $bSuccess or ($iRead =0) then
    pipe_reconnect()
    return
    endif
    endif
    endif
    return dllstructgetdata($tbuf, "Text")
    endfunc
    func pipe_reconnect()
    if not _namedpipes_disconnectnamedpipe($pipe) then
    return
    endif
    pipe_connect()
    endfunc
    func pipe_connect()
    $cstate=0
    $pconnect = _namedpipes_connectnamedpipe($pipe, $poverlap)
    if $pconnect then
    msgbox(64, "MCBackup - Error", "Couldn't connect to Pipe. Please contact software@satoprogs.de and sent us the following Error-Information." & @crlf & @tab & "Error-Code: " & _winapi_getlasterror() & @crlf & @tab & "Error-Message: " & _winapi_getlasterrormessage())
    mcb_shutdown()
    else
    switch number(_winapi_getlasterror())
    case $error_pipe_connected
    $cstate =1
    if not _winapi_setevent(dllstructgetdata($boverlap, "hEvent")) then
    msgbox(64, "MCBackup - Error", "Failed to set the event for the pipe. Please contact software@satoprogs.de and sent us the following Error-Information." & @crlf & @tab & "Error-Code: " & _winapi_getlasterror() & @crlf & @tab & "Error-Message: " & _winapi_getlasterrormessage())
    mcb_shutdown()
    endif
    case else
    msgbox(64, "MCBackup - Error", "Failed to connect to the pipe a second time. Please contact software@satoprogs.de with the following Error-Information." & @crlf & @tab & "Error-Code: " & _winapi_getlasterror() & @crlf & @tab & "Error-Message: " & _winapi_getlasterrormessage())
    mcb_shutdown()
    endswitch
    endif
    endfunc
    func WriteMsg($msg)
    if not _namedpipes_setnamedpipehandlestate($pipe, 1, 0, 0, 0) then return false
    local $iWritten, $ibuf, $pbuf, $tbuf
    $ibuf = stringlen($msg) +1
    $tbuf = dllstructcreate("char Text[" & $ibuf & "]")
    $pbuf = dllstructgetptr($tbuf)
    dllstructsetdata($tbuf, "Text", $msg)
    if not _winapi_writefile($pipe, $pbuf, $ibuf, $iwritten, 0) then return false
    return true
    endfunc

    Console:

    Spoiler anzeigen


    dim const $pbufsize =4096
    dim const $pipename = "\\.\\pipe\\MCBackup"
    dim const $error_more_data =234
    dim $boverlap = dllstructcreate($tagoverlapped)
    dim $poverlap = dllstructgetptr($boverlap)
    dim $pipe
    func pipe_initialize()
    global $pevent = _winapi_createevent()
    if $pevent =0 then
    msgbox(64, "MCBackup - Error", "Couldn't initialize event for interprocess communication in console. Please contact www.software@satoprogs.de with the following Error details:" & @crlf & @tab & "Errorcode: " & _winapi_getlasterror() & @crlf & @tab & "Error-Message: " & _winapi_getlasterrormessage())
    mcb_shutdown()
    endif
    dllstructsetdata($boverlap, "hEvent", $pevent)
    $pipe = _winapi_createfile($pipe, 2, 6)
    if $pipe <> -1 then return true
    msgbox(64, "MCBackup - Error", "Error connecting the console to the pipe. Please contact software@satoprogs.de with the following Error-Information. " & @crlf & @tab & "Error-Code: " & _winapi_getlasterror() & @crlf & @tab & "Error-Message: " & _winapi_getlasterrormessage())
    mcb_shutdown()
    return false
    endfunc
    func WriteMsg($msg)
    if not _namedpipes_setnamedpipehandlestate($pipe, 1, 0, 0, 0) then return false
    local $iWritten, $ibuf, $pbuf, $tbuf
    $ibuf = stringlen($msg) +1
    $tbuf = dllstructcreate("char Text[" & $ibuf & "]")
    $pbuf = dllstructgetptr($tbuf)
    dllstructsetdata($tbuf, "Text", $msg)
    if not _winapi_writefile($pipe, $pbuf, $ibuf, $iwritten, 0) then return false
    return true
    endfunc
    func ReadMsg()
    local $pbuf, $tbuf, $iRead, $bSuccess
    $tbuf = dllstructcreate("char Text[" & $pbufsize & "]")
    $pbuf = dllstructgetptr($tbuf)
    $bSuccess = _winapi_ReadFile($pipe, $pbuf, $pbufsize, $iRead, $poverlap)
    if not $bSuccess and ($iRead <> 0) then
    if not _winapi_getoverlappedresult($pipe, $poverlap, $iRead, true) then
    pipe_initialize()
    return
    else
    $bsuccess = _winapi_readfile($pipe, $pbuf, $pbufsize, $iRead, $poverlap)
    if not $bSuccess or ($iRead =0) then
    pipe_initialize()
    return
    endif
    endif
    endif
    return dllstructgetdata($tbuf, "Text")
    endfunc

    Momentan ist das Problem, dass ich nicht weiß, wie ich überprüfen soll, wann er endlich die Verbindung in pipe_connect() (Processor) hergestellt hat, es wird immer noch gemeldet, dass er noch am arbeiten ist (Error-Code 997). Vielleicht gibt es ja auch eine viel rentablere Lösung, vielleicht sogar eine Möglichkeit, die Console nicht ständig das Hauptskript pausieren zu lassen, dann könnte ich mir diese Funktionen natürlich auch in die Haare schmieren.
    Hinweis: Ich habe fast keinen Plan, was ich da überhaupt mache, dafür habe ich nicht wirklich den Einblick in die Winapi, ich habe diese Funktionen fast vollständig aus den Beispielen, die in AutoIt mitgeliefert werden übernommen.

    Kann mir einer irgendwie Denkanstöße geben?
    Vielen Dank im Voraus.
    mfg.
    Timtam
    PS: Ob die Lesen /Schreiben (ReadMsg und WriteMsg) so überhaupt funktionieren weiß ich auch nicht, komme ja nicht mal dazu das zu testen...

  • Hallo,
    danke erstmal für deine Antwort.
    Hmm, naja so wirklich hilft mir das nicht weiter. Aber das hat natürlich auch einen Grund. Der Grund ist einfach, dass es in dem in AutoIt mitgelieferten Beispiel anscheinend extrem umständlich gemacht wird. Wozu brauche ich zum Beispiel den ganzen Kram mit dem $tagOVERLAP struct? Um eine overlapped Pipe zu erzeugen. Aber wozu muss diese Pipe overlapped sein? Denn genau das scheint ja die Erstellung der Pipe so zu verzögern, denn durch _winapi_getlasterrormessage() kommt in etwa: Erstellung der überlappenden Pipe ist in Arbeit oder so... vielleicht steht die Pipe direkt zur Verfügung wenn ich die Überlappung weglasse? Aber wozu ist die Überlappung denn überhaupt da?