Running an outside process within PureBasic

Just starting out? Need help? Post your questions and find answers here.
gonpublic2k
User
User
Posts: 40
Joined: Mon Oct 14, 2019 1:38 am

Running an outside process within PureBasic

Post by gonpublic2k »

Hi to all,

I'm new to this forum and to PureBasic. I was wondering it anyone has done a program with PureBasic where you run a CMD windows issuing a command, for example, ROBOCOPY - and display the output within a form in PureBasic. I'm trying to create a backup utility but want to use ROBOCOPY for the copying process but show it inside a form in PureBasic. I don't know if this is even possible. Share your ideas.

Thanks!
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Running an outside process within PureBasic

Post by skywalk »

Yes, I use robocopy for many backups.
Pipe the log to a file and then open it and display in PB.
RunProgram(mybackup.bat) or set robocopy as a service that runs at your desired frequency.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
BarryG
Addict
Addict
Posts: 3294
Joined: Thu Apr 18, 2019 8:17 am

Re: Running an outside process within PureBasic

Post by BarryG »

Hi gonpublic2k! Here's something to get you started:

Code: Select all

If OpenWindow(0, 320, 320, 422, 250, "DOS Output", #PB_Window_SystemMenu)
  
  EditorGadget(0, 8, 8, 406, 233)
  
  comspec$=GetEnvironmentVariable("comspec")
  
  DOS = RunProgram(comspec$, "/c dir c:", "", #PB_Program_Hide | #PB_Program_Open | #PB_Program_Read)
  
  If DOS
    Output$ = ""
    While ProgramRunning(DOS)
      If AvailableProgramOutput(DOS)
        Output$ + ReadProgramString(DOS) + Chr(13)
      EndIf
    Wend
    CloseProgram(DOS)
    AddGadgetItem(0, -1, Output$)
  EndIf
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  
EndIf
gonpublic2k
User
User
Posts: 40
Joined: Mon Oct 14, 2019 1:38 am

Re: Running an outside process within PureBasic

Post by gonpublic2k »

BarryG wrote:Hi gonpublic2k! Here's something to get you started:

Code: Select all

If OpenWindow(0, 320, 320, 422, 250, "DOS Output", #PB_Window_SystemMenu)
  
  EditorGadget(0, 8, 8, 406, 233)
  
  comspec$=GetEnvironmentVariable("comspec")
  
  DOS = RunProgram(comspec$, "/c dir c:", "", #PB_Program_Hide | #PB_Program_Open | #PB_Program_Read)
  
  If DOS
    Output$ = ""
    While ProgramRunning(DOS)
      If AvailableProgramOutput(DOS)
        Output$ + ReadProgramString(DOS) + Chr(13)
      EndIf
    Wend
    CloseProgram(DOS)
    AddGadgetItem(0, -1, Output$)
  EndIf
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  
EndIf
Thank you both, Skywalk and BarryG - I will try this code and see what I can come up with. Appreciated!
gonpublic2k
User
User
Posts: 40
Joined: Mon Oct 14, 2019 1:38 am

Re: Running an outside process within PureBasic

Post by gonpublic2k »

skywalk wrote:Yes, I use robocopy for many backups.
Pipe the log to a file and then open it and display in PB.
RunProgram(mybackup.bat) or set robocopy as a service that runs at your desired frequency.
Could you share a sample source code please! I want to have a user map a drive, then use robocopy with the following switches:

S /E /Z /ZB /R:5 /W:5 /TBD /NP /V /MT:32

showing the progress in a PB window.

Thanks!
Marc56us
Addict
Addict
Posts: 1477
Joined: Sat Feb 08, 2014 3:26 pm

Re: Running an outside process within PureBasic

Post by Marc56us »

Could you share a sample source code please!

Code: Select all

; Robocopy with output in a window
; Based on code from BarryG - https://www.purebasic.fr/english/viewtopic.php?p=543167#p543167

Source$         = "C:\Data_Source"
Destination$    = "C:\Data_SAV"

OpenWindow(0, 320, 320, 600, 300, "DOS Output", #PB_Window_SystemMenu)
SetGadgetFont(#PB_Default, FontID(LoadFont(#PB_Any, "Consolas", 10)))
EditorGadget(0, 5, 5, WindowWidth(0)-10, WindowHeight(0)-10)

; RoboCopy.exe is on %WinDir% so in PATH so no need full path

DOS = RunProgram("RoboCopy.exe", "/s " + Source$ + " " + Destination$, "", #PB_Program_Hide | #PB_Program_Open | #PB_Program_Read)

If DOS
    While ProgramRunning(DOS)
        If AvailableProgramOutput(DOS)
            AddGadgetItem(0, -1,  ReadProgramString(DOS))
        EndIf
    Wend
    CloseProgram(DOS)
EndIf

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Add your other parameters after
+ Destination + " " + ...

You will not see anything in real time because Robocopy is very, very, very fast

You will not see the % displayed in the same place, because this system captures line by line while RoboCopy repositions the cursor using console functions

:wink:
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Running an outside process within PureBasic

Post by skywalk »

I do not use AvailableProgramOutput() for this function as my backups are automated.
I append this switch to each robocopy command string: /LOG:c:\myapp\mybackup.log
And later review their results for any errors.

Code: Select all

-------------------------------------------------------------------------------
   ROBOCOPY     ::     Robust File Copy for Windows                              
-------------------------------------------------------------------------------

  Started : Saturday, March 2, 2019 4:38:51 PM
   Source : d:\Music\
     Dest : e:\Music\

    Files : *.*
	    
  Options : *.* /S /E /DCOPY:DA /COPY:DAT /PURGE /NP /R:2 /W:30 

------------------------------------------------------------------------------
blah
blah 
blah
------------------------------------------------------------------------------

               Total    Copied   Skipped  Mismatch    FAILED    Extras
    Dirs :       373         0       373         0         0        10
   Files :      3223        10      3213         0         0       126
   Bytes :  20.899 g   132.1 k  20.899 g         0         0  605.41 m
   Times :   0:00:01   0:00:00                       0:00:00   0:00:00


   Speed :             4509666 Bytes/sec.
   Speed :             258.045 MegaBytes/min.
   Ended : Saturday, March 2, 2019 4:38:52 PM
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
ZX80
Enthusiast
Enthusiast
Posts: 330
Joined: Mon Dec 12, 2016 1:37 pm

Re: Running an outside process within PureBasic

Post by ZX80 »

gonpublic2k

Hi, this is my attempt (very simple logic).

Code: Select all

Procedure.q ListFiles(directory.s, directoryid.l) ;written by Rings
  If Right(directory,1)<>"\":directory+"\":EndIf
  If ExamineDirectory(directoryid,directory,"*.*")
    dirid=NextDirectoryEntry(directoryid)
    While dirid
      dirtype = DirectoryEntryType(directoryid)
      Select dirtype
        Case #PB_DirectoryEntry_File
          file.s=directory + DirectoryEntryName(directoryid)
          FS.q=FileSize(File)
          FZ.q + FS
        Case #PB_DirectoryEntry_Directory
          If DirectoryEntryName(directoryid)<>"." And DirectoryEntryName(directoryid)<>".."
            FZ  + ListFiles(directory+DirectoryEntryName(directoryid)+"\",directoryid+1)
          EndIf
      EndSelect
      dirid=NextDirectoryEntry(directoryid)
    Wend
    FinishDirectory(directoryid)
  EndIf
  ProcedureReturn FZ
EndProcedure

Procedure.l IntPerc(current.q, all.q)
  ProcedureReturn ((current)*1000/(all)+5)/10
EndProcedure


Source$         = "d:\-----2017\_MUS\"
Destination$    = "c:\888888_\"

;get folder size
_original.q = Listfiles(Source$, 1)
_copy.q = 0

If OpenWindow(0, 0, 0, 500, 100, "DOS Output", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  TextGadget(0, 10, 20, 480, 30, "0 %", #PB_Text_Center)
  ProgressBarGadget(1, 10, 50, 480, 30, 0, 100, #PB_ProgressBar_Smooth)
  
  DOS = RunProgram("RoboCopy.exe", "/s " + Source$ + " " + Destination$, "", #PB_Program_Open); | #PB_Program_Hide)
  If DOS = 0
    CloseWindow(0)
    MessageRequester("Error", "Can't launch robocopy")
    End
  EndIf
  
  StickyWindow(0, 1)
  AddWindowTimer(0, 1, 500)
  process.a = 1
  
  
  Repeat
    Event.l = WaitWindowEvent()
    If Event = #PB_Event_CloseWindow
      If process
        RemoveWindowTimer(0, 1)
        KillProgram(DOS)
      EndIf
      Break
    ElseIf Event = #PB_Event_Timer
      Timer = EventTimer()
      If Timer = 1
        If _copy = _original
          If ProgramRunning(DOS) = 0
            process = 0
            RemoveWindowTimer(0, 1)
            SetGadgetText(0, "100 %  - Complete!")
          EndIf
        Else
          _copy = Listfiles(Destination$, 2)
          percentage = IntPerc(_copy, _original)
          SetGadgetText(0, Str(percentage) + " %")
          SetGadgetState(1, percentage)
        EndIf
      EndIf
    EndIf
  ForEver
Else
  MessageRequester("Error", "Can't open main window  :(")
EndIf
Good luck!
gonpublic2k
User
User
Posts: 40
Joined: Mon Oct 14, 2019 1:38 am

Re: Running an outside process within PureBasic

Post by gonpublic2k »

Thank you all for your kind answers and sharing of code. I will sure take a look at all these suggestions and try to come up with
something useful for my project. I'm a newbie at PB but I've been programming with Delphi for a little bit now and I think I can
learn my way around it. Appreciate all your input!

As soon as I get something put together I'd share my code for others to see and hopefully help someone else.

:)
gonpublic2k
User
User
Posts: 40
Joined: Mon Oct 14, 2019 1:38 am

Re: Running an outside process within PureBasic

Post by gonpublic2k »

Hello... one thing I noticed is when trying to create this small utility , PB doesn't accept variable paths for reference? Do they have to be absolute paths? Let me
explain ..
My code is something like :

Code: Select all

Source$                  =  "%USERPROFILE%\Pictures"
Destination$            =  "\\consejo\APPS\Backup"

 ....
....
....
DOS = RunProgram("Robocopy.exe", "/s " + Source$ + " " + Destination$, "", #PB_Program_Open); | #PB_Program_Hide)

etc...
This gives me an error message that ROBOCOPY cannot find the source specified. Any ideas?
Marc56us
Addict
Addict
Posts: 1477
Joined: Sat Feb 08, 2014 3:26 pm

Re: Running an outside process within PureBasic

Post by Marc56us »

Picture in not always picture directory.
Use GetUserDirectory(#PB_Directory_Pictures) instead.

Check if file or dir exist with filesize() function

Code: Select all

Source$ = "%USERPROFILE%\Pictures"

Debug FileSize(Source$)


; F1: FileSize()
; 
; Returns the size of the file in bytes, Or one of the following values:
; 
;   -1: File Not found.
;   -2: File is a directory.

; PB >= 5.60 uses GetUserDirectory
Source$ = GetUserDirectory(#PB_Directory_Pictures)

Debug FileSize(Source$)
gonpublic2k
User
User
Posts: 40
Joined: Mon Oct 14, 2019 1:38 am

Re: Running an outside process within PureBasic

Post by gonpublic2k »

Marc56us wrote:Picture in not always picture directory.
Use GetUserDirectory(#PB_Directory_Pictures) instead.

Check if file or dir exist with filesize() function

Code: Select all

Source$ = "%USERPROFILE%\Pictures"

Debug FileSize(Source$)


; F1: FileSize()
; 
; Returns the size of the file in bytes, Or one of the following values:
; 
;   -1: File Not found.
;   -2: File is a directory.

; PB >= 5.60 uses GetUserDirectory
Source$ = GetUserDirectory(#PB_Directory_Pictures)

Debug FileSize(Source$)
Mmmm.... very interesting. Thanks so much, I will try this code and post back with results!
BarryG
Addict
Addict
Posts: 3294
Joined: Thu Apr 18, 2019 8:17 am

Re: Running an outside process within PureBasic

Post by BarryG »

An alternative to GetUserDirectory() is to expand the environment variables. This saves you the hassle of doing multiple GetUserDirectory() calls for every folder that you need to access (documents, downloads, music, pictures, videos, etc).

Code: Select all

Procedure.s ExpandEnvString(old$)
  new$=Space(999)
  ExpandEnvironmentStrings_(old$,new$,990)
  ProcedureReturn new$
EndProcedure

Debug ExpandEnvString("%USERPROFILE%\Pictures")
gonpublic2k
User
User
Posts: 40
Joined: Mon Oct 14, 2019 1:38 am

Re: Running an outside process within PureBasic

Post by gonpublic2k »

BarryG wrote:An alternative to GetUserDirectory() is to expand the environment variables. This saves you the hassle of doing multiple GetUserDirectory() calls for every folder that you need to access (documents, downloads, music, pictures, videos, etc).

Code: Select all

Procedure.s ExpandEnvString(old$)
  new$=Space(999)
  ExpandEnvironmentStrings_(old$,new$,990)
  ProcedureReturn new$
EndProcedure

Debug ExpandEnvString("%USERPROFILE%\Pictures")
Great point BarryG - I was wondering if I was going to have to do those multiple calls. Excellent, this saves me a lot of trouble :D
Post Reply