RTC Forums
November 13, 2024, 07:57:37 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: TRtcFunction and WinExecAndWait32  (Read 5418 times)
thomh
RTC License+
****
Posts: 17


« on: May 29, 2014, 10:04:58 AM »

I am trying to use the WinExecAndWait32V2 method listed below on the server from within a TRtcFunction.OnExecute event.
It basically starts an OCR application/process and waits for it to finish. However when I get to the CreateProcess call it gives me a
"Read of address 00000000" exception.

Is there another preferred way to do this?

{-- WinExecAndWait32V2 ------------------------------------------------}
{: Executes a program and waits for it to terminate
@Param FileName contains executable + any parameters
@Param Visibility is one of the ShowWindow options, e.g. SW_SHOWNORMAL
@Returns -1 in case of error, otherwise the programs exit code
@Desc In case of error SysErrorMessage( GetlastError ) will return an
  error message. The routine will process paint messages and messages
  send from other threads while it waits.
}{ Created 27.10.2000 by P. Below
-----------------------------------------------------------------------}
Function WinExecAndWait32( FileName: String; Visibility: integer ): DWORD;
  Procedure WaitFor( processHandle: THandle );
    Var
      msg: TMsg;
      ret: DWORD;
    Begin
      Repeat
        ret := MsgWaitForMultipleObjects(
                 1, { 1 handle to wait on }
                 processHandle, { the handle }
                 False, { wake on any event }
                 INFINITE, { wait without timeout }
                 QS_PAINT or { wake on paint messages }
                 QS_SENDMESSAGE { or messages from other threads }
                 );
        If ret = WAIT_FAILED Then Exit; { can do little here }
        If ret = (WAIT_OBJECT_0 + 1) Then Begin
          { Woke on a message, process paint messages only. Calling
            PeekMessage gets messages send from other threads processed. }
          While PeekMessage( msg, 0, WM_PAINT, WM_PAINT, PM_REMOVE ) Do
            DispatchMessage( msg );
        End;
      Until ret = WAIT_OBJECT_0;
    End; { Waitfor }
  Var { V1 by Pat Ritchey, V2 by P.Below }
    zAppName:array[0..512] of char;
    StartupInfo:TStartupInfo;
    ProcessInfo:TProcessInformation;
  Begin { WinExecAndWait32V2 }
    StrPCopy(zAppName,FileName);
    FillChar(StartupInfo,Sizeof(StartupInfo),#0);
    StartupInfo.cb := Sizeof(StartupInfo);
    StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartupInfo.wShowWindow := Visibility;
    If not CreateProcess(nil,
      zAppName, { pointer to command line string }
      nil, { pointer to process security attributes }
      nil, { pointer to thread security attributes }
      false, { handle inheritance flag }
      CREATE_NEW_CONSOLE or { creation flags }
      NORMAL_PRIORITY_CLASS,
      nil, { pointer to new environment block }
      nil, { pointer to current directory name }
      StartupInfo, { pointer to STARTUPINFO }
      ProcessInfo) { pointer to PROCESS_INF }
    Then
      Result := DWORD(-1) { failed, GetLastError has error code }
    Else Begin
       Waitfor(ProcessInfo.hProcess);
       GetExitCodeProcess(ProcessInfo.hProcess, Result);
       CloseHandle( ProcessInfo.hProcess );
       CloseHandle( ProcessInfo.hThread );
    End; { Else }
  End; { WinExecAndWait32V2 }


Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #1 on: May 29, 2014, 11:04:26 AM »

I see at least one problem with that function. The WaitFor() loop inside that function could be causing problems when called from within a RTC event, because it imlements a message queue and basically does the same as calling Application.ProcessMessages, which will mess up mesage processing done by the RTC SDK. But since your exception is happening before that line of code, I guess the problem you are having now is that one of the parameters you were passing to the CreateProcess API was NIL, when it should have pointed to something.

On a side-note, I think it is a bad idea for a Server to create and run external processes on-the-fly. That's definitely going to be a weakness in a production environment, when more users will be accessing the Server.

Best Regards,
Danijel Tkalcec
Logged
thomh
RTC License+
****
Posts: 17


« Reply #2 on: May 29, 2014, 03:13:55 PM »

Thanks for the reply. I got this from the makers of the OCR engine:

Quote
No, the engine is not multithread safe, however, programmatically you can initialize more than one instance of the engine to accommodate for multiple simultaneous use. Hope you understand what this means.

Based on this what do you suggest would be the best way to interface with this engine from within TRtcFunction event?
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #3 on: May 29, 2014, 06:27:05 PM »

If running multiple instances of a process is the only way you can get that engine running in a multithreaded environment, I would recommend you to find a different engine, because that engine was obviously not designed for use from a Server.

Normally, if the engine was component based (using object-oriented design), you could create a pool of engine components, the same way you can create a pool of database connection objects, then you could pick one engine object from that pool before use, use it in your code, then put it back into a pool. That would be a propper way of using non-thread-safe objects inside a multi-threaded Server.

Alternatively, if the engine is very fast, of if you don't care much about parallel request processing, you could use a single engine instance within a critical section to avoid concurrent access in a multi-threaded environment. Or, if every single function in your Server needs to access the engine, you can even keep the Server single-threaded to avoid councurrent access alltogether.

Naturally, all of these options are only possible if the engine was written in Delphi and you can compile it into the Server executable. If the engine is only available as a separate executable and there is no other interface to accessing the engine except from the command line, then you're stuck.

Best Regards,
Danijel Tkalcec
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #4 on: May 29, 2014, 06:45:34 PM »

If you can not choose a different OCR engine, then you should ask the developers if there is any other interface to accessing that engine than using command line parameters. Then, you could spawn multiple OCR instances when the Server starts and use a pool of interfaces to those processes to pass "jobs" to the running engines. That would be a lot better solution than spawning a new OCR process for every single OCR job. But you still need a way to wait for a response without the use of a message queue loop.

Best Regards,
Danijel Tkalcec
Logged
thomh
RTC License+
****
Posts: 17


« Reply #5 on: May 29, 2014, 06:53:56 PM »

Thanks again.

The OCR engine is a C DLL.

I did manage to call it without any exceptions. It was a parameter that was not assigned correctly. So the call using CreateProcess/WaitFor() is working from within a TRtcFunction.Execute event. The question is how it will perform on a multithreaded RTC server.
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.025 seconds with 17 queries.