RunProgramConPTY (windows only)

Share your advanced PureBasic knowledge/code with the community.
infratec
Always Here
Always Here
Posts: 7834
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

RunProgramConPTY (windows only)

Post by infratec »

Since RunProgram() is not able to fetch all output of some console programs, I wrote a PseudoConsole program, which fetch the output.

This is a work in progress and I don't know if I ever implement all possible stuff.

Code: Select all

;
; RunProgramConPTY.pbi
;
; by infratec
;
; https://www.purebasic.fr/english/viewtopic.php?t=88449
;
; 2026.03.01 16:00  initial upload
; 2026.03.01 17:02  added the write procedures
; 2026.03.01 18:14  added a Mutex for reading
; 2026.03.01 20:17  check the Mutex before using it
;


CompilerIf Not #PB_Compiler_Thread
  CompilerError "Enable threadsafe option!"
CompilerEndIf

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf



#PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = $00020016
#EXTENDED_STARTUPINFO_PRESENT = $00080000

#HANDLE_FLAG_INHERIT = 1
#HANDLE_FLAG_PROTECT_FROM_CLOSE = 2

Structure STARTUPINFOEX
  StartupInfo.STARTUPINFO
  *lpAttributeList
EndStructure

Structure RunProgramConPTY_Structure
  Id.i
  Flags.i
  hPipePTYInR.i
  hPipePTYInW.i
  hPipePTYOutR.i
  hPipePTYOutW.i
  sa.SECURITY_ATTRIBUTES
  si.STARTUPINFOEX
  pi.PROCESS_INFORMATION
  hPC.i
  Thread.i
  ReadThread.i
  *BufferRead
  BufferReadMutex.i
  exitCode.l
  window.i
  Exit.i
EndStructure


Prototype.l Proto_CreatePseudoConsole(size.l, hInput.i, hOutput.i, dwFlags.l, *phPC)
Prototype Proto_ClosePseudoConsole(hPC.i)
Prototype.l Proto_InitializeProcThreadAttributeList(*lpAttributeList, dwAttributeCount.l, dwFlags.l, *lpSize)
Prototype.l Proto_UpdateProcThreadAttribute(*lpAttributeList, dwFlags.l, *Attribute, *lpValue, cbSize.i, *lpPreviousValue, *lpReturnSize)
Prototype Proto_DeleteProcThreadAttributeList(*lpAttributeList)

Global CreatePseudoConsole.Proto_CreatePseudoConsole
Global ClosePseudoConsole.Proto_ClosePseudoConsole
Global InitializeProcThreadAttributeList.Proto_InitializeProcThreadAttributeList
Global UpdateProcThreadAttribute.Proto_UpdateProcThreadAttribute
Global DeleteProcThreadAttributeList.Proto_DeleteProcThreadAttributeList


Global NewMap RunProgramConPTYMap.RunProgramConPTY_Structure()


XIncludeFile "RemoveANSIEscapeCodes.pbi"




Define RunProgramConPTY_kernel32.i


RunProgramConPTY_kernel32 = OpenLibrary(#PB_Any, "Kernel32.dll")
If RunProgramConPTY_kernel32
  CreatePseudoConsole = GetFunction(RunProgramConPTY_kernel32, "CreatePseudoConsole")
  ClosePseudoConsole = GetFunction(RunProgramConPTY_kernel32, "ClosePseudoConsole")
  InitializeProcThreadAttributeList = GetFunction(RunProgramConPTY_kernel32, "InitializeProcThreadAttributeList")
  UpdateProcThreadAttribute = GetFunction(RunProgramConPTY_kernel32, "UpdateProcThreadAttribute")
  DeleteProcThreadAttributeList = GetFunction(RunProgramConPTY_kernel32, "DeleteProcThreadAttributeList")
EndIf




Procedure RunProgramConPTYReadThread(*RunProgramConPTY.RunProgramConPTY_Structure)
  
  Protected *Buffer, BufferPtr.i, bytesRead.l
  
  
  *Buffer = AllocateMemory(4096)
  If *Buffer
    
    Repeat
      
      If ReadFile_(*RunProgramConPTY\hPipePTYOutR, *Buffer, MemorySize(*Buffer), @bytesRead, #Null) And bytesRead > 0
        
        ;         Debug bytesRead
        
        If *RunProgramConPTY\BufferReadMutex
          
          LockMutex(*RunProgramConPTY\BufferReadMutex)
          
          If *RunProgramConPTY\BufferRead = #Null
            *RunProgramConPTY\BufferRead = AllocateMemory(bytesRead, #PB_Memory_NoClear)
            BufferPtr = 0
          Else
            BufferPtr = MemorySize(*RunProgramConPTY\BufferRead)
            *RunProgramConPTY\BufferRead = ReAllocateMemory(*RunProgramConPTY\BufferRead, BufferPtr + bytesRead)
          EndIf
          
          ;ShowMemoryViewer(*Buffer, bytesRead)
          
          CopyMemory(*Buffer, *RunProgramConPTY\BufferRead + BufferPtr, bytesRead)
          
          UnlockMutex(*RunProgramConPTY\BufferReadMutex)
          
        EndIf
        
      EndIf
      
    Until *RunProgramConPTY\Exit
    
    FreeMemory(*Buffer)
  EndIf
  
EndProcedure


Procedure RunProgramConPTYThread(*RunProgramConPTY.RunProgramConPTY_Structure)
  
  Protected ExitCode.l
  
  
  If *RunProgramConPTY\Flags & #PB_Program_Read
    *RunProgramConPTY\ReadThread = CreateThread(@RunProgramConPTYReadThread(), *RunProgramConPTY)
  EndIf
  
  ExitCode = #STILL_ACTIVE
  
  Repeat
    
    If ExitCode = #STILL_ACTIVE
      GetExitCodeProcess_(*RunProgramConPTY\pi\hProcess, @exitCode)
      Delay(10)
    Else
      Delay(100)  ; to allow processing of Read
      *RunProgramConPTY\exitCode = ExitCode
    EndIf
    
  Until *RunProgramConPTY\Exit
  
EndProcedure


Procedure.i IsProgramConPTY(Program.i)
  
  Protected Result.i
  
  
  If FindMapElement(RunProgramConPTYMap(), Str(Program))
    Result = #True
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


Procedure.i ProgramRunningConPTY(Program.i)
  
  Protected Result.i, *RunProgramConPTY.RunProgramConPTY_Structure
  
  
  *RunProgramConPTY = FindMapElement(RunProgramConPTYMap(), Str(Program))
  If *RunProgramConPTY
    If *RunProgramConPTY\exitCode = #STILL_ACTIVE
      Result = #True
    EndIf
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


Procedure.i AvailableProgramOutputConPTY(Program.i)
  
  Protected Result.i, *RunProgramConPTY.RunProgramConPTY_Structure
  
  
  *RunProgramConPTY = FindMapElement(RunProgramConPTYMap(), Str(Program))
  If *RunProgramConPTY
    If *RunProgramConPTY\BufferRead
      Result = MemorySize(*RunProgramConPTY\BufferRead)
    EndIf
  EndIf
  
  ProcedureReturn Result
  
EndProcedure


Procedure.i ReadProgramDataConPTY(Program.i, *Buffer, Size.i)
  
  Protected Result.i, *RunProgramConPTY.RunProgramConPTY_Structure
  
  
  *RunProgramConPTY = FindMapElement(RunProgramConPTYMap(), Str(Program))
  If *RunProgramConPTY
    LockMutex(*RunProgramConPTY\BufferReadMutex)
    If Size > MemorySize(*RunProgramConPTY\BufferRead)
      Size = MemorySize(*RunProgramConPTY\BufferRead)
    EndIf
    CopyMemory(*RunProgramConPTY\BufferRead, *Buffer, Size)
    If Size = MemorySize(*RunProgramConPTY\BufferRead)
      FreeMemory(*RunProgramConPTY\BufferRead)
      *RunProgramConPTY\BufferRead = #Null
    Else
      MoveMemory(*RunProgramConPTY\BufferRead + Size, *RunProgramConPTY\BufferRead, MemorySize(*RunProgramConPTY\BufferRead) - Size)
      *RunProgramConPTY\BufferRead = ReAllocateMemory(*RunProgramConPTY\BufferRead, MemorySize(*RunProgramConPTY\BufferRead) - Size)
    EndIf
    UnlockMutex(*RunProgramConPTY\BufferReadMutex)
  EndIf
  
  ProcedureReturn Size
  
EndProcedure


Procedure.s ReadProgramStringConPTY(Program.i)
  
  Protected *RunProgramConPTY.RunProgramConPTY_Structure, Result$, *CharPtr.Ascii, *BufferEnd
  
  
  *RunProgramConPTY = FindMapElement(RunProgramConPTYMap(), Str(Program))
  If *RunProgramConPTY
    
    Repeat
      
      LockMutex(*RunProgramConPTY\BufferReadMutex)
      If *RunProgramConPTY\BufferRead
        
        *BufferEnd = *RunProgramConPTY\BufferRead + MemorySize(*RunProgramConPTY\BufferRead) - 1
        *CharPtr = *RunProgramConPTY\BufferRead
        While *CharPtr < *BufferEnd
          If *CharPtr\a = #CR            
            ;ShowMemoryViewer(*RunProgramConPTY\BufferRead, MemorySize(*RunProgramConPTY\BufferRead))
            *CharPtr + 1
            If *CharPtr\a = #LF
              Result$ = PeekS(*RunProgramConPTY\BufferRead, *CharPtr - *RunProgramConPTY\BufferRead + 1, #PB_ByteLength|#PB_UTF8)
              *CharPtr + 1
            Else
              Result$ = PeekS(*RunProgramConPTY\BufferRead, *CharPtr - *RunProgramConPTY\BufferRead, #PB_ByteLength|#PB_UTF8)
            EndIf
            If *CharPtr < *BufferEnd
              ;Debug "NotEnd"
              MoveMemory(*CharPtr, *RunProgramConPTY\BufferRead, *BufferEnd - *CharPtr + 1)
              *RunProgramConPTY\BufferRead = ReAllocateMemory(*RunProgramConPTY\BufferRead, *BufferEnd - *CharPtr + 1)
              ;ShowMemoryViewer(*RunProgramConPTY\BufferRead, MemorySize(*RunProgramConPTY\BufferRead))
            Else
              FreeMemory(*RunProgramConPTY\BufferRead)
              *RunProgramConPTY\BufferRead = #Null
            EndIf
            Break
          EndIf
          *CharPtr + 1
        Wend
        
      EndIf
      UnlockMutex(*RunProgramConPTY\BufferReadMutex)
      
    Until Result$ <> "" Or *RunProgramConPTY\exitCode <> #STILL_ACTIVE
    
  EndIf
  
  
  ProcedureReturn Result$
  
EndProcedure


Procedure.i WriteProgramDataConPTY(Program.i, *Buffer, Size.l)
  
  Protected Result.i, *RunProgramConPTY.RunProgramConPTY_Structure, BytesWritten.l
  
  
  *RunProgramConPTY = FindMapElement(RunProgramConPTYMap(), Str(Program))
  If *RunProgramConPTY
    If *RunProgramConPTY\Flags & (#PB_Program_Open | #PB_Program_Write) = #PB_Program_Open | #PB_Program_Write
      If Not WriteFile_(*RunProgramConPTY\hPipePTYInW, *Buffer, Size, @BytesWritten, #Null)
        BytesWritten = 0
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn BytesWritten
  
EndProcedure


Procedure.i WriteProgramStringConPTY(Program.i, String$)
  
  Protected Result.i, *RunProgramConsole.RunProgramConPTY_Structure, BytesWritten.i, *Buffer
  
  *RunProgramConsole = FindMapElement(RunProgramConPTYMap(), Str(Program))
  If *RunProgramConsole
    
    *Buffer = AllocateMemory(StringByteLength(String$, #PB_UTF8), #PB_Memory_NoClear)
    If *Buffer
      PokeS(*Buffer, String$, -1, #PB_UTF8|#PB_String_NoZero)
      BytesWritten = WriteProgramDataConPTY(Program, *Buffer, MemorySize(*Buffer))
      FreeMemory(*Buffer)
    EndIf
    
  EndIf
  
  ProcedureReturn BytesWritten
  
EndProcedure


Procedure.i WriteProgramStringNConPTY(Program.i, String$)
  
  ProcedureReturn WriteProgramStringConPTY(Program.i, String$ + #CR$)
  
EndProcedure


Procedure CloseProgramConPTY(Program.i)
  
  Protected *RunProgramConPTY.RunProgramConPTY_Structure
  
  
  *RunProgramConPTY = FindMapElement(RunProgramConPTYMap(), Str(Program))
  If *RunProgramConPTY
    
    *RunProgramConPTY\Exit = #True
    If WaitThread(*RunProgramConPTY\Thread, 500) = 0
      Debug "Should never happen"
      KillThread(*RunProgramConPTY\Thread)
    EndIf
    
    If *RunProgramConPTY\BufferReadMutex
      FreeMutex(*RunProgramConPTY\BufferReadMutex)
      *RunProgramConPTY\BufferReadMutex = 0
    EndIf
    
    ; --- Cleanup ---
    CloseHandle_(*RunProgramConPTY\pi\hProcess)
    CloseHandle_(*RunProgramConPTY\pi\hThread)
    ClosePseudoConsole(*RunProgramConPTY\hPC)
    DeleteProcThreadAttributeList(*RunProgramConPTY\si\lpAttributeList)
    FreeMemory(*RunProgramConPTY\si\lpAttributeList)
    
    CloseHandle_(*RunProgramConPTY\hPipePTYOutR)
    CloseHandle_(*RunProgramConPTY\hPipePTYInW)
    
    DeleteMapElement(RunProgramConPTYMap(), Str(Program))
  EndIf
  
EndProcedure




Procedure RunProgramConPTYWindowCallBack()
  Debug "WindowCallBack"
EndProcedure




Procedure.i RunProgramConPTY(Filename$, Parameter$="", WorkingDirectory$="", Flags.i=0)
  
  Protected.i Id
  Protected.l Size
  Protected.q attrSize
  Protected cmd$
  Protected *lpCurrentDirectory
  Protected coord.COORD
  
  Protected *RunProgramConPTY.RunProgramConPTY_Structure
  
  
  Id = MapSize(RunProgramConPTYMap()) + 1
  
  *RunProgramConPTY = AddMapElement(RunProgramConPTYMap(), Str(Id))
  *RunProgramConPTY\Id = Id
  *RunProgramConPTY\Flags = Flags
  
  ; --- Create pipes for ConPTY ---
  
  *RunProgramConPTY\sa\nLength = SizeOf(SECURITY_ATTRIBUTES)
  *RunProgramConPTY\sa\bInheritHandle = #True
  
  CreatePipe_(@*RunProgramConPTY\hPipePTYInR, @*RunProgramConPTY\hPipePTYInW, @*RunProgramConPTY\sa, 0)
  CreatePipe_(@*RunProgramConPTY\hPipePTYOutR, @*RunProgramConPTY\hPipePTYOutW, @*RunProgramConPTY\sa, 0)
  
  ; The PTY side must NOT be inherited by child
  SetHandleInformation_(*RunProgramConPTY\hPipePTYOutR, #HANDLE_FLAG_INHERIT, 0)
  SetHandleInformation_(*RunProgramConPTY\hPipePTYInW,  #HANDLE_FLAG_INHERIT, 0)
  
  ; --- Create pseudo console ---
  
  coord\X = 80
  coord\Y = 40
  
  Size = coord\y << 16 | coord\x
  
  If CreatePseudoConsole(Size, *RunProgramConPTY\hPipePTYInR, *RunProgramConPTY\hPipePTYOutW, 0, @*RunProgramConPTY\hPC) = #S_OK
    
    InitializeProcThreadAttributeList(#Null, 1, 0, @attrSize)
    *RunProgramConPTY\si\lpAttributeList = AllocateMemory(attrSize)
    InitializeProcThreadAttributeList(*RunProgramConPTY\si\lpAttributeList, 1, 0, @attrSize)
    
    UpdateProcThreadAttribute(*RunProgramConPTY\si\lpAttributeList, 0, #PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, *RunProgramConPTY\hPC, SizeOf(Integer), #Null, #Null)
    
    *RunProgramConPTY\si\StartupInfo\cb = SizeOf(STARTUPINFOEX)
    
    If Flags & #PB_Program_Hide = 0
      *RunProgramConPTY\si\StartupInfo\dwFlags = #STARTF_USESHOWWINDOW
      *RunProgramConPTY\si\StartupInfo\wShowWindow = #SW_SHOW
    EndIf
    
    cmd$ = Filename$ + " " + Parameter$
    ;Debug cmd$
    
    If WorkingDirectory$ <> ""
      *lpCurrentDirectory = @WorkingDirectory$
    EndIf
    
    If CreateProcess_(#Null, @cmd$, #Null, #Null, #False, #EXTENDED_STARTUPINFO_PRESENT, #Null, *lpCurrentDirectory, @*RunProgramConPTY\si, @*RunProgramConPTY\pi)
      
      ; --- Close handles not needed ---
      CloseHandle_(*RunProgramConPTY\hPipePTYInR)   ; read from input
      CloseHandle_(*RunProgramConPTY\hPipePTYOutW)  ; write to output
      
      If *RunProgramConPTY\Flags & #PB_Program_Hide = 0
        ;         *RunProgramConPTY\window = OpenWindow(#PB_Any, 0, 0, 800, 400, "", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
        ;         SetWindowColor(*RunProgramConPTY\window, #Black)
        ;         BindEvent(#PB_Event_CloseWindow, @RunProgramConsoleWindowCallBack(), *RunProgramConPTY\window)
      EndIf
      
      Delay(100)  ; needed by x64
      
      *RunProgramConPTY\exitCode = #STILL_ACTIVE
      
      If Flags & #PB_Program_Open
        If Flags & #PB_Program_Read
          *RunProgramConPTY\BufferReadMutex = CreateMutex()
        EndIf
        *RunProgramConPTY\Thread = CreateThread(@RunProgramConPTYThread(), *RunProgramConPTY)
      EndIf
      
      If Flags & #PB_Program_Wait
        While *RunProgramConPTY\exitCode = #STILL_ACTIVE
          Delay(10)
        Wend
        CloseProgramConPTY(Id)
      EndIf
      
    EndIf
    
  EndIf
  
  ProcedureReturn Id
  
EndProcedure







;-Demo
CompilerIf #PB_Compiler_IsMainFile
  
  #Compiler$ = #DQUOTE$ + #PB_Compiler_Home + "Compilers\pbcompilerc.exe" + #DQUOTE$
  
  Define Prog.i, Length.i, Out$, *Buffer, SendState.i
  
  
  ;Prog = RunProgramConPTY(#Compiler$, #PB_Compiler_FilePath + "MySource.pb /PREPROCESS " + #PB_Compiler_FilePath + "FullSource.pb", "", #PB_Program_Open|#PB_Program_Read)
  Prog = RunProgramConPTY("cmd", "", "", #PB_Program_Open|#PB_Program_Read|#PB_Program_Write)
  If Prog
    
    *Buffer = AllocateMemory(4096)
    If *Buffer
      
      While ProgramRunningConPTY(Prog)
        
        Length = AvailableProgramOutputConPTY(Prog)
        If Length
          If ReadProgramDataConPTY(Prog, *Buffer, Length)
            Out$ = PeekS(*Buffer, Length, #PB_ByteLength|#PB_UTF8)
            ;Debug Out$
            Out$ = RemoveANSIEscapeCodes(@Out$)
            Debug Out$
            
            If Right(RTrim(Out$), 1) = ">"
              Select SendState
                Case 0
                  WriteProgramStringNConPTY(Prog, "date /t")
                  SendState = 1
                Case 1
                  WriteProgramStringNConPTY(Prog, "exit")
                  SendState = 2
              EndSelect
            EndIf
            
          EndIf
        EndIf
        
        ;Out$ + ReadProgramStringConPTY(Prog)
        
      Wend
      
      FreeMemory(*Buffer)
    EndIf
    CloseProgramConPTY(Prog)
    
    
    
    
  EndIf
  
CompilerEndIf
The needed helper:

Code: Select all

;
; RemoveANSIEscapeCodes.pbi
;


CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


Procedure.s RemoveANSIEscapeCodes(*CharPtr.Character)
  
  Protected Clean$, Char.c, State.i
  
  
  If *CharPtr
    While *CharPtr\c
      
      If *CharPtr\c = #ESC
        ; Jump behind the first letter, which terminates the escape sequence
        *CharPtr + 2
        State = 0
        While *CharPtr\c
          Char = *CharPtr\c
          Select State
            Case 0
              Select Char
                Case ']'
                  State = 1
                Case '['
                  State = 11
              EndSelect
            Case 1
              If Char = '0'
                State = 2 ; set window title
              Else
                State = 0
                Break
              EndIf
            Case 2
              If Char = ';' ; following text is the window title up to BEL
                State = 3
              Else
                State = 0
                Break
              EndIf
            Case 3
              If Char = #BEL
                State = 0
                *CharPtr + 2
                Break
              EndIf
              
            Case 11
              If (Char >= '@' And Char <= 'Z') Or (Char >= 'a' And Char <= '~')
                State = 0
                *CharPtr + 2
                Break
              EndIf
          EndSelect
          
          *CharPtr + 2
        Wend
      Else
        Clean$ + Chr(*CharPtr\c)
        *CharPtr + 2
      EndIf
    Wend
  EndIf
  
  ProcedureReturn Clean$
  
EndProcedure
Last edited by infratec on Wed Mar 04, 2026 8:14 am, edited 4 times in total.
Little John
Addict
Addict
Posts: 4864
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: RunProgramConsole (windows only)

Post by Little John »

Great! :thumbsup: Thank you very much :!:
Axolotl
Addict
Addict
Posts: 945
Joined: Wed Dec 31, 2008 3:36 pm

Re: RunProgramConsole (windows only)

Post by Axolotl »

@infratec
Awesome, that may solve my problems as well.
Thanks for sharing.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
infratec
Always Here
Always Here
Posts: 7834
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RunProgramConsole (windows only)

Post by infratec »

Added the write procedures:

Code: Select all

EnableExplicit

IncludeFile "RunProgramConsole.pbi"


Define Prog.i, *Buffer, Length.i, Out$, SendState.i


Prog = RunProgramConsole("cmd", "", "", #PB_Program_Open|#PB_Program_Read|#PB_Program_Write)
If Prog
  
  *Buffer = AllocateMemory(4096)
  If *Buffer
  
    While ProgramRunningConsole(Prog)
      
      Length = AvailableProgramOutputConsole(Prog)
      If Length
        If ReadProgramDataConsole(Prog, *Buffer, Length)
          Out$ = PeekS(*Buffer, Length, #PB_ByteLength|#PB_UTF8)
          ;Debug Out$
          Out$ = RemoveANSIEscapeCodes(@Out$)
          Debug Out$
          If SendState = 0
            If Right(RTrim(Out$), 1) = ">"
              PokeS(*Buffer, "date /t" + #CR$, -1, #PB_UTF8|#PB_String_NoZero)
              WriteProgramDataConsole(Prog, *Buffer, 8)
              SendState = 1
            EndIf
          EndIf
          
          If SendState = 1
            WriteProgramStringNConsole(Prog, "exit")
            SendState = 2
          EndIf
          
        EndIf
      EndIf
      
    Wend
    
    FreeMemory(*Buffer)
  EndIf
  CloseProgramConsole(Prog)
  
EndIf
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5708
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: RunProgramConsole (windows only)

Post by Kwai chang caine »

Super idea INFRATEC and mainly enormous work :shock:
Never i imagine, that communicate with console need an also long and difficult code
Thanks a lot for sharing this very usefull code 8)

Is it very important to have the "MySource.pb" and "FullSource.pb" in #PB_Compiler_FilePath ?
For the compilation apparently not, because the "FullSource.pb" is created in "D:\FullSource.pb" 8)

But when sometime i run in mainfile mode "RunProgramConsole.pbi" all works nice, and the second run i have an IMA in line 278 :|

Code: Select all

*BufferEnd = *RunProgramConsole\BufferRead + MemorySize(*RunProgramConsole\BufferRead) - 1
And all run after it's the same thing
I use v6.21 x86
Last edited by Kwai chang caine on Sun Mar 01, 2026 5:59 pm, edited 1 time in total.
ImageThe happiness is a road...
Not a destination

PureBasic French Forum
infratec
Always Here
Always Here
Posts: 7834
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RunProgramConsole (windows only)

Post by infratec »

Your file can be located where ever you want.
I will add a check for the error.
infratec
Always Here
Always Here
Posts: 7834
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RunProgramConsole (windows only)

Post by infratec »

There is already a check.
So I need a look at your code. I can not reproduce it.
infratec
Always Here
Always Here
Posts: 7834
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RunProgramConsole (windows only)

Post by infratec »

I added a Mutex to avoid conflicts.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5708
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: RunProgramConsole (windows only)

Post by Kwai chang caine »

Like you can't reproduce the problem, i have tested with a little source and that works
But with PB IDE source not, perhaps the path or the source is too long
Then i have move the folder PB source in root D

Code: Select all

Prog = RunProgramConsole(#Compiler$, Chr(34) + "D:\v6.21\PureBasicIDE\PureBasic.pb" + Chr(34) + " /PREPROCESS D:\FullSource.pb", "", #PB_Program_Open|#PB_Program_Read)
And it's the same thing the FullSource is created, but i have the IMA only with PB IDE
I also took the opportunity to clean up all the "PureBasic_CompilationX.exe" files and processes that sometimes remained active.
ImageThe happiness is a road...
Not a destination

PureBasic French Forum
infratec
Always Here
Always Here
Posts: 7834
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RunProgramConsole (windows only)

Post by infratec »

Try the new version with the Mutex inside.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5708
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: RunProgramConsole (windows only)

Post by Kwai chang caine »

You are too much strong...and found the problem :wink:
So normally...with your "Boeing 747 code" 8) we can pilot ALL the console software ? like Putty, Python, etc ... ?
Last edited by Kwai chang caine on Sun Mar 01, 2026 6:59 pm, edited 1 time in total.
ImageThe happiness is a road...
Not a destination

PureBasic French Forum
infratec
Always Here
Always Here
Posts: 7834
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RunProgramConsole (windows only)

Post by infratec »

It should work like the 'normal' RunProgram().
But, at the moment, without the posibility to show the console.

I will try to solve this, but it's a problem of an eventloop.

Btw.: there is no differentiation of out and err, because both of them are written in the console.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5708
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: RunProgramConsole (windows only)

Post by Kwai chang caine »

I have try with a "PureBasic_Compilation0.exe" that open the "PureBasicConsoleDebugger" with txt inside, but not the debug windows

Code: Select all

[Debugger]  Debugger_ExecuteProgram():
[Debugger]  X:\A\B\H\E\PB\v6.21\Codes TESTS\PureBasic_Compilation0.exe
[Debugger]
[Debugger]  X:\A\B\H\E\PB\v6.21
[Debugger]  0

[Debugger Error]  Invalid memory access. (read error at address 0)
[Debugger Error]  File: X:\A\B\H\E\PB\v6.21\Codes outils\DebuggerPilotage.pb (Line: 487)
  Fatal error. Do you want to open the Debugger console? (Yes, No)
yes

==============================================
 PureBasic Console Debugger
==============================================

Type 'help' for command options.
DEBUGGER::
ImageThe happiness is a road...
Not a destination

PureBasic French Forum
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5708
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: RunProgramConsole (windows only)

Post by Kwai chang caine »

I have test another "PureBasic_Compilation0.exe" with very simple loop

Code: Select all

Prog = RunProgramConsole("X:\A\B\H\E\PB\v6.21\Codes TESTS\PureBasic_Compilation0.exe", "", "", #PB_Program_Open|#PB_Program_Read|#PB_Program_Write)

Code: Select all

Repeat
 i + 1
 Debug "Hello KCC " + Str(i)
 Delay(500)
ForEver
And it's the same thing, the console open, with
[Debugger] Hello KCC 2
[Debugger] Hello KCC 3
[Debugger] Hello KCC 4
[Debugger] Hello KCC 5
[Debugger] Hello KCC 6
But not the debug PB window :|
ImageThe happiness is a road...
Not a destination

PureBasic French Forum
infratec
Always Here
Always Here
Posts: 7834
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: RunProgramConsole (windows only)

Post by infratec »

This is normal.

The Debug window is an other window and not the console of the program.

If you want to see that, you need printn() to put the messages into the console.
Post Reply