PYTHON communicate with PIPES [Resolved]

Just starting out? Need help? Post your questions and find answers here.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

PYTHON communicate with PIPES [Resolved]

Post by Kwai chang caine »

Hello at all :D

With a code i have found (don't know the author :oops:) and modified
I try to sending a commande to PYTHON using PIPES without success
If someone see the problem

Code: Select all

Enumeration
 #Form0
 #EditorCommande
 #StringCommande
 #Bouton
EndEnumeration

Global pi.PROCESS_INFORMATION
Global hWritePipe.l,hReadPipe.l,PipeMem.l,PipeString.s
Global compx.l,last.s

PipeMem = AllocateMemory(10000)

Procedure GetOutPut()
 
 bytesread.l = 0
 o.l = 1023
 r.l = PeekNamedPipe_(hreadPipe,0,0,0,@bytesread,0)
 
 If bytesread > 0
 
  o.l = ReadFile_(hReadPipe,PipeMem,1023,@bytesread,0)
 
  For f.l=0 To bytesread
 
   t.b = PeekB(PipeMem+f)
 
   If t<>0
 
    u.b=PeekB(PipeMem+f+1)
    v.b=PeekB(PipeMem+f+1)
 
    If t=13
 
     Print(PipeString)
     PipeString=""
 
     If u=10 
      f+1
     EndIf                
 
    Else
 
     If t>31 And t<128 
      PipeString + Chr(t)
     EndIf
 
    EndIf
    
   EndIf
     
 
  Next
     
  AddGadgetItem(#EditorCommande, -1, PipeString)
  PipeString = ""
 
 Else
 
  Delay(10)
 
 EndIf
 
EndProcedure

Procedure RunCommand(cmd.s)
 
 path.s=GetPathPart(cmd)
 sa.SECURITY_ATTRIBUTES
 sa\nLength=SizeOf(SECURITY_ATTRIBUTES)
 sa\bInheritHandle=1
 sa\lpSecurityDescriptor=0
 
 xx.l=CreatePipe_(@hReadPipe,@hWritePipe,@sa,1)
 
 si.STARTUPINFO
 si\cb=SizeOf(STARTUPINFO)
 si\dwFlags=#STARTF_USESTDHANDLES|#STARTF_USESHOWWINDOW
 si\hStdOutput=hWritePipe
 si\hStdError=hWritePipe
 Result = CreateProcess_(0,cmd,@sa,@sa,1,#CREATE_NO_WINDOW,0,path,@si,@pi)
 ProcedureReturn Result
 
EndProcedure

Procedure WaitProcess(*value)
 
 exitcode.l=259
 
 While exitcode=259
 
  t=GetExitCodeProcess_(pi\hProcess,@exitcode)
 
  If exitcode<>259
   ; We've Finished
  Else
   GetOutPut()
  EndIf
  
 Wend
 
 CloseHandle_(hWritePipe)
 
EndProcedure

PipeString=""

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

If RunCommand("C:\Python37\python.exe")
 
 CreateThread(@WaitProcess(),0)
 
 Repeat  
  
  Evenement = WaitWindowEvent()
  EvenementGadget = EventGadget()
  EvenementType = EventType()
  
  If Evenement = #PB_Event_Gadget
   
   Select EvenementGadget
     
    Case #Bouton
    
    Commande$ = GetGadgetText(#StringCommande) + #CRLF$
    Define Writen.l
    WriteFile_(hWritePipe, Commande$, Len(Commande$), @Writen, #Null)
    Debug writen
    FlushFileBuffers_(hWritePipe)
   
   EndSelect
   
  EndIf
  
 Until Evenement = #PB_Event_CloseWindow
 
Else
 
 Debug GetLastError_()
 
EndIf

Last edited by Kwai chang caine on Sun Jan 16, 2022 6:19 pm, edited 1 time in total.
ImageThe happiness is a road...
Not a destination
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: PYTHON communicate with PIPES

Post by infratec »

I can not test it, because I don't use python, but ...

Code: Select all

WriteFile_(hWritePipe, Commande$, Len(Commande$), @Writen, #Null)
looks totally wrong to me.

If you really want to send unicode it should look like:

Code: Select all

WriteFile_(hWritePipe, @Commande$, StringByteLength(Commande$), @Writen, #Null)
Does python need unicode?

But if you use stdin and stdout, why you don't use the 'normal' PB way ?
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: PYTHON communicate with PIPES

Post by infratec »

Ok, it was tricky, but ...

Code: Select all

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 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
    
    If *Parameter\ProgramWorkingDirectory$ = ""
      *Parameter\ProgramWorkingDirectory$ = GetPathPart(*Parameter\Program$)
    EndIf
    
    *Parameter\ProgramID = RunProgram(*Parameter\Program$, *Parameter\ProgramParameter$, *Parameter\ProgramWorkingDirectory$, #PB_Program_Open|#PB_Program_Read|#PB_Program_Write|#PB_Program_Error|*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
            Debug *Parameter\StdOut$
            PostEvent(#ExternalProgram_Event_StdOut)
            WaitSemaphore(*Parameter\Semaphore)
          EndIf
        Wend
        
;         Debug 11
;         Error$ = ReadProgramError(*Parameter\ProgramID, StringMode)
;         Debug 111
;         If Len(Error$)
;           Debug Error$
;           ShowMemoryViewer(@Error$, StringByteLength(Error$, #PB_Unicode))
;           *Parameter\StdErr$ = Error$
;           PostEvent(#ExternalProgram_Event_Error)
;           WaitSemaphore(*Parameter\Semaphore)
;           Debug "Err End"
;         EndIf
        
        If TryLockMutex(*Parameter\Mutex)
          ;Debug 2
          If Len(*Parameter\StdIn$)
            WriteLen = PokeS(*Buffer, *Parameter\StdIn$, -1, StringMode|#PB_String_NoZero)
            *Parameter\StdIn$ = ""
            UnlockMutex(*Parameter\Mutex)
            SignalSemaphore(*Parameter\Semaphore)
            WriteLen = WriteProgramData(*Parameter\ProgramID, *Buffer, WriteLen)
            Debug WriteLen
            Delay(50)
          Else
            UnlockMutex(*Parameter\Mutex)
          EndIf
          
        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.i Event, Exit, i, j, LastLine
  Define Help$
  Define ThreadParameter.ExternalProgram_ParameterStructure
  NewList CommandList$()
  
  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, "")
  ButtonGadget(#ButtonGadget, 200, 460, 200, 30, "Send to console")
  
  ThreadParameter\Program$ = "cmd.exe"
  ThreadParameter\ProgramParameter$ = "/C " + #DQUOTE$ + "c:\Program Files\Python310\python.exe" + #DQUOTE$ + " -i 2>&1"
  ThreadParameter\ProgramReadWriteMode = #PB_Program_UTF8
  ThreadParameter\ProgramExit$ = "exit()"
  ;ThreadParameter\CodePageConverter = @ExternalProgram_CP850ToUnicode()
  ThreadParameter\Semaphore = CreateSemaphore()
  ThreadParameter\Mutex = CreateMutex()
  ThreadParameter\Thread = CreateThread(@ExternalProgram_Thread(), @ThreadParameter)
    
  ResetList(CommandList$())
  
  Repeat
    
    Event = WaitWindowEvent()
    
    Select Event
      Case #ExternalProgram_Event_StdOut
        Help$ = ThreadParameter\StdOut$
        SignalSemaphore(ThreadParameter\Semaphore)
        
        If Right(Help$, 1) = ">"
          If NextElement(CommandList$())
            LockMutex(ThreadParameter\Mutex)
            ThreadParameter\StdIn$ = CommandList$()
            UnlockMutex(ThreadParameter\Mutex)
            WaitSemaphore(ThreadParameter\Semaphore)
          EndIf
        EndIf
        
        Help$ = RemoveString(Help$, #CR$)
        Help$ = RTrim(Help$, #LF$)
        
        i = CountString(Help$, #LF$)
        For j = 0 To i
          If j = 0
            LastLine = CountGadgetItems(#EditorGadget) - 1
            SetGadgetItemText(#EditorGadget, LastLine, GetGadgetItemText(#EditorGadget, LastLine) + StringField(Help$, j + 1, #LF$))
          Else
            AddGadgetItem(#EditorGadget, -1, StringField(Help$, j + 1, #LF$))
          EndIf
        Next j
        
      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) + #CRLF$
            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
The main problem was, that ReadProgramError() hangs also until a CRLF is at the end.
python uses stderr as output.
So I need to redirect stderr to stdout.
Now I can use the 'normal' AvailableProgramOutput()
Also the -i parameter for python was needed to make the output 'unbuffered'.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: PYTHON communicate with PIPES

Post by Kwai chang caine »

A thousand thanks INFRATEC that works perfectly !!! 8)
Master wrote:ython uses stderr as output.
So I need to redirect stderr to stdout.
You are too strong :shock:
I have searched all the afternoon, but how do you expect me to find this ? :oops:
Stupidly I thought that all consoles worked with the same principle :cry:
Master of the keys wrote:But if you use stdin and stdout, why you don't use the 'normal' PB way ?
I have always been passionate about communication between processes, the piloting of one application by another, for more than 20 years I have been following all the subjects concerning this subject and try also to do it myself with more or less success :oops:
And when I saw that the stdin/stdout PYTHON didn't work and that you had created a direct access to the PYTHON DLL, I said to myself that it was because talk to the PYTHON executable to be surely impossible
So I continued my research and came across this awesome code, which at least gave me half of the goal I wanted to achieve. :shock:
Anyway, the more different methods of inter-process communication I have...the happier I am :mrgreen:

Again thanks master 8) ....for your 22 000e help for me :oops:
Again a jewel i keep in my PB safe :wink:
Have the best good day of the world 8)
ImageThe happiness is a road...
Not a destination
Post Reply