It is currently Sat Feb 29, 2020 2:33 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Handle an external program via stdin/out/error
PostPosted: Sat Feb 13, 2016 10:19 pm 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4523
Location: Germany
Hi,

since KCC had some problems and he want to use the solution as a 'standard',
I rewrote it a bit.

Save it as ExternalProgram.pbi

Code:
;
; ExternalProgram.pbi
;
; V 1.00
;
; by infratec
;

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

CompilerIf Not #PB_Compiler_Thread
  MessageRequester("Info", "Enable Thread-Safe in compiler options!")
  End
CompilerEndIf

CompilerIf Not Defined(Event_CustomValue, #PB_Enumeration)
 
  Enumeration Event_CustomValue #PB_Event_FirstCustomValue
    #ExternalProgram_Event_StdOut
    #ExternalProgram_Event_Error
    #ExternalProgram_Event_Exit
  EndEnumeration
 
CompilerElse
 
  Enumeration Event_CustomValue
    #ExternalProgram_Event_StdOut
    #ExternalProgram_Event_Error
    #ExternalProgram_Event_Exit
  EndEnumeration
 
CompilerEndIf

Prototype.s ExternalProgram_CPxxxToUnicode(*Buffer, Length.i)

Structure ExternalProgram_ParameterStructure
  Program$
  ProgramParameter$
  ProgramWorkingDirectory$
  ProgramReadWriteMode.i
  ProgramExit$
  Semaphore.i
  Mutex.i
  Thread.i
  ProgramID.i
  StdOut$
  StdIn$
  StdErr$
  CodePageConverter.ExternalProgram_CPxxxToUnicode
  Exit.i
EndStructure




Procedure.s ExternalProgram_CP437ToUnicode(*Buffer, Length.i)
 
  DataSection
    ExternalProgram_CP437Data:
    Data.u $00C7, $00FC, $00E9, $00E2, $00E4, $00E0, $00E5, $00E7
    Data.u $00EA, $00EB, $00E8, $00EF, $00EE, $00EC, $00C4, $00C5
    Data.u $00C9, $00E6, $00C6, $00F4, $00F6, $00F2, $00FB, $00F9
    Data.u $00FF, $00D6, $00DC, $00A2, $00A3, $00A5, $20A7, $0192
    Data.u $00E1, $00ED, $00F3, $00FA, $00F1, $00D1, $00AA, $00BA
    Data.u $00BF, $2310, $00AC, $00BD, $00BC, $00A1, $00AB, $00BB
    Data.u $2591, $2592, $2593, $2502, $2524, $2561, $2562, $2556
    Data.u $2555, $2563, $2551, $2557, $255D, $255C, $255B, $2510
    Data.u $2514, $2534, $252C, $251C, $2500, $253C, $255E, $255F
    Data.u $255A, $2554, $2569, $2566, $2560, $2550, $256C, $2567
    Data.u $2568, $2564, $2565, $2559, $2558, $2552, $2553, $256B
    Data.u $256A, $2518, $250C, $2588, $2584, $258C, $2590, $2580
    Data.u $03B1, $00DF, $0393, $03C0, $03A3, $03C3, $00B5, $03C4
    Data.u $03A6, $0398, $03A9, $03B4, $221E, $03C6, $03B5, $2229
    Data.u $2261, $00B1, $2265, $2264, $2320, $2321, $00F7, $2248
    Data.u $00B0, $2219, $00B7, $221A, $207F, $00B2, $25A0, $00A0
  EndDataSection
 
  Protected Result$, i.i, Byte.a
 
 
  Length - 1
 
  For i = 0 To Length
    Byte = PeekA(*Buffer + i)
    If Byte < $80
      Result$ + Chr(Byte)
    Else
      Result$ + Chr(PeekU(?ExternalProgram_CP437Data + (Byte & $7F) << 1))
    EndIf
  Next i
 
  ProcedureReturn Result$
 
EndProcedure




Procedure.s ExternalProgram_CP850ToUnicode(*Buffer, Length.i)
 
  DataSection
    ExternalProgram_CP850Data:
    Data.u $00c7, $00fc, $00e9, $00e2, $00e4, $00e0, $00e5, $00e7
    Data.u $00ea, $00eb, $00e8, $00ef, $00ee, $00ec, $00c4, $00c5
    Data.u $00c9, $00e6, $00c6, $00f4, $00f6, $00f2, $00fb, $00f9
    Data.u $00ff, $00d6, $00dc, $00f8, $00a3, $00d8, $00d7, $0192
    Data.u $00e1, $00ed, $00f3, $00fa, $00f1, $00d1, $00aa, $00ba
    Data.u $00bf, $00ae, $00ac, $00bd, $00bc, $00a1, $00ab, $00bb
    Data.u $2591, $2592, $2593, $2502, $2524, $00c1, $00c2, $00c0
    Data.u $00a9, $2563, $2551, $2557, $255d, $00a2, $00a5, $2510
    Data.u $2514, $2534, $252c, $251c, $2500, $253c, $00e3, $00c3
    Data.u $255a, $2554, $2569, $2566, $2560, $2550, $256c, $00a4
    Data.u $00f0, $00d0, $00ca, $00cb, $00c8, $0131, $00cd, $00ce
    Data.u $00cf, $2518, $250c, $2588, $2584, $00a6, $00cc, $2580
    Data.u $00d3, $00df, $00d4, $00d2, $00f5, $00d5, $00b5, $00fe
    Data.u $00de, $00da, $00db, $00d9, $00fd, $00dd, $00af, $00b4
    Data.u $00ad, $00b1, $2017, $00be, $00b6, $00a7, $00f7, $00b8
    Data.u $00b0, $00a8, $00b7, $00b9, $00b3, $00b2, $25a0, $00a0
  EndDataSection
 
  Protected Result$, i.i, Byte.a
 
 
  Length - 1
 
  For i = 0 To Length
    Byte = PeekA(*Buffer + i)
    If Byte < $80
      Result$ + Chr(Byte)
    Else
      Result$ + Chr(PeekU(?ExternalProgram_CP850Data + (Byte & $7F) << 1))
    EndIf
  Next i
 
  ProcedureReturn Result$
 
EndProcedure



Procedure.s ExternalProgram_CP852ToUnicode(*Buffer, Length.i)
 
  DataSection
    ExternalProgram_CP852Data:
    Data.u $00C7, $00FC, $00E9, $00E2, $00E4, $016F, $0107, $00E7
    Data.u $0142, $00EB, $0150, $0151, $00EE, $0179, $00C4, $0106
    Data.u $00C9, $0139, $013A, $00F4, $00F6, $013D, $013E, $015A
    Data.u $015B, $00D6, $00DC, $0164, $0165, $0141, $00D7, $010D
    Data.u $00E1, $00ED, $00F3, $00FA, $0104, $0105, $017D, $017E
    Data.u $0118, $0119, $00AC, $017A, $010C, $015F, $00AB, $00BB
    Data.u $2591, $2592, $2593, $2502, $2524, $00C1, $00C2, $011A
    Data.u $015E, $2563, $2551, $2557, $255D, $017B, $017C, $2510
    Data.u $2514, $2534, $252C, $251C, $2500, $253C, $0102, $0103
    Data.u $255A, $2554, $2569, $2566, $2560, $2550, $256C, $00A4
    Data.u $0111, $0110, $010E, $00CB, $010F, $0147, $00CD, $00CE
    Data.u $011B, $2518, $250C, $2588, $2584, $0162, $016E, $2580
    Data.u $00D3, $00DF, $00D4, $0143, $0144, $0148, $0160, $0161
    Data.u $0154, $00DA, $0155, $0170, $00FD, $00DD, $0163, $00B4
    Data.u $00AD, $02DD, $02DB, $02C7, $02D8, $00A7, $00F7, $00B8
    Data.u $00B0, $00A8, $02D9, $0171, $0158, $0159, $25A0, $00A0
  EndDataSection
 
  Protected Result$, i.i, Byte.a
 
 
  Length - 1
 
  For i = 0 To Length
    Byte = PeekA(*Buffer + i)
    If Byte < $80
      Result$ + Chr(Byte)
    Else
      Result$ + Chr(PeekU(?ExternalProgram_CP852Data + (Byte & $7F) << 1))
    EndIf
  Next i
 
  ProcedureReturn Result$
 
EndProcedure




Procedure.s ExternalProgram_CP863ToUnicode(*Buffer, Length.i)
 
  DataSection
    ExternalProgram_CP863Data:
    Data.u $00c7, $00fc, $00e9, $00e2, $00c2, $00e0, $00b6, $00e7
    Data.u $00ea, $00eb, $00e8, $00ef, $00ee, $2017, $00c0, $00a7
    Data.u $00c9, $00c8, $00ca, $00f4, $00cb, $00cf, $00fb, $00f9
    Data.u $00a4, $00d4, $00dc, $00a2, $00a3, $00d9, $00db, $0192
    Data.u $00a6, $00b4, $00f3, $00fa, $00a8, $00b8, $00b3, $00af
    Data.u $00ce, $2310, $00ac, $00bd, $00bc, $00be, $00ab, $00bb
    Data.u $2591, $2592, $2593, $2502, $2524, $2561, $2562, $2556
    Data.u $2555, $2563, $2551, $2557, $255d, $255c, $255b, $2510
    Data.u $2514, $2534, $252c, $251c, $2500, $253c, $255e, $255f
    Data.u $255a, $2554, $2569, $2566, $2560, $2550, $256c, $2567
    Data.u $2568, $2564, $2565, $2559, $2558, $2552, $2553, $256b
    Data.u $256a, $2518, $250c, $2588, $2584, $258c, $2590, $2580
    Data.u $03b1, $00df, $0393, $03c0, $03a3, $03c3, $00b5, $03c4
    Data.u $03a6, $0398, $03a9, $03b4, $221e, $03c6, $03b5, $2229
    Data.u $2261, $00b1, $2265, $2264, $2320, $2321, $00f7, $2248
    Data.u $00b0, $2219, $00b7, $221a, $207f, $00b2, $25a0, $00a0
  EndDataSection
 
  Protected Result$, i.i, Byte.a
 
 
  Length - 1
 
  For i = 0 To Length
    Byte = PeekA(*Buffer + i)
    If Byte < $80
      Result$ + Chr(Byte)
    Else
      Result$ + Chr(PeekU(?ExternalProgram_CP863Data + (Byte & $7F) << 1))
    EndIf
  Next i
 
  ProcedureReturn Result$
 
EndProcedure




Procedure.s ExternalProgram_CP1252ToUnicode(*Buffer, Length.i)
 
  DataSection
    ExternalProgram_CP1252Data:
    Data.u $20AC, $0000, $201A, $0192, $201E, $2026, $2020, $2021
    Data.u $02C6, $2030, $0160, $2039, $0152, $0000, $017D, $0000
    Data.u $0000, $2018, $2019, $201C, $201D, $2022, $2013, $2014
    Data.u $02DC, $2122, $0161, $203A, $0153, $0000, $017E, $0178
  EndDataSection
 
  Protected Result$, i.i, Byte.a
 
 
  Length - 1
 
  For i = 0 To Length
    Byte = PeekA(*Buffer + i)
    If Byte < $80 Or Byte > $9F
      Result$ + Chr(Byte)
    Else
      Result$ + Chr(PeekU(?ExternalProgram_CP1252Data + (Byte & $7F) << 1))
    EndIf
  Next i
 
  ProcedureReturn Result$
 
EndProcedure




Procedure ExternalProgram_Thread(*Parameter.ExternalProgram_ParameterStructure)
 
  Protected *Buffer, ReadLen.i, WriteLen.i, Error$, Timeout.i, StringMode.i, PeekStringMode.i
 
  *Buffer = AllocateMemory(1024, #PB_Memory_NoClear)
 
  If *Buffer
   
    Select *Parameter\ProgramReadWriteMode
      Case #PB_Program_Ascii
        StringMode = #PB_Ascii
        PeekStringMode = #PB_Ascii
      Case #PB_Program_Unicode
        StringMode = #PB_Unicode
        PeekStringMode = #PB_Unicode
      Case #PB_Program_UTF8
        StringMode = #PB_UTF8
        PeekStringMode = #PB_UTF8|#PB_ByteLength
    EndSelect
   
    *Parameter\ProgramID = RunProgram(*Parameter\Program$, *Parameter\ProgramParameter$, *Parameter\ProgramWorkingDirectory$, #PB_Program_Open|#PB_Program_Read|#PB_Program_Write|#PB_Program_Error|#PB_Program_Hide|*Parameter\ProgramReadWriteMode)
   
    If *Parameter\ProgramID
     
      Repeat
       
        While AvailableProgramOutput(*Parameter\ProgramID)
          ReadLen = AvailableProgramOutput(*Parameter\ProgramID)
         
          If ReadLen > MemorySize(*Buffer)
            *Buffer = ReAllocateMemory(*Buffer, ReadLen, #PB_Memory_NoClear)
          EndIf
         
          ReadLen = ReadProgramData(*Parameter\ProgramID, *Buffer, ReadLen)
          If ReadLen
            If *Parameter\CodePageConverter
              *Parameter\StdOut$ = *Parameter\CodePageConverter(*Buffer, ReadLen)
            Else
              *Parameter\StdOut$ = PeekS(*Buffer, ReadLen, PeekStringMode)
            EndIf
            PostEvent(#ExternalProgram_Event_StdOut)
            WaitSemaphore(*Parameter\Semaphore)
          EndIf
        Wend
       
        Error$ = ReadProgramError(*Parameter\ProgramID, StringMode)
        If Len(Error$)
          *Parameter\StdErr$ = Error$
          PostEvent(#ExternalProgram_Event_Error)
          WaitSemaphore(*Parameter\Semaphore)
        EndIf
       
        If TryLockMutex(*Parameter\Mutex)
          If Len(*Parameter\StdIn$)
            *Parameter\StdIn$ + #CRLF$
            WriteLen = PokeS(*Buffer, *Parameter\StdIn$, -1, StringMode|#PB_String_NoZero)
            *Parameter\StdIn$ = ""
            WriteLen = WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
            SignalSemaphore(*Parameter\Semaphore)
          EndIf
          UnlockMutex(*Parameter\Mutex)
        EndIf
       
        Delay(10)
       
      Until *Parameter\Exit Or Not ProgramRunning(*Parameter\ProgramID)
     
      If *Parameter\Exit
        If ProgramRunning(*Parameter\ProgramID)
          If Len(*Parameter\ProgramExit$)
            *Parameter\ProgramExit$ + #CRLF$
            WriteLen = PokeS(*Buffer, *Parameter\ProgramExit$, -1, StringMode|#PB_String_NoZero)
            WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
          Else
            WriteProgramData(*Parameter\ProgramID, #PB_Program_Eof, 0)
          EndIf
          Timeout = 300
          Repeat
            Delay(10)
            Timeout - 1
            While AvailableProgramOutput(*Parameter\ProgramID)
              ReadProgramData(*Parameter\ProgramID, *Buffer, 1)
            Wend
          Until Timeout = 0 Or Not ProgramRunning(*Parameter\ProgramID)
          If Timeout = 0
            Debug "Kill"
            KillProgram(*Parameter\ProgramID)
          EndIf
        EndIf
      EndIf
     
      CloseProgram(*Parameter\ProgramID)
     
    EndIf
   
    FreeMemory(*Buffer)
  EndIf
 
  PostEvent(#ExternalProgram_Event_Exit)
 
EndProcedure




;- Example
CompilerIf #PB_Compiler_IsMainFile
 
  Enumeration
    #MainWindow
    #EditorGadget
    #StringGadget
    #ButtonGadget
  EndEnumeration
 
  Define Event.i, Exit.i, i.i, j.i
  Define ThreadParameter.ExternalProgram_ParameterStructure
 
  LoadFont(0, "Consolas", 10)
 
  OpenWindow(#MainWindow, 0, 0, 600, 500, "Remote console", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_ScreenCentered)
  WindowBounds(#MainWindow, 600, 500, #PB_Ignore, #PB_Ignore)
  EditorGadget(#EditorGadget, 10, 10, 580, 410)
  SetGadgetFont(#EditorGadget, FontID(0))
  StringGadget(#StringGadget, 10, 430, 580, 20, "help")
  ButtonGadget(#ButtonGadget, 200, 460, 200, 30, "Send to console")
 
  ThreadParameter\Program$ = "cmd.exe"
  ThreadParameter\ProgramReadWriteMode = #PB_Program_Ascii
  ThreadParameter\ProgramExit$ = "exit"
  ThreadParameter\CodePageConverter = @ExternalProgram_CP850ToUnicode()
  ThreadParameter\Semaphore = CreateSemaphore()
  ThreadParameter\Mutex = CreateMutex()
  ThreadParameter\Thread = CreateThread(@ExternalProgram_Thread(), @ThreadParameter)
 
  Repeat
   
    Event = WaitWindowEvent()
   
    Select Event
      Case #ExternalProgram_Event_StdOut
        ThreadParameter\StdOut$ = RemoveString(ThreadParameter\StdOut$, #CR$)
        ThreadParameter\StdOut$ = RTrim(ThreadParameter\StdOut$, #LF$)
        i = CountString(ThreadParameter\StdOut$, #LF$)
        For j = 0 To i
          AddGadgetItem(#EditorGadget, -1, StringField(ThreadParameter\StdOut$, j + 1, #LF$))
        Next j
        SignalSemaphore(ThreadParameter\Semaphore)
       
      Case #ExternalProgram_Event_Error
        Debug ThreadParameter\StdErr$
        SignalSemaphore(ThreadParameter\Semaphore)
       
      Case #ExternalProgram_Event_Exit
        Exit = #True
       
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #ButtonGadget
            LockMutex(ThreadParameter\Mutex)
            ThreadParameter\StdIn$ = GetGadgetText(#StringGadget)
            UnlockMutex(ThreadParameter\Mutex)
            WaitSemaphore(ThreadParameter\Semaphore)
        EndSelect
       
      Case #PB_Event_SizeWindow
        ResizeGadget(#ButtonGadget, WindowWidth(#MainWindow) / 2 - 100, WindowHeight(#MainWindow) - 40, #PB_Ignore, #PB_Ignore)
        ResizeGadget(#StringGadget, #PB_Ignore, WindowHeight(#MainWindow) - 70, WindowWidth(#MainWindow) - 20, #PB_Ignore)
        ResizeGadget(#EditorGadget, #PB_Ignore, #PB_Ignore, WindowWidth(#MainWindow) - 20, WindowHeight(#MainWindow) - 90)
       
      Case #PB_Event_CloseWindow
        If IsThread(ThreadParameter\Thread)
          ThreadParameter\Exit = #True
          WaitThread(ThreadParameter\Thread)
        EndIf
        FreeMutex(ThreadParameter\Mutex)
        FreeSemaphore(ThreadParameter\Semaphore)
        Exit = #True
    EndSelect
   
  Until Exit
 
CompilerEndIf


I hope it is 'universal' enough to handle all possibilities.
Maybe it is useful for others too.

Bernd


Last edited by infratec on Tue Nov 26, 2019 10:01 am, edited 12 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Sun Feb 14, 2016 8:13 pm 
Offline
Addict
Addict
User avatar

Joined: Sun Nov 05, 2006 11:42 pm
Posts: 4632
Location: Lyon - France
Hello INFRATEC :D

I have tried your splendid code, and it works very well, for Phantom, but also with CMD.

Your code is very usefull, for remote apparently all console applications by PB
I have searched the same in all the forum and not found a full remote console (read/write) for all exe, just remote of CMD

Again thanks 8)

_________________
ImageThe happiness is a road...
Not a destination


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Tue Jun 13, 2017 4:57 pm 
Offline
Addict
Addict
User avatar

Joined: Sun Nov 05, 2006 11:42 pm
Posts: 4632
Location: Lyon - France
Hello INFRATEC

I need another time your code, and i see now, it works only if the lengh of the return of console is not too long :|

Then, this time, i have another time try with console, but also with ADB of androidSdk and i have just a part of return
I have also try to modify the two delay(), that change a little the lengh of return, but it's nor perfect :(

Have you an idea for fix that ?

Code:
CompilerIf Not #PB_Compiler_Thread
  MessageRequester("Info", "Enable Thread-Safe in compiler options!")
  End
CompilerEndIf

Enumeration #PB_Event_FirstCustomValue
  #ExternalProgram_Event_StdOut
  #ExternalProgram_Event_Error
  #ExternalProgram_Event_Exit
EndEnumeration

Structure ExternalProgramParameterStructure
  Program$
  ProgramParameter$
  ProgramWorkingDirectory$
  ProgramReadWriteMode.i
  ProgramExit$
  Semaphore.i
  Mutex.i
  Thread.i
  ProgramID.i
  StdOut$
  StdIn$
  StdErr$
  Exit.i
EndStructure

Procedure ExternalProgramThread(*Parameter.ExternalProgramParameterStructure)
 
  Protected *Buffer, ReadLen.i, WriteLen.i, Error$, Timeout.i
 
  *Buffer = AllocateMemory(1024)
 
  If *Buffer
   
    *Parameter\ProgramID = RunProgram(*Parameter\Program$, *Parameter\ProgramParameter$, GetPathPart(*Parameter\Program$), #PB_Program_Open|#PB_Program_Read|#PB_Program_Write|#PB_Program_Error|#PB_Program_Hide|*Parameter\ProgramReadWriteMode)
   
    If *Parameter\ProgramID
     
      Repeat
       
        ReadLen = AvailableProgramOutput(*Parameter\ProgramID)
        If ReadLen
          ReadLen = ReadProgramData(*Parameter\ProgramID, *Buffer, ReadLen)
          If ReadLen
            *Parameter\StdOut$ = PeekS(*Buffer, ReadLen, *Parameter\ProgramReadWriteMode|#PB_ByteLength)
            PostEvent(#ExternalProgram_Event_StdOut)
            WaitSemaphore(*Parameter\Semaphore)
          EndIf
        EndIf
       
        Error$ = ReadProgramError(*Parameter\ProgramID, *Parameter\ProgramReadWriteMode)
        If Len(Error$)
          *Parameter\StdErr$ = Error$
          PostEvent(#ExternalProgram_Event_Error)
          WaitSemaphore(*Parameter\Semaphore)
        EndIf
       
        If TryLockMutex(*Parameter\Mutex)
          If Len(*Parameter\StdIn$)
            *Parameter\StdIn$ + #CRLF$
            WriteLen = PokeS(*Buffer, *Parameter\StdIn$, -1, *Parameter\ProgramReadWriteMode)
            *Parameter\StdIn$ = ""
            WriteLen = WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
            SignalSemaphore(*Parameter\Semaphore)
          EndIf
          UnlockMutex(*Parameter\Mutex)
        EndIf
       
        Delay(10)
       
      Until *Parameter\Exit Or Not ProgramRunning(*Parameter\ProgramID)
     
      If *Parameter\Exit
        If ProgramRunning(*Parameter\ProgramID)
          If Len(*Parameter\ProgramExit$)
            *Parameter\ProgramExit$ + #CRLF$
            WriteLen = PokeS(*Buffer, *Parameter\ProgramExit$, -1, *Parameter\ProgramReadWriteMode)
            WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
          Else
            WriteProgramData(*Parameter\ProgramID, #PB_Program_Eof, 0)
          EndIf
          Timeout = 300
          Repeat
            Delay(10)
            Timeout - 1
          Until Timeout = 0 Or Not ProgramRunning(*Parameter\ProgramID)
          If Timeout = 0
            Debug "Kill"
            KillProgram(*Parameter\ProgramID)
          EndIf
        EndIf
      EndIf
     
      CloseProgram(*Parameter\ProgramID)
     
    EndIf
   
    FreeMemory(*Buffer)
  EndIf
 
  PostEvent(#ExternalProgram_Event_Exit)
 
EndProcedure
 
Enumeration
 #Form0
 #EditorCommande
 #StringCommande
 #Bouton
EndEnumeration

Define Event.i, Exit.i, i.i, j.i
Define ThreadParameter.ExternalProgramParameterStructure

OpenWindow(#Form0, 379, 176, 608, 542, "Remote Console windows", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_TitleBar)
EditorGadget(#EditorCommande, 5, 15, 593, 447)
StringGadget(#StringCommande, 6, 469, 594, 23, "help")
ButtonGadget(#Bouton, 211, 503, 201, 33, "Send to console")

ThreadParameter\Program$ = "C:\Windows\System32\cmd.exe"
ThreadParameter\ProgramReadWriteMode = #PB_UTF8
ThreadParameter\ProgramExit$ = ""
ThreadParameter\Semaphore = CreateSemaphore()
ThreadParameter\Mutex = CreateMutex()
ThreadParameter\Thread = CreateThread(@ExternalProgramThread(), @ThreadParameter)

Repeat

 Event = WaitWindowEvent()

 Select Event
   Case #ExternalProgram_Event_StdOut
     ThreadParameter\StdOut$ = RemoveString(ThreadParameter\StdOut$, #CR$)
     ThreadParameter\StdOut$ = RTrim(ThreadParameter\StdOut$, #LF$)
     i = CountString(ThreadParameter\StdOut$, #LF$)
     For j = 0 To i
       AddGadgetItem(#EditorCommande, -1, StringField(ThreadParameter\StdOut$, j + 1, #LF$))
     Next j
     SignalSemaphore(ThreadParameter\Semaphore)
   
   Case #ExternalProgram_Event_Error
     Debug ThreadParameter\StdErr$
     SignalSemaphore(ThreadParameter\Semaphore)
   
   Case #ExternalProgram_Event_Exit
     Exit = #True
   
   Case #PB_Event_Gadget
     Select EventGadget()
       Case #Bouton
         LockMutex(ThreadParameter\Mutex)
         ThreadParameter\StdIn$ = GetGadgetText(#StringCommande) + #CRLF$
         UnlockMutex(ThreadParameter\Mutex)
         WaitSemaphore(ThreadParameter\Semaphore)
     EndSelect
   
   Case #PB_Event_CloseWindow
     If IsThread(ThreadParameter\Thread)
       ThreadParameter\Exit = #True
       WaitThread(ThreadParameter\Thread)
     EndIf
     FreeMutex(ThreadParameter\Mutex)
     FreeSemaphore(ThreadParameter\Semaphore)
     Exit = #True
 EndSelect

Until Exit
   


Have a good day

_________________
ImageThe happiness is a road...
Not a destination


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Thu Nov 21, 2019 8:51 am 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4523
Location: Germany
I updated the code above.
The character mode was not correct handled.
#PB_Program_UTF8 is not #PB_UTF8 ...


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Sat Nov 23, 2019 7:18 pm 
Offline
Addict
Addict
User avatar

Joined: Sun Nov 05, 2006 11:42 pm
Posts: 4632
Location: Lyon - France
Hello INFRATEC :D

Thanks to your fix 8)
But that not works here with W10 X64 / v5.70 X86 :|

The full result of "HELP" is always not returned
And the french characters is not good returned

Perhaps your splendid code for "Phantom.exe" not works with the windows console ?

Code:
CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

CompilerIf Not #PB_Compiler_Thread
  MessageRequester("Info", "Enable Thread-Safe in compiler options!")
  End
CompilerEndIf


CompilerIf Not Defined(FirstCustomValue, #PB_Enumeration)
 
  Enumeration FirstCustomValue #PB_Event_FirstCustomValue
    #ExternalProgram_Event_StdOut
    #ExternalProgram_Event_Error
    #ExternalProgram_Event_Exit
  EndEnumeration
 
CompilerElse
 
  Enumeration FirstCustomValue
    #ExternalProgram_Event_StdOut
    #ExternalProgram_Event_Error
    #ExternalProgram_Event_Exit
  EndEnumeration
 
CompilerEndIf

Structure ExternalProgramParameterStructure
  Program$
  ProgramParameter$
  ProgramWorkingDirectory$
  ProgramReadWriteMode.i
  ProgramExit$
  Semaphore.i
  Mutex.i
  Thread.i
  ProgramID.i
  StdOut$
  StdIn$
  StdErr$
  Exit.i
EndStructure

Procedure ExternalProgramThread(*Parameter.ExternalProgramParameterStructure)
 
  Protected *Buffer, ReadLen.i, WriteLen.i, Error$, Timeout.i, StringMode.i, PeekStringMode.i
 
  *Buffer = AllocateMemory(1024)
 
  If *Buffer
   
    Select *Parameter\ProgramReadWriteMode
      Case #PB_Program_Ascii
        StringMode = #PB_Ascii
        PeekStringMode = #PB_Ascii
      Case #PB_Program_Unicode
        StringMode = #PB_Unicode
        PeekStringMode = #PB_Unicode
      Case #PB_Program_UTF8
        StringMode = #PB_UTF8
        PeekStringMode = #PB_UTF8|#PB_ByteLength
    EndSelect
   
    *Parameter\ProgramID = RunProgram(*Parameter\Program$, *Parameter\ProgramParameter$, *Parameter\ProgramWorkingDirectory$, #PB_Program_Open|#PB_Program_Read|#PB_Program_Write|#PB_Program_Error|#PB_Program_Hide|*Parameter\ProgramReadWriteMode)
   
    If *Parameter\ProgramID
     
      Repeat
       
        ReadLen = AvailableProgramOutput(*Parameter\ProgramID)
        If ReadLen
          ReadLen = ReadProgramData(*Parameter\ProgramID, *Buffer, ReadLen)
          If ReadLen
            *Parameter\StdOut$ = PeekS(*Buffer, ReadLen, PeekStringMode)
            PostEvent(#ExternalProgram_Event_StdOut)
            WaitSemaphore(*Parameter\Semaphore)
          EndIf
        EndIf
       
        Error$ = ReadProgramError(*Parameter\ProgramID, StringMode)
        If Len(Error$)
          *Parameter\StdErr$ = Error$
          PostEvent(#ExternalProgram_Event_Error)
          WaitSemaphore(*Parameter\Semaphore)
        EndIf
       
        If TryLockMutex(*Parameter\Mutex)
          If Len(*Parameter\StdIn$)
            *Parameter\StdIn$ + #CRLF$
            WriteLen = PokeS(*Buffer, *Parameter\StdIn$, -1, StringMode|#PB_String_NoZero)
            *Parameter\StdIn$ = ""
            WriteLen = WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
            SignalSemaphore(*Parameter\Semaphore)
          EndIf
          UnlockMutex(*Parameter\Mutex)
        EndIf
       
        Delay(10)
       
      Until *Parameter\Exit Or Not ProgramRunning(*Parameter\ProgramID)
     
      If *Parameter\Exit
        If ProgramRunning(*Parameter\ProgramID)
          If Len(*Parameter\ProgramExit$)
            *Parameter\ProgramExit$ + #CRLF$
            WriteLen = PokeS(*Buffer, *Parameter\ProgramExit$, -1, StringMode|#PB_String_NoZero)
            WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
          Else
            WriteProgramData(*Parameter\ProgramID, #PB_Program_Eof, 0)
          EndIf
          Timeout = 300
          Repeat
            Delay(10)
            Timeout - 1
          Until Timeout = 0 Or Not ProgramRunning(*Parameter\ProgramID)
          If Timeout = 0
            Debug "Kill"
            KillProgram(*Parameter\ProgramID)
          EndIf
        EndIf
      EndIf
     
      CloseProgram(*Parameter\ProgramID)
     
    EndIf
   
    FreeMemory(*Buffer)
  EndIf
 
  PostEvent(#ExternalProgram_Event_Exit)
 
EndProcedure


;- Example
CompilerIf #PB_Compiler_IsMainFile
 
  Enumeration
    #Form0
    #EditorCommande
    #StringCommande
    #Bouton
  EndEnumeration
 
  Define Event.i, Exit.i, i.i, j.i
  Define ThreadParameter.ExternalProgramParameterStructure
 
  OpenWindow(#Form0, 379, 176, 608, 542, "Remote console", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_TitleBar)
  EditorGadget(#EditorCommande, 5, 15, 593, 447)
  StringGadget(#StringCommande, 6, 469, 594, 23, "help")
  ButtonGadget(#Bouton, 211, 503, 201, 33, "Send to Console")
 
  ThreadParameter\Program$ = "cmd.exe"
  ThreadParameter\ProgramReadWriteMode = #PB_Program_UTF8
  ThreadParameter\ProgramExit$ = "console.exit()"
  ThreadParameter\Semaphore = CreateSemaphore()
  ThreadParameter\Mutex = CreateMutex()
  ThreadParameter\Thread = CreateThread(@ExternalProgramThread(), @ThreadParameter)
 
  Repeat
   
    Event = WaitWindowEvent()
   
    Select Event
      Case #ExternalProgram_Event_StdOut
        ThreadParameter\StdOut$ = RemoveString(ThreadParameter\StdOut$, #CR$)
        ThreadParameter\StdOut$ = RTrim(ThreadParameter\StdOut$, #LF$)
        i = CountString(ThreadParameter\StdOut$, #LF$)
        For j = 0 To i
          AddGadgetItem(#EditorCommande, -1, StringField(ThreadParameter\StdOut$, j + 1, #LF$))
        Next j
        SignalSemaphore(ThreadParameter\Semaphore)
       
      Case #ExternalProgram_Event_Error
        Debug ThreadParameter\StdErr$
        SignalSemaphore(ThreadParameter\Semaphore)
       
      Case #ExternalProgram_Event_Exit
        Exit = #True
       
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Bouton
            LockMutex(ThreadParameter\Mutex)
            ThreadParameter\StdIn$ = GetGadgetText(#StringCommande)
            UnlockMutex(ThreadParameter\Mutex)
            WaitSemaphore(ThreadParameter\Semaphore)
        EndSelect
       
      Case #PB_Event_CloseWindow
        If IsThread(ThreadParameter\Thread)
          ThreadParameter\Exit = #True
          WaitThread(ThreadParameter\Thread)
        EndIf
        FreeMutex(ThreadParameter\Mutex)
        FreeSemaphore(ThreadParameter\Semaphore)
        Exit = #True
    EndSelect
   
  Until Exit
 
CompilerEndIf

_________________
ImageThe happiness is a road...
Not a destination


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Sun Nov 24, 2019 5:29 pm 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4523
Location: Germany
I extended the code above.
The exit stuff was not working if the programm have transmitted data in the 'pipeline'.

I think cmd does not listen on stdin.
It only listens on key presses.

Here is an example, which shows that Inkey() does not return any values.
Only ReadConsoleData() returns stdin.
Code:
OpenConsole()

PrintN("Console started")

*Buffer = AllocateMemory(1024)
If *Buffer
 
  Repeat
   
    Inkey$ = Inkey()
    If Inkey$ <> ""
      OpenFile(0, GetPathPart(ProgramFilename()) + "Console.log", #PB_File_Append)
      WriteString(0, "Inkey: " + Inkey$)
      CloseFile(0)
      In$ + Inkey$
    EndIf
   
    If ReadConsoleData(*Buffer, 1) = 1
      Inkey$ = PeekS(*Buffer, 1, #PB_UTF8)
      OpenFile(0, GetPathPart(ProgramFilename()) + "Console.log", #PB_File_Append)
      WriteString(0, "ReadConsoleData: " + Inkey$)
      CloseFile(0)
      In$ + Inkey$
    EndIf
   
    If Inkey$ = #CR$
      Print(In$)
      If In$ = "exit" + #CR$
        OpenFile(0, GetPathPart(ProgramFilename()) + "Console.log", #PB_File_Append)
        WriteStringN(0, "EXIT")
        CloseFile(0)
        Break
      EndIf
      In$ = ""
    EndIf
   
  ForEver
 
  OpenFile(0, GetPathPart(ProgramFilename()) + "Console.log", #PB_File_Append)
  WriteStringN(0, "BREAKED")
  CloseFile(0)
 
  FreeMemory(*Buffer)
EndIf

PrintN("Console terminated")

CloseConsole()

Save it as Console.pb and compile it to Console.exe.
Then call it instead of Cmd.exe.


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Sun Nov 24, 2019 7:42 pm 
Offline
Addict
Addict
User avatar

Joined: Sun Nov 05, 2006 11:42 pm
Posts: 4632
Location: Lyon - France
Hello INFRATEC :wink:

Unfortunately your new code always not works :|
See the answer of "HELP" command (Specials characters and not the full answer)

Quote:
Microsoft Windows [version 10.0.17763.864]
(c) 2018 Microsoft Corporation. Tous droits r�serv�s.

D:\Temp\Lecture console v5.70 [Infratec]>
help
Pour plus d'informations sur une commande sp�cifique, entrez HELP
suivi de la commande.
ASSOC Affiche ou modifie les applications associ�es aux extensions de
fichiers.
ATTRIB Affiche ou modifie les attributs d'un fichier.
BREAK Active ou d�sactive le contr�le �tendu de CTRL+C.
BCDEDIT D�finit les propri�t�s dans la base de donn�es de d�marrage pour
le contr�le du chargement d'amor�age.
CACLS Affiche ou modifie les listes de contr�les d'acc�s aux fichiers.
CALL Appelle un fichier de commandes � partir d'un autre fichier de
commandes.
CD Modifie le r�pertoire ou affiche le r�pertoire actif.
CHCP Modifie ou affiche le num�ro de la page de code active.
CHDIR Modifie le r�pertoire ou affiche le nom du r�pertoire actif.
CHKDSK V�rifie un disque et affiche un rapport d'�tat.
CHKNTFS Affiche ou modifie la v�rification du disque au d�marrage.
CLS Efface l'�cran.
CMD Ex�cute une nouvelle instance de l'interpr�teur de commandes de
Windows.
COLOR Modifie les couleurs du premier plan et de l'arri�re-plan de la
console.
COMP Compare les contenus de deux fichiers ou groupes de fichiers.
COMPACT Modifie ou affiche la compression des fichiers sur une
partition NTFS.
CONVERT Convertit des volumes FAT en volumes NTFS. Vous ne pouvez pas
convertir le lecteur en cours d'utilisation.
COPY Copie un ou plusieurs fichiers.
DATE Affiche ou d�finit la date.
Then the full answer wit "cmd.exe" and "help" manually is
Quote:
Microsoft Windows [version 10.0.17763.864]
(c) 2018 Microsoft Corporation. Tous droits réservés.

C:\>help
Pour plus d’informations sur une commande spécifique, entrez HELP
suivi de la commande.
ASSOC Affiche ou modifie les applications associées aux extensions de
fichiers.
ATTRIB Affiche ou modifie les attributs d’un fichier.
BREAK Active ou désactive le contrôle étendu de CTRL+C.
BCDEDIT Définit les propriétés dans la base de données de démarrage pour
le contrôle du chargement d’amorçage.
CACLS Affiche ou modifie les listes de contrôles d’accès aux fichiers.
CALL Appelle un fichier de commandes à partir d’un autre fichier de
commandes.
CD Modifie le répertoire ou affiche le répertoire actif.
CHCP Modifie ou affiche le numéro de la page de code active.
CHDIR Modifie le répertoire ou affiche le nom du répertoire actif.
CHKDSK Vérifie un disque et affiche un rapport d’état.
CHKNTFS Affiche ou modifie la vérification du disque au démarrage.
CLS Efface l’écran.
CMD Exécute une nouvelle instance de l’interpréteur de commandes de
Windows.
COLOR Modifie les couleurs du premier plan et de l’arrière-plan de la
console.
COMP Compare les contenus de deux fichiers ou groupes de fichiers.
COMPACT Modifie ou affiche la compression des fichiers sur une
partition NTFS.
CONVERT Convertit des volumes FAT en volumes NTFS. Vous ne pouvez pas
convertir le lecteur en cours d’utilisation.
COPY Copie un ou plusieurs fichiers.
DATE Affiche ou définit la date.
DEL Supprime un ou plusieurs fichiers.
DIR Affiche la liste des fichiers et des sous-répertoires d’un
répertoire.
DISKPART Affiche ou configure les propriétés d'une partition de disque.
DOSKEY Modifie les lignes de commande, rappelle des commandes Windows,
et crée des macros.
DRIVERQUERY Affiche l'état et les propriétés du pilote de périphérique en
cours d'utilisation.
ECHO Affiche des messages ou active/désactive l'affichage des
commandes.
ENDLOCAL Stoppe la localisation des modifications d'environnement dans
un fichier de commandes.
ERASE Supprime un ou plusieurs fichiers.
EXIT Quitte l'interpréteur de commandes (CMD.EXE).
FC Compare deux fichiers ou groupes de fichiers et affiche
les différences.
FIND Recherche une chaîne de caractères dans un ou plusieurs
fichiers.
FINDSTR Cherche des chaînes dans les fichiers.
FOR Exécute une commande sur chaque fichier d'un ensemble de
fichiers.
FORMAT Formate un disque devant être utilisé avec Windows.
FSUTIL Affiche ou configure les propriétés du système de fichiers.
FTYPE Affiche ou modifie les types de fichiers utilisés dans les
associations d'extensions.
GOTO Indique l'exécution d'un fichier de commandes pour une ligne
identifiée par une étiquette.
GPRESULT Affiche les informations de stratégie de groupe pour un
ordinateur ou un utilisateur.
GRAFTABL Permet à Windows d'afficher un jeu de caractères en
mode graphique.
HELP Affiche des informations sur les commandes de Windows.
ICACLS Afficher, modifier, sauvegarder ou restaurer les listes de
contrôle d'accès pour les fichiers et les répertoires.
IF Effectue un traitement conditionnel dans un fichier de
commandes.
LABEL Crée, modifie ou supprime le nom de volume d'un disque.
MD Crée un répertoire.
MKDIR Crée un répertoire.
MKLINK Créer des liens symboliques et des liens physiques
MODE Configure un périphérique du système.
MORE Affiche la sortie écran par écran.
MOVE Déplace un ou plusieurs fichiers d'un répertoire
à un autre.
OPENFILES Affiche les fichiers partagés ouverts à distance par les
utilisateurs.
PATH Affiche ou définit le chemin de recherche des fichiers
exécutables.
PAUSE Interrompt l'exécution d'un fichier de commandes et affiche un
message.
POPD Restaure la valeur précédente du répertoire actif enregistrée
par PUSHD.
PRINT Imprime un fichier texte.
PROMPT Modifie l'invite de commande de Windows.
PUSHD Enregistre le répertoire actif puis le modifie.
RD Supprime un répertoire.
RECOVER Récupère l'information lisible d'un disque défectueux.
REM Insère un commentaire dans un fichier de commandes ou
CONFIG.SYS.
REN Renomme un ou plusieurs fichiers.
RENAME Renomme un ou plusieurs fichiers.
REPLACE Remplace des fichiers.
RMDIR Supprime un répertoire.
ROBOCOPY Utilitaire avancé pour copier les fichiers et les
arborescences de répertoires
SET Affiche, définit ou supprime des variables d'environnement
Windows.
SETLOCAL Commence la localisation des modifications d'environnement dans
un fichier de commandes.
SC Affiche ou configure les services (processus en arrière-plan).
SCHTASKS Planifie les commandes et les programmes à exécuter sur
l'ordinateur.
SHIFT Modifie la position des paramètres remplaçables dans un fichier
de commandes.
SHUTDOWN Permet un arrêt local ou distant correct de l'ordinateur.
SORT Trie les entrées.
START Ouvre une fenêtre séparée pour l'exécution d'un programme ou
d'une commande spécifique.
SUBST Associe un chemin d'accès à une lettre de lecteur.
SYSTEMINFO Affiche les propriétés et la configuration spécifiques de
l'ordinateur.
TASKLIST Affiche toutes les tâches en cours d'exécution, y compris les
services.
TASKKILL Termine ou interrompt un processus ou une application en cours
d'exécution.
TIME Affiche ou définit l'heure du système.
TITLE Définit le titre de la fenêtre pour une session CMD.EXE.
TREE Affiche le graphisme de la structure de répertoire d'un lecteur
ou d'un chemin d'accès.
TYPE Affiche le contenu d'un fichier texte.
VER Affiche la version de Windows.
VERIFY Demande à Windows de vérifier si vos fichiers sont
correctement écrits sur le disque.
VOL Affiche le nom et le numéro de série d'un volume de disque.
XCOPY Copie les fichiers et les arborescences de répertoires.
WMIC Affiche les informations WMI dans l'interface de commande
interactive.

Pour obtenir plus d'informations sur les outils, consultez la référence de
commande en ligne dans l'aide en ligne.


In fact it's worst of that, i have see if i not run manually the "cmd.exe" and do "help" i have no answer :shock:
Then if i run "cmd.exe" and write "help" and close console, your code give the partial answer above
This is the code i use in W10 X64 / v5.70 X86
Code:
CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

CompilerIf Not #PB_Compiler_Thread
  MessageRequester("Info", "Enable Thread-Safe in compiler options!")
  End
CompilerEndIf

CompilerIf Not Defined(FirstCustomValue, #PB_Enumeration)
 
  Enumeration FirstCustomValue #PB_Event_FirstCustomValue
    #ExternalProgram_Event_StdOut
    #ExternalProgram_Event_Error
    #ExternalProgram_Event_Exit
  EndEnumeration
 
CompilerElse
 
  Enumeration FirstCustomValue
    #ExternalProgram_Event_StdOut
    #ExternalProgram_Event_Error
    #ExternalProgram_Event_Exit
  EndEnumeration
 
CompilerEndIf

Structure ExternalProgramParameterStructure
  Program$
  ProgramParameter$
  ProgramWorkingDirectory$
  ProgramReadWriteMode.i
  ProgramExit$
  Semaphore.i
  Mutex.i
  Thread.i
  ProgramID.i
  StdOut$
  StdIn$
  StdErr$
  Exit.i
EndStructure

Procedure ExternalProgramThread(*Parameter.ExternalProgramParameterStructure)
 
  Protected *Buffer, ReadLen.i, WriteLen.i, Error$, Timeout.i, StringMode.i, PeekStringMode.i
 
  *Buffer = AllocateMemory(1024)
 
  If *Buffer
   
    Select *Parameter\ProgramReadWriteMode
      Case #PB_Program_Ascii
        StringMode = #PB_Ascii
        PeekStringMode = #PB_Ascii
      Case #PB_Program_Unicode
        StringMode = #PB_Unicode
        PeekStringMode = #PB_Unicode
      Case #PB_Program_UTF8
        StringMode = #PB_UTF8
        PeekStringMode = #PB_UTF8|#PB_ByteLength
    EndSelect
   
    *Parameter\ProgramID = RunProgram(*Parameter\Program$, *Parameter\ProgramParameter$, *Parameter\ProgramWorkingDirectory$, #PB_Program_Open|#PB_Program_Read|#PB_Program_Write|#PB_Program_Error|#PB_Program_Hide|*Parameter\ProgramReadWriteMode)
   
    If *Parameter\ProgramID
     
      Repeat
       
        ReadLen = AvailableProgramOutput(*Parameter\ProgramID)
        If ReadLen
          ReadLen = ReadProgramData(*Parameter\ProgramID, *Buffer, ReadLen)
          If ReadLen
            *Parameter\StdOut$ = PeekS(*Buffer, ReadLen, PeekStringMode)
            PostEvent(#ExternalProgram_Event_StdOut)
            WaitSemaphore(*Parameter\Semaphore)
          EndIf
        EndIf
       
        Error$ = ReadProgramError(*Parameter\ProgramID, StringMode)
        If Len(Error$)
          *Parameter\StdErr$ = Error$
          PostEvent(#ExternalProgram_Event_Error)
          WaitSemaphore(*Parameter\Semaphore)
        EndIf
       
        If TryLockMutex(*Parameter\Mutex)
          If Len(*Parameter\StdIn$)
            *Parameter\StdIn$ + #CRLF$
            WriteLen = PokeS(*Buffer, *Parameter\StdIn$, -1, StringMode|#PB_String_NoZero)
            *Parameter\StdIn$ = ""
            WriteLen = WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
            SignalSemaphore(*Parameter\Semaphore)
          EndIf
          UnlockMutex(*Parameter\Mutex)
        EndIf
       
        Delay(10)
       
      Until *Parameter\Exit Or Not ProgramRunning(*Parameter\ProgramID)
     
      If *Parameter\Exit
        If ProgramRunning(*Parameter\ProgramID)
          If Len(*Parameter\ProgramExit$)
            *Parameter\ProgramExit$ + #CRLF$
            WriteLen = PokeS(*Buffer, *Parameter\ProgramExit$, -1, StringMode|#PB_String_NoZero)
            WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
          Else
            WriteProgramData(*Parameter\ProgramID, #PB_Program_Eof, 0)
          EndIf
          Timeout = 300
          Repeat
            Delay(10)
            Timeout - 1
            While AvailableProgramOutput(*Parameter\ProgramID)
              ReadProgramData(*Parameter\ProgramID, *Buffer, 1)
            Wend
          Until Timeout = 0 Or Not ProgramRunning(*Parameter\ProgramID)
          If Timeout = 0
            Debug "Kill"
            KillProgram(*Parameter\ProgramID)
          EndIf
        EndIf
      EndIf
     
      CloseProgram(*Parameter\ProgramID)
     
    EndIf
   
    FreeMemory(*Buffer)
  EndIf
 
  PostEvent(#ExternalProgram_Event_Exit)
 
EndProcedure

;- Example
CompilerIf #PB_Compiler_IsMainFile
 
  Enumeration
    #Form0
    #EditorCommande
    #StringCommande
    #Bouton
  EndEnumeration
 
  Define Event.i, Exit.i, i.i, j.i
  Define ThreadParameter.ExternalProgramParameterStructure
 
  OpenWindow(#Form0, 379, 176, 608, 542, "Remote console", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_TitleBar)
  EditorGadget(#EditorCommande, 5, 15, 593, 447)
  StringGadget(#StringCommande, 6, 469, 594, 23, "help")
  ButtonGadget(#Bouton, 211, 503, 201, 33, "Send to console")
 
  ThreadParameter\Program$ = "cmd.exe"
  ThreadParameter\ProgramReadWriteMode = #PB_Program_UTF8
  ThreadParameter\ProgramExit$ = "console.exit()"
  ThreadParameter\Semaphore = CreateSemaphore()
  ThreadParameter\Mutex = CreateMutex()
  ThreadParameter\Thread = CreateThread(@ExternalProgramThread(), @ThreadParameter)
 
  Repeat
   
    Event = WaitWindowEvent()
   
    Select Event
      Case #ExternalProgram_Event_StdOut
        ThreadParameter\StdOut$ = RemoveString(ThreadParameter\StdOut$, #CR$)
        ThreadParameter\StdOut$ = RTrim(ThreadParameter\StdOut$, #LF$)
        i = CountString(ThreadParameter\StdOut$, #LF$)
        For j = 0 To i
          AddGadgetItem(#EditorCommande, -1, StringField(ThreadParameter\StdOut$, j + 1, #LF$))
        Next j
        SignalSemaphore(ThreadParameter\Semaphore)
       
      Case #ExternalProgram_Event_Error
        Debug ThreadParameter\StdErr$
        SignalSemaphore(ThreadParameter\Semaphore)
       
      Case #ExternalProgram_Event_Exit
        Exit = #True
       
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Bouton
            LockMutex(ThreadParameter\Mutex)
            ThreadParameter\StdIn$ = GetGadgetText(#StringCommande)
            UnlockMutex(ThreadParameter\Mutex)
            WaitSemaphore(ThreadParameter\Semaphore)
        EndSelect
       
      Case #PB_Event_CloseWindow
        If IsThread(ThreadParameter\Thread)
          ThreadParameter\Exit = #True
          WaitThread(ThreadParameter\Thread)
        EndIf
        FreeMutex(ThreadParameter\Mutex)
        FreeSemaphore(ThreadParameter\Semaphore)
        Exit = #True
    EndSelect
   
  Until Exit
 
CompilerEndIf


And you have right...the close windows not works too :|
Decidedly....this "black" console have apparently "not affraid" and is very difficult to train :mrgreen:

Image

Thanks MASTER for all you try to help me 8)

_________________
ImageThe happiness is a road...
Not a destination


Last edited by Kwai chang caine on Sun Nov 24, 2019 7:53 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Sun Nov 24, 2019 7:52 pm 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4523
Location: Germany
What I was trying to show you with my Console.pb is:

Some programs does not react on stdin, they only react on keyboard strokes.
It looks like cmd.exe is also such a program.


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Sun Nov 24, 2019 7:55 pm 
Offline
Addict
Addict
User avatar

Joined: Sun Nov 05, 2006 11:42 pm
Posts: 4632
Location: Lyon - France
Yes i have understand that, but why your code not return the full answer of "Help" command, and furthermore bad characters :| (See THREAD above viewtopic.php?p=545203#p545203) :wink:

_________________
ImageThe happiness is a road...
Not a destination


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Sun Nov 24, 2019 9:47 pm 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4523
Location: Germany
Hi KCC,

I fixed a bug in my code.
I had a fixed buffer of 1024 bytes. This buffer was to small for the help output.
Now I changed this to be reallocatable.

Next thing in your code:

Code:
ThreadParameter\ProgramExit$ = "console.exit()"

should be
Code:
ThreadParameter\ProgramExit$ = "exit"


Then cmd.exe generates ascii an not utf-8

Code:
ThreadParameter\ProgramReadWriteMode = #PB_Program_Ascii


Next problem:
It returns ASCII for a specific codepage.
So all codes above 127 are codespace specific and are not displayed correctly with a standard font.


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Sun Nov 24, 2019 9:49 pm 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4523
Location: Germany
Hi KCC,

I extended again :mrgreen:

Now with CP852 and CP437 converter.
I use now your cmd example, since everyone has cmd.exe on his PC :wink:
You can simpy copy the complete listing.


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Mon Nov 25, 2019 7:40 am 
Offline
Addict
Addict

Joined: Sat Feb 08, 2014 3:26 pm
Posts: 825
Thank you infratec,
It works very well (at least for our french accents)
:wink:

_________________
(English is not my native language, I use an online translator)
Windows 10 Family x64 + Linux (Slackware, Debian on Oracle VirtualBox 6.0) + Raspberry Pi
All codes are tested with the latest version of PB, including beta versions at date of post.


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Mon Nov 25, 2019 7:53 pm 
Offline
Addict
Addict
User avatar

Joined: Sun Nov 05, 2006 11:42 pm
Posts: 4632
Location: Lyon - France
One thousand of thanks MASTER 8)
You are an angel
Image
Then this time :

1/ The full return of "help" command works perfectly 8)
2/ The close of windows too 8) 8)

3/ But there is again a little problem with the french accent (This french....never do like others :? sometime i say to me, that even Microsoft is not also complex than the french langage :mrgreen:)

See yourself :
Splendid code of master INFRATEC wrote:
CALL Appelle un fichier de commandes ů partir d'un autre fichier de
commandes.
FIND Recherche une chaîne de caractŐres dans un ou plusieurs
fichiers.
MODE Configure un périphérique du systŐme.
etc .....
Must be
Cmd.exe ''help'' manual wrote:
CALL Appelle un fichier de commandes à partir d’un autre fichier de
commandes.
FIND Recherche une chaîne de caractères dans un ou plusieurs
fichiers.

_________________
ImageThe happiness is a road...
Not a destination


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Mon Nov 25, 2019 9:03 pm 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4523
Location: Germany
Marc56us meant that it is Ok.

Do you now the codepage which is used normally for french?
I thought it is also 852.


Top
 Profile  
Reply with quote  
 Post subject: Re: Handle an external program via stdin/out/error
PostPosted: Mon Nov 25, 2019 9:45 pm 
Offline
Addict
Addict

Joined: Sun Sep 07, 2008 12:45 pm
Posts: 4523
Location: Germany
Added codepage 863 Canadian-french and 1252 Latin I


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye