Page 1 of 1

ReadProgramString() not working with unicode exe?

Posted: Mon Jan 07, 2013 6:09 pm
by Kukulkan
Hi,

I try to get the result of a nslookup call using purebasic RunProgram() function. Here is how I do:

Code: Select all

#LineBreak = #CRLF$

; run an executable and return his console output
Procedure.s runCmd(program.s, params.s, wd.s = "", lf.s = #LineBreak, Hidden.b = #False)
  Protected Compiler.i
  If Hidden.b = #True
    Compiler.i = RunProgram(program.s, params.s, wd.s, #PB_Program_Open|#PB_Program_Read|#PB_Program_Hide)
  Else
    Compiler.i = RunProgram(program.s, params.s, wd.s, #PB_Program_Open|#PB_Program_Read)
  EndIf
  Protected Output.s = ""
  If Compiler.i
    While ProgramRunning(Compiler.i)
      If AvailableProgramOutput(Compiler.i)
        Protected Line.s = ReadProgramString(Compiler.i)
        Output.s + Line.s + lf.s
      EndIf
    Wend
    CloseProgram(Compiler.i) ; Close the connection to the program
  EndIf
  ProcedureReturn Output.s
EndProcedure

Debug runCmd("nslookup", "-q=MX google.com.")
Sadly, using Unicode does not work at all. Is this a bug?

Got it to work like this, but is this really needed?

Code: Select all

; run an executable and return his console output
Procedure.s runCmd(program.s, params.s, wd.s = "", lf.s = #LineBreak, Hidden.b = #False)
  Protected Compiler.i
  If Hidden.b = #True
    Compiler.i = RunProgram(program.s, params.s, wd.s, #PB_Program_Open|#PB_Program_Read|#PB_Program_Hide)
  Else
    Compiler.i = RunProgram(program.s, params.s, wd.s, #PB_Program_Open|#PB_Program_Read)
  EndIf
  Protected Output.s = ""
  If Compiler.i
    While ProgramRunning(Compiler.i)
      Protected LineLength.i = AvailableProgramOutput(Compiler.i)
      If LineLength.i > 0
        Protected *buffer = AllocateMemory(LineLength.i)
        ReadProgramData(Compiler.i, *buffer, LineLength.i)
        Protected Line.s = PeekS(*buffer, LineLength.i, #PB_Ascii)
        FreeMemory(*buffer)
        Output.s + Line.s + lf.s
      EndIf
    Wend
    CloseProgram(Compiler.i) ; Close the connection to the program
  EndIf
  ProcedureReturn Output.s
EndProcedure
Kukulkan

Re: ReadProgramString() not working with unicode exe?

Posted: Mon Jan 07, 2013 6:17 pm
by c4s
This feature request might be related: ReadProgramString() and ReadProgramError() with unicode

Re: ReadProgramString() not working with unicode exe?

Posted: Mon Jan 07, 2013 6:31 pm
by Kukulkan
Yes, this seems to be the same issue. In April 2010 freak stated it will be changed in the future. It is not until now :(

By the way, the somewhat complicated aproach by c4s is not needed (see my first post with second code as solution).

Kukulkan

Re: ReadProgramString() not working with unicode exe?

Posted: Mon Jan 07, 2013 6:59 pm
by c4s
Kukulkan wrote:By the way, the somewhat complicated aproach by c4s is not needed (see my first post with second code as solution).
Really? I didn't test it yet, but does your workaround also work for ReadProgramError() or just ReadProgramString() as I've mentioned in that thread?

Re: ReadProgramString() not working with unicode exe?

Posted: Tue Jan 08, 2013 9:39 am
by Kukulkan
Hi c4s,

sorry, I did noch check all of your functionality. The ReadProgramError() function was not needed by myself. Maybe the effort is needed only there?

Best,

Kukulkan

Re: ReadProgramString() not working with unicode exe?

Posted: Tue Jan 08, 2013 9:41 am
by gnozal
I use this workaround (found on this forum ?) [example on WinXP x86 (french) with ping.exe] :

Code: Select all

Procedure.s ReadProgramStringSafe(ProgramNr) ; ReadProgramString does NOT support Unicode
  ;
  Protected Char.a, ReturnValue.s
  ;
  Static MyReadProgramOffset = 0
  ;
  Shared *MyReadProgramStringBuffer
  ;
  Size = AvailableProgramOutput(ProgramNr)
  If Size > 0
    ;
    Repeat
      ;
      ReadProgramData(ProgramNr, @Char, 1)
      PokeB(*MyReadProgramStringBuffer + MyReadProgramOffset, Char)
      MyReadProgramOffset + 1
      ;
      If AvailableProgramOutput(ProgramNr) = 0 Or MyReadProgramOffset > 255
        Break
      EndIf
      ;
    Until Char = $0A
    ;
    If Char <> $0A
      ReturnValue = ""
    Else
      PokeB(*MyReadProgramStringBuffer + MyReadProgramOffset, 0)
      ReturnValue = PeekS(*MyReadProgramStringBuffer, -1, #PB_Ascii)
      MyReadProgramOffset = 0
      ReturnValue = ReplaceString(ReturnValue, Chr(13), "")
      ReturnValue = ReplaceString(ReturnValue, Chr(10), "")
    EndIf
    ;
  EndIf
  ;
  ProcedureReturn ReturnValue
  ;
EndProcedure
Procedure IsRemotePCAvailable(RemotePC.s)
  ;
  Protected ConnectionOk, ResponseLine, Prog, FindLast, FindFirst, TimeOut.i
  ;
  Shared IsRemotePCAvailable_IP.s
  Shared *MyReadProgramStringBuffer
  ;
  IsRemotePCAvailable_IP = ""
  ;
  *MyReadProgramStringBuffer = AllocateMemory(2048)
  If *MyReadProgramStringBuffer
    ;
    Prog = RunProgram("ping.exe", RemotePC, GetTemporaryDirectory(), #PB_Program_Open | #PB_Program_Read | #PB_Program_Hide)
    If Prog
      TimeOut = ElapsedMilliseconds() + 5000
      Debug "IsRemotePCAvailable : START -> " + RemotePC
      While ProgramRunning(Prog)
        Response$ = ReadProgramStringSafe(Prog)
        If Response$
          Debug "---> " + Response$
          ResponseLine + 1
          If ResponseLine = 1
            IsRemotePCAvailable_IP = RemotePC
            FindFirst = FindString(Response$, "[", 1)
            If FindFirst
              FindLast = FindString(Response$, "]", FindFirst + 1)
              If FindLast
                IsRemotePCAvailable_IP = Mid(Response$, FindFirst + 1, FindLast - FindFirst - 1)
              EndIf
            EndIf
          ElseIf ResponseLine = 2
            If FindString(Response$, "TTL", 1)
              ConnectionOk = #True
            Else
              IsRemotePCAvailable_IP = ""
            EndIf
            KillProgram(Prog)
            Break
          EndIf
        EndIf
        If ElapsedMilliseconds() > TimeOut
          KillProgram(Prog)
          Break
        EndIf
      Wend
      If ResponseLine = 1
        IsRemotePCAvailable_IP = ""
      EndIf
      CloseProgram(Prog)
      Debug "IsRemotePCAvailable : END"
    Else
      ConnectionOk = -1
    EndIf
    ;
    FreeMemory(*MyReadProgramStringBuffer)
    ;
  Else
    ConnectionOk = -1
  EndIf
  ;
  ProcedureReturn ConnectionOk
  ;
EndProcedure

Debug IsRemotePCAvailable("z1501")