Page 1 of 1

RunProgram Java tool multiple times in the same instance

Posted: Sat Sep 05, 2020 6:02 pm
by THCM
Hi, I'm running a Java tool to convert data multiple times from my Purebasic app. When I run the Java tool from the windows shell only the first run is quite slow (more than 10 seconds). All following runs in the same shell window are a lot faster, running nearly instant. Running the Java tool from PureBasic using RunProgam every run is slow. There seems to be some caching in the background from Windows or Java which gets lost when using RunProgram. Any ideas how to overcome this?

Code: Select all

JavaParameter.s = "-cp " + Chr(34) + GetCurrentDirectory() + "javamod.jar" + Chr(34) + " de.quippy.javamod.converter.Converter " + Chr(34) + ModFile.s + Chr(34) + " -o:" + Chr(34) + WorkingDir.s + "thc_channel" + Chr(34)
Java = RunProgram("Java.exe", JavaParameter.s, GetCurrentDirectory(), #PB_Program_Open|#PB_Program_Read|#PB_Program_Hide)

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Sep 05, 2020 6:06 pm
by DarkDragon
Simple solution: you could create a cmd.exe process, keep it always running in the background and run the java application by writing the corresponding command into the command prompt.

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Sep 05, 2020 6:16 pm
by THCM
I thought about using OpenConsole, but I wasn't sure if this works from a windows gui app. Your suggestion would be using RunProgram with cmd.exe and sending my commands using WriteProgramStringN?

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Sep 05, 2020 6:32 pm
by #NULL
Did you try if multiple calls of RunProgram within one instance of your PB program makes any difference? I don't know but I would check that first.

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Sep 05, 2020 6:35 pm
by THCM
The program is open the whole time.

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Sep 05, 2020 7:20 pm
by DarkDragon
THCM wrote:I thought about using OpenConsole, but I wasn't sure if this works from a windows gui app. Your suggestion would be using RunProgram with cmd.exe and sending my commands using WriteProgramStringN?
Exactly that's what I meant.

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Sep 05, 2020 8:58 pm
by oreopa
Nice to see THCM using PB! And kinda hoping this is C64 related ;)

MDG forever! <3 *tips hat*

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Sep 05, 2020 9:45 pm
by THCM
oreopa wrote:Nice to see THCM using PB! And kinda hoping this is C64 related ;)

MDG forever! <3 *tips hat*
Yes, I‘m using Purebasic for more than 17 years now, but only from time to time and mainly for small tools generating c64 demostuff. Still WIP is my THCMod Protracker Converter written in Purebasic and I‘ve converted my game Orb to Purebasic, but I have to adapt the code from PB 3.93 to the current build. Thx for the help!

Re: RunProgram Java tool multiple times in the same instance

Posted: Tue Sep 15, 2020 3:49 pm
by THCM
I did some tests and can't get it work as I wanted:

Code: Select all

If OpenWindow(0, 320, 320, 422, 250, "DOS-Output", #PB_Window_SystemMenu)
 
  EditorGadget(0, 8, 8, 406, 233)
 
    DOS = RunProgram(GetEnvironmentVariable("comspec"), "/k", "", #PB_Program_Open | #PB_Program_Read | #PB_Program_Write )
 
  If DOS
    Output.s = ""
    
       WriteProgramStringN(DOS,"dir c:")
    
      While  AvailableProgramOutput(DOS)
        Output.s + ReadProgramString(DOS) + Chr(13)
      Wend
      
    CloseProgram(DOS)
    AddGadgetItem(0, -1, Output.s)
  EndIf
 
  Repeat 
  Until WaitWindowEvent() = #PB_Event_CloseWindow
 
It looks like WriteProgramStringN doesn't exectute the dir command in the cmd window. It works when I directly send the dir command:

Code: Select all

DOS = RunProgram(GetEnvironmentVariable("comspec"), "dir c: /k", "", #PB_Program_Open | #PB_Program_Read | #PB_Program_Write )
 
But I need to send a command more than once. What am I doing wrong?

Re: RunProgram Java tool multiple times in the same instance

Posted: Thu Sep 17, 2020 9:28 am
by ZX80
Hi, THCM.

Hope this wonderful code will help you (by JHPJHP):

Code: Select all

#SystemProcessInformation = 5

Structure UNICODE_STRING Align #PB_Structure_AlignC
  Length.w
  MaximumLength.w
  Buffer.i
EndStructure

Structure VM_COUNTERS
  PeakVirtualSize.l
  VirtualSize.l
  PageFaultCount.l
  PeakWorkingSetSize.l
  WorkingSetSize.l
  QuotaPeakPagedPoolUsage.l
  QuotaPagedPoolUsage.l
  QuotaPeakNonPagedPoolUsage.l
  QuotaNonPagedPoolUsage.l
  PagefileUsage.l
  PeakPagefileUsage.l
EndStructure

Structure IO_COUNTERS
  ReadOperationCount.LARGE_INTEGER
  WriteOperationCount.LARGE_INTEGER
  OtherOperationCount.LARGE_INTEGER
  ReadTransferCount.LARGE_INTEGER
  WriteTransferCount.LARGE_INTEGER
  OtherTransferCount.LARGE_INTEGER
EndStructure

Structure SYSTEM_THREAD
  KernelTime.LARGE_INTEGER
  UserTime.LARGE_INTEGER
  CreateTime.LARGE_INTEGER
  WaitTime.l
  StartAddress.l
  UniqueProcess.l
  UniqueThread.l
  Priority.l
  BasePriority.l
  ContextSwitchCount.l
  State.l
  WaitReason.l
  Reserved1.l
EndStructure

Structure SYSTEM_PROCESS_INFORMATION
  NextEntryOffset.l
  NumberOfThreads.l
  Reserved1.LARGE_INTEGER[3]
  CreateTime.LARGE_INTEGER
  UserTime.LARGE_INTEGER
  KernelTime.LARGE_INTEGER
  ModuleName.UNICODE_STRING
  BasePriority.i
  ProcessID.l
  InheritedFromProcessId.l
  HandleCount.l
  Reserved2.l[2]
  VirtualMemoryCounters.VM_COUNTERS
  PrivatePageCount.l
  IOCounters.IO_COUNTERS
  ThreadInfo.SYSTEM_THREAD[0]
EndStructure

Prototype protoAttachConsole(dwProcessId)

Procedure cmdGetProcessId(ModuleName.s)
  *spi.SYSTEM_PROCESS_INFORMATION
  *spi = AllocateMemory(1024 * 1024)
  NtQuerySystemInformation_(#SystemProcessInformation, *spi, MemorySize(*spi), #Null)
  *spi\ModuleName\Buffer = AllocateMemory(#MAX_PATH)

  While *spi\NextEntryOffset
    If LCase(PeekS(*spi\ModuleName\Buffer, *spi\ModuleName\Length, #PB_Unicode)) = ModuleName
      dwProcessId = *spi\ProcessID : Break
    Else
      *spi + *spi\NextEntryOffset
    EndIf
  Wend
  ProcedureReturn dwProcessId
EndProcedure

Procedure.l cmdOpenConsole(dwProcessId)
  Protected AttachConsole.protoAttachConsole

  kernel32 = OpenLibrary(#PB_Any, "kernel32.dll")

  If IsLibrary(kernel32)
    AttachConsole = GetFunction(kernel32, "AttachConsole")

    If AttachConsole(dwProcessId) : hStdInput.l = GetStdHandle_(#STD_INPUT_HANDLE) : EndIf

    CloseLibrary(kernel32)
  EndIf
  ProcedureReturn hStdInput
EndProcedure

Procedure cmdAddAlias(Source.s, Target.s)
  ProcedureReturn AddConsoleAlias_(Source, Target, "cmd.exe")
EndProcedure

Procedure cmdRunScript(hStdInput.l, ScriptText.s, RunAndWait = #False)
  ScriptText + Chr(13)
  nLength = Len(ScriptText) + 1

  If nLength > 1
    Dim lpBuffer.INPUT_RECORD(nLength)

    For rtnCount = 0 To nLength - 2
      ascKey = Asc(Mid(ScriptText, rtnCount + 1, 1))
      vkKey = VkKeyScanEx_(ascKey, GetKeyboardLayout_(0)) & $FF
      lpBuffer(rtnCount)\EventType = #KEY_EVENT
      lpBuffer(rtnCount)\Event\KeyEvent\bKeyDown = #True
      lpBuffer(rtnCount)\Event\KeyEvent\dwControlKeyState = 0
      lpBuffer(rtnCount)\Event\KeyEvent\uChar = ascKey
      lpBuffer(rtnCount)\Event\KeyEvent\wRepeatCount = 1
      lpBuffer(rtnCount)\Event\KeyEvent\wVirtualKeyCode = vkKey
      lpBuffer(rtnCount)\Event\KeyEvent\wVirtualScanCode = MapVirtualKey_(vkKey, 0)
    Next
    lpBuffer(nLength - 1)\EventType = #KEY_EVENT
    lpBuffer(nLength - 1)\Event\KeyEvent\bKeyDown = #True
    lpBuffer(nLength - 1)\Event\KeyEvent\dwControlKeyState = 0
    lpBuffer(nLength - 1)\Event\KeyEvent\uChar = #VK_RETURN
    lpBuffer(nLength - 1)\Event\KeyEvent\wRepeatCount = 1
    lpBuffer(nLength - 1)\Event\KeyEvent\wVirtualKeyCode = #VK_RETURN
    lpBuffer(nLength - 1)\Event\KeyEvent\wVirtualScanCode = MapVirtualKey_(#VK_RETURN, 0)
    WriteConsoleInput_(hStdInput, @lpBuffer(), nLength, @lpNumberOfCharsWritten)

    If RunAndWait
      Repeat
        Result = WaitForSingleObject_(hStdInput, 100)

        Select Result
          Case #WAIT_ABANDONED : Break
          Case #WAIT_OBJECT_0 : Delay(100)
          Case #WAIT_TIMEOUT : Break
          Case #WAIT_FAILED : Break
        EndSelect
      ForEver
    EndIf
  EndIf
EndProcedure

dwProcessId = cmdGetProcessId("cmd.exe")

If Not dwProcessId : RunProgram("cmd") : Delay(200) : dwProcessId = cmdGetProcessId("cmd.exe") : EndIf

If dwProcessId
  hStdInput.l = cmdOpenConsole(dwProcessId)

  If hStdInput
    con = FindWindow_("ConsoleWindowClass",0)
    SetForegroundWindow_(con)
    Sleep_(1000)
    If cmdAddAlias(".", "cls&&cd c:\&&dir c:") : cmdRunScript(hStdInput, ".") : EndIf
    Sleep_(1000)
    If cmdAddAlias(".", "cd d:\&&dir d:") : cmdRunScript(hStdInput, ".") : EndIf
  EndIf
EndIf
[/size]
Note: replace "." with non-printable/invisible character if it's critical.

------------------------
Or use this:

Code: Select all

ImportC "msvcrt.lib"
  system(str.p-ascii)
EndImport

OpenConsole()
system("cd c:\&&dir c:")
system("dir d:")
Input()
[/size]
Good luck!

Re: RunProgram Java tool multiple times in the same instance

Posted: Thu Sep 17, 2020 10:44 am
by infratec
You made one big mistake:

The command needs time to be executed. You simply closed the program until the result was ready.

Code: Select all

Define DOS.i, Output$, Timeout.i

If OpenWindow(0, 320, 320, 422, 250, "DOS-Output", #PB_Window_SystemMenu)
  
  EditorGadget(0, 8, 8, 406, 233)
  
  DOS = RunProgram("cmd", "/k", "", #PB_Program_Open | #PB_Program_Read | #PB_Program_Write )
  If DOS
    
    *Buffer = AllocateMemory(1024, #PB_Memory_NoClear)
    If *Buffer
      
      WriteProgramStringN(DOS, "dir c:")
      
      Timeout = 10
      Repeat
        
        Len = AvailableProgramOutput(DOS)
        If Len
          Len = ReadProgramData(DOS, *Buffer, Len)
          If Len
            Output$ + PeekS(*Buffer, Len, #PB_UTF8|#PB_ByteLength) + #LF$
          EndIf
          
        EndIf
        
        Delay(100)
        
        Timeout - 1
        
      Until Timeout = 0
      FreeMemory(*Buffer)
    EndIf
    
    CloseProgram(DOS)
    AddGadgetItem(0, -1, Output$)
  EndIf
  
  Repeat
  Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Oct 03, 2020 1:05 pm
by THCM
I tried your example and it works if the execution time is short enough for the selected delay, but how can I check if the called program is finished? The exectution time ist more than a few seconds and differs a lot from PC to PC and the selected conversion data I called.
infratec wrote:You made one big mistake:

The command needs time to be executed. You simply closed the program until the result was ready.

Code: Select all

Define DOS.i, Output$, Timeout.i

If OpenWindow(0, 320, 320, 422, 250, "DOS-Output", #PB_Window_SystemMenu)
  
  EditorGadget(0, 8, 8, 406, 233)
  
  DOS = RunProgram("cmd", "/k", "", #PB_Program_Open | #PB_Program_Read | #PB_Program_Write )
  If DOS
    
    *Buffer = AllocateMemory(1024, #PB_Memory_NoClear)
    If *Buffer
      
      WriteProgramStringN(DOS, "dir c:")
      
      Timeout = 10
      Repeat
        
        Len = AvailableProgramOutput(DOS)
        If Len
          Len = ReadProgramData(DOS, *Buffer, Len)
          If Len
            Output$ + PeekS(*Buffer, Len, #PB_UTF8|#PB_ByteLength) + #LF$
          EndIf
          
        EndIf
        
        Delay(100)
        
        Timeout - 1
        
      Until Timeout = 0
      FreeMemory(*Buffer)
    EndIf
    
    CloseProgram(DOS)
    AddGadgetItem(0, -1, Output$)
  EndIf
  
  Repeat
  Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Oct 03, 2020 1:18 pm
by THCM
@ZX80 Both of your examples seem to work. Is it possible to open a hidden console window? Does it close automatically after exiting the purebasic app?

Re: RunProgram Java tool multiple times in the same instance

Posted: Sat Oct 03, 2020 1:51 pm
by mk-soft
I don't know if you can call Java Tools (.jar) from JavaScript (Script).

If so, try ActiveScript.
Don't reinitialize every time (NewActiveScript), but create a java function and call it as needed. So you don't have to recompile everything every time.

Code: Select all

XIncludeFile "Modul_ActiveScript.pb"

UseModule ActiveScript

Define js.s, Message.s
Runtime Message
Message = "Hello World"

js = ~"var shell = new ActiveXObject(\"WScript.Shell\");" + #LF$
js + ~"var msg = Runtime.String(\"Message\");" + #LF$
js + ~"shell.Popup(msg);" + #LF$

Debug "*** New ActiveScript ***"
*Control = NewActiveScript("JScript")
If *Control
  Debug "*** Parse ScriptText ***"
  r1 = ParseScriptText(*Control, js)
  If r1 = #S_OK
    Debug "Code Ready."
  EndIf
  Debug "*** Free ActiveScript ***"
  FreeActiveScript(*Control)
  Debug "*** Finished ActiceScript ***"
EndIf
[/size]

Link: Module ActiveScript