Hide Command Prompt Window when RUN Batch file

Hello everyone.

Is there a way to hide the command prompt window while running from application as I have a loop which contains a run command calls a batch file which causes unpleasant flickering.(the case is not limited to batch files but to any command that opens the command prompt window.

Regards

I don’t think you’d regret a Capesoft Oddjob purchase.

The problem that I am using clarion 6.3 which is not compatible with Capesoft Oddjob.

thank you anyway.

Regards

One way to run is calling CreateProcess() and set siStartInfo.wShowWindow = SW_HIDE.

If you want to wait on it to finish, like RUN(File,Wait), you’ll need to monitor the Process Handle piProcInfo.hProcess. The easy way is to monitor GetExitCodeProcess() for STILL_ACTIVE (259) in a timer.

I think it would be easier to call ShellExecuteEx(InfoGroup). The passed Info has a .nShow that can be set to SW_Hide. It can return a Process Handle to monitor for it closing with SEE_MASK_NOCLOSEPROCESS.


There is a CreateProcess() example on GitHub in Devuna KSS where it runs DOS command FindStr. Here’s some of that code…

piProcInfo   LIKE(PROCESS_INFORMATION)
!szCmdline   CSTRING('findstr /s /i /n /p "keystone" "*.inc *.clw"')
siStartInfo  LIKE(STARTUPINFOTYPE)

      ! Create a child process that uses the previously created pipes for STDIN and STDOUT.
      ! Set up members of the PROCESS_INFORMATION structure.
      kcr_ZeroMemory(ADDRESS(piProcInfo), SIZE(PROCESS_INFORMATION))

      ! Set up members of the STARTUPINFO structure.
      ! This structure specifies the STDIN and STDOUT handles for redirection.

      kcr_ZeroMemory(ADDRESS(siStartInfo), SIZE(STARTUPINFOTYPE))
      siStartInfo.cb = SIZE(STARTUPINFOTYPE);
      siStartInfo.hStdError = g_hChildStd_OUT_Wr
      siStartInfo.hStdOutput = g_hChildStd_OUT_Wr
      siStartInfo.hStdInput = g_hChildStd_IN_Rd
      siStartInfo.dwFlags = BOR(siStartInfo.dwFlags,STARTF_USESTDHANDLES)
      siStartInfo.dwFlags = BOR(siStartInfo.dwFlags,STARTF_USESHOWWINDOW)
      siStartInfo.wShowWindow = SW_HIDE  !<=== Hide the Window ****
      ! Create the child process.
      bSuccess = kcr_CreateProcess(0,              |  ! application name
                                   szCmdline,      |  ! command line
                                   0,              |  ! process security attributes
                                   0,              |  ! primary thread security attributes
                                   TRUE,           |  ! handles are inherited
                                   0,              |  ! creation flags
                                   0,              |  ! use parent's environment
                                   0,              |  ! use parent's current directory
                                   siStartInfo,    |  ! STARTUPINFO pointer
                                   piProcInfo)        ! receives PROCESS_INFORMATION

      ! If an error occurs, exit the application.
      IF bSuccess = TRUE
         ! Close handles to the child process and its primary thread.
         ! Some applications might keep these handles to monitor the status
         ! of the child process, for example.
         !kcr_CloseHandle(piProcInfo.hProcess)
         kcr_CloseHandle(piProcInfo.hThread)
      ELSE
         !MESSAGE('CreateProcess')
      END

2 Likes

ShellExecuteEx is perfect. Thanks a lot.

Regards

Please post your code when you get it working.


A simple idea is to make the DOS Window less visible. less obvious. or more like an App Window

  • Screen size small e.g. 60x10 … it can be smaller like 40x3
  • Colored White/Gray or like App. There are new ANSI colors in Win 10. Yu canot make both colors the same.
  • Prompt just space ($S) not X:>
  • Title not “Command Prompt” e.g. “Copying…”
MODE CON COLS=60 LINES=10
COLOR  87
PROMPT $S
TITLE Copying...

image

You could run the Batch file Minimized making it less visible. The way I know how to do that is with START /min My.BAT. That’s not going to work with RUN(,wait). There may be other ways for a BAT to hide or minimize.

1 Like

That was my approach before but in my application every command has an update on the screen which I am stating the loop from, so I need an update for each command instantly. Before when I used to create a batch file and run it, I had to add an additional line after the command to send the result after each execution to an “ini” file from the batch file and read the results from clarion with a timer or such, but still there was a delay sometimes and I felt it was a poor workaround.

Regarding the code I will post soon because I am still testing it to make sure that it is not skipping any data because I am testing around 300,000 command and each command takes 2 to 3 seconds to complete. I faced some issues and fixed them but it seems so far so good.

Regards

300000 RUNs? Excellent solution.

just so you know, if you look at

https://www.capesoft.com/accessories/DownloadPatchesArchive.htm

you can find old versions of Capesoft stuff including last C6 builds

cheers

Nice to know.

Thank you

Actually I have an application that applies a sort of converting files from type to another using a third party line command application. The application used to be very noisy while running but now after the command window is not showing ;you don’t feel that there is a third party application in running in the background.

I see this is well underway, but I have a ShellExecuteExA example (with options to hide window and wait for process to end) if you need it.

Helo Julian,
And example would be much appreciated. :pleading_face:

Here is the example from my ToolBox extract whatever you need/want.

I call batch files like this …

jhTools.Run('cmd.exe','/c the_batch_filename.cmd')

When the last parameter inRunAs=True, admin rights will be requested.

jhTools.Run             PROCEDURE(STRING inFilename,<STRING inParams>,<STRING inStartPath>,<BYTE inWait>,<BYTE inHide>,<BYTE inRunAs>)

procName                   EQUATE('jhTools.Run')

ShellExecInfo              GROUP
cbSize                        ULONG
fMask                         ULONG
hwnd                          ULONG
lpVerb                        LONG
lpFile                        LONG
lpParameters                  LONG
lpDirectory                   LONG
nShow                         LONG
hInstApp                      ULONG
lpIDList                      ULONG
lpClass                       LONG
hkeyClass                     ULONG
dwHotKey                      ULONG
lpUnion                       LONG
hProcess                      ULONG
                           END

szOperation                CSTRING(12)
szFilename                 CSTRING(256)
szParams                   CSTRING(256)
szPath                     CSTRING(256)
dwResult                   LONG

hWND                       LONG
dwProcessID                LONG

   CODE
      !-- Check the Filename
      IF ~inFilename 
         RETURN(FALSE)
      .
      
      IF inRunAs
         szOperation = 'runas'
      ELSE
         szOperation = 'open'
      .
      
      szFilename = CLIP(inFilename)

      !-- Wrap a file name containing a space with double quotes if necessary ..
      !--
      IF INSTRING(' ',szFilename,1,1) AND szFilename[1] ~= '"'
         szFilename = '"' & szFilename & '"'
      .

      !-- StartIn Path ..
      IF inStartPath
         szPath = CLIP(inStartPath)
      ELSE
         szPath = ''
      .
      
      szParams = CLIP(inParams)

      
      CLEAR(ShellExecInfo)
      ShellExecInfo.cbSize = SIZE(ShellExecInfo)
      ShellExecInfo.fMask = 040H  ! SEE_MASK_NOCLOSEPROCESS (0x00000040) 
      ShellExecInfo.hwnd = 0
      ShellExecInfo.lpVerb = ADDRESS(szOperation)      
      ShellExecInfo.lpFile = ADDRESS(szFilename)    
      ShellExecInfo.lpParameters = ADDRESS(szParams)   
      ShellExecInfo.lpDirectory = ADDRESS(szPath)

      IF inHide
         ShellExecInfo.nShow = 0
      ELSE
         ShellExecInfo.nShow = 10
      .
      

      !-- ShellExecuteExA ..
      !-- Returns TRUE if successful; otherwise, FALSE. Call GetLastError for extended error information.
      !-- If the function fails, it returns an error value that indicates the cause of the failure. 
      !-- The return value is cast as an HINSTANCE for backward compatibility with 16-bit Windows applications. 
      !-- It is not a true HINSTANCE, however. It can be cast only to an int and compared to either 32 or it's error codes.

      IF ShellExecuteExA(ADDRESS(ShellExecInfo)) = True
                  
         !MESSAGE('ShellExecute SEInfo.hProcess = ' & SEInfo.hProcess & |
         !   '|inWait = ' & inWait,procName)
         
         IF ShellExecInfo.hProcess
            !-- Do we need to wait for this process to finish ?
            IF inWait = TRUE
               
               dwResult = WaitForSingleObject(ShellExecInfo.hProcess, -1)
            .
            
            !-- Close the Process Handle once finished
            CloseHandle(ShellExecInfo.hProcess)
            
            RETURN(TRUE)
         .

      .
      
      RETURN(False)

I use these prototypes …

ShellExecuteExA(LONG lpShellExecuteInfoA),LONG,PASCAL,NAME('ShellExecuteExA')
WaitForSingleObject(LONG hHandle,ULONG dwMilliseconds),LONG,PASCAL,NAME('WaitForSingleObject')
CloseHandle( Long hObject ),Long,Pascal,Proc,Name('CloseHandle')
2 Likes

300000 executions x 3 sec / 60 sec / 60 sec/ 24 hours = 10.42 days, Oh my God!!

Did I make the account correctly?

Yes your calculation is correct but in my case some commands take less than a second and from my logs each 100,000 takes around 6 hours, so I ran 3 processes at the same time so it took the whole job around 6 hours.

regards

Do you have this example in .clw file, as including it as it is i get constantly some errors. Thanks a lot…

Have you …

a) removed the jhTools. prefix from the procedure name above
b) specified the required prototypes in your map ?

I’ve created an example based on the code posted by @Julian.

It can be found in this gist here

Mark

a) yes it was complaning when I tryed to name the procedure, so I left the dot out
b) yes, when doing that I’ve encountered some problem, like the indistinguishable error because it seams I’ve alredy have the winapi.inc there with same procedure names. Tried to avoid that with renaming procedures but that gave me some other problems.
Let me check @Mark_Sarson example, and try to implement it in my app. I’ll come back with additonal comments if needed. Thanks