1

Ahoy thar,

I am attempting to run a .exe program (a small helper app written in another language) from within an existing TD6.3 application.

Going by the documentation, I'd think this works with SalLoadApp (or ideally with SalLoadAppAndWait, since I do need to wait for it to finish and would like it to be invisible to the user - the app is a console app with no visible output or user interaction), but trying to call it like that does nothing at all. I've tried both just the appname as a parameter (it's in the same folder as the TD application):

Call SalLoadApp('HelperApp.exe', '')

as well as the full path:

Call SalLoadApp('C:\Users\user\ProjectFolder\HelperApp.exe', '')

Am I misunderstanding how this works or missing something there? Does it only work with TD applications? Is there another way of executing an existing non-TD .exe file via code?

Skjoldson
  • 41
  • 4

2 Answers2

0

Yes you can use SalLoadApp for that purpose. The function can be used for invoking any exe file(no restrictions like only td exe's). For example, If you want call windows calculator just write,

SalLoadApp( "calc.exe", "" )

Also if you want specify file path, then please use double slash(instead of singleslash) as shown below,

Call SalLoadApp('C:\\Users\user\\ProjectFolder\\HelperApp.exe', '')

The format for SalLoadApp is: SalLoadApp( strAppName, strParameters )

strAppName - Name of exe file.

strParameters - Parameter array(space in strParameters marks the end of one argument).

Also If you want call salloadapp without specifying the filelocation, then you can keep the both exe's in same folder- ( HelperApp.exe and calling application)

Chandralal
  • 559
  • 2
  • 11
  • 26
  • The double slashes are a good point, I forgot that. But it seems my problem is another: – Skjoldson Nov 20 '19 at 13:14
  • @Skjoldson Do you tried running the exe's from the same folder. That is HelperApp.exe and calling application exe.(after removing the filepath from first parameter) – Chandralal Nov 20 '19 at 13:19
  • Yes. If I try calling the function that calls SalLoadApp by itself, from a button, everything works fine. In its actual use context, which is during report generation, it doesn't work however. The function is called but does nothing. Any file handling I do within it isn't executed either. Curiously this happens also if I call the function right before the function that calls SalReportPrint, not just if it's called in Sam_ReportFetchNext (where I need it). The direct call via button also stops working if I print a report at some point beforehand. Smells like a synchronicity issue to me – Skjoldson Nov 20 '19 at 13:25
  • Also make sure no command line parameters needed for the HelperApp.exe. If needed, you have to specify it on the second parameter(strParameters). – Chandralal Nov 20 '19 at 13:25
  • You can use the function - call SalPause (nMilliseconds ). It causes a non-blocking pause in the application for the specified number of milliseconds. Call this function after the Load exe call. Try with different durations. – Chandralal Nov 20 '19 at 13:31
  • Another option is, you can try with SalLoadAppAndWait( ). It Starts an application, then waits for it to exit before returning control to the original application. – Chandralal Nov 20 '19 at 13:34
  • Yeah, I tried those too, and on its own, it works. Stepped through my function that handles the .exe (let's call it RunHelper() )in both scenarios. When I just call it by itself via the button, all calls return bOK = true (things like SalFileOpen, SalFileWrite, SalLoadApp/SalLoadAppAndWait etc). When I call the method and follow that call with my Report function call (call it StartReport() ), they all return false. Even if I add the second call below the RunHelper() call in the same button action. Which puzzles me because at that point NO report code has been executed yet. – Skjoldson Nov 20 '19 at 13:42
  • 1
    Ah. I may have found the culprit. The project is a small tester application for reports I'm working on, and I use SalDlgOpenFile to specify the .QRP I want to test. Apparently that causes this behavior, as without it things work as intended. No idea why, but at least now I know I can circumvent it. Thank you very much for the help, however. If you have any idea why SalDlgOpenFile causes this behavior I'd love to know, because it's pretty inconvenient ... – Skjoldson Nov 20 '19 at 13:51
  • SalDlgOpenFile() - displays a window dialog box where the user can select a file to open. It stops(waits) further processing till user selects a file or clicks the cancel button. – Chandralal Nov 20 '19 at 14:01
  • Yeah, I figured it'd probably prevent file system access and since it's probably asynchronous that might somehow cause issues, but it's still blocking access after I did indeed select a file, which is quite unexpected ... is there a way to ensure I can access it again after a file has been selected? – Skjoldson Nov 20 '19 at 14:12
  • After selecting a file successfully function should return TRUE and FALSE if the user clicks the Cancel push button. It will not stops\pause processing after that. – Chandralal Nov 20 '19 at 14:20
  • Also if you are using SAM_ReportFetchNext event, TD does not send data from the application to Report Builder until the application returns TRUE from SAM_ReportFetchNext event. – Chandralal Nov 20 '19 at 15:07
0

Use ShellExecuteW(). This way you have more control

1) Include it as an external function as part of SHELL32.dll:

Library name: SHELL32.DLL
ThreadSafe: No
Function: ShellExecuteW
    Description: The ShellExecute function opens or prints a specified file. The file can be an executable file or a document file. See ShellExecuteEx also.

    Export Ordinal: 0
    Returns
        Number: DWORD
    Parameters
        Window Handle: HWND
        String: LPWSTR
        String: LPWSTR
        String: LPWSTR
        String: LPWSTR
        Number: INT

2) Run your exe with the following syntax ( or lookup 'ShellExecute' for more info )

Call ShellExecuteW( hWndNULL, "open", "C:\\Program Files (x86)\\Gupta\\TeamDeveloper6.2.1\\Your.exe", STRING_Null, STRING_Null, SW_SHOWNORMAL )

3) Optionally write a wrapper function, so you can check any return codes you want e.g. :

Select Case nRet
Case SE_ERR_FNF
    If spApplication
        Set sError = 'Either the Application, or the specified file was not found. ' || sCTRL || sCTRL ||
                'Check the Application ' || spApplication || ' and any Compatibility Packs have been installed on this machine .' || sCTRL  || sCTRL  ||
                'Check the file ' || spFile || ' exists. '
    Else
        Set sError = 'The specified file was not found. ' || sCTRL || sCTRL ||
                'Check the file ' || spFile || ' exists. '
    Break
Case SE_ERR_PNF
    Set sError = 'The specified Path was not found'
    Break
Case SE_ERR_ACCESSDENIED
    Set sError = 'The operating system denied access to the specified file.'
    Break
Case SE_ERR_ASSOCINCOMPLETE
    Set sError = 'The filename association is incomplete , invalid, or has not been defined within Windows'
    Break
Case SE_ERR_DDEBUSY
    Set sError = 'The DDE transaction could not be completed because other DDE transactions are being processed.'
    Break
Case SE_ERR_DDEFAIL
    Set sError = 'The DDE transaction failed.'
    Break
Case SE_ERR_DDETIMEOUT
    Set sError = 'The DDE transaction could not be completed because the request timed out'
    Break
Case SE_ERR_NOASSOC
    Set sError = 'There is no application associated with the given filename extension'
    Break
Case SE_ERR_OOM
    Set sError = 'There was not enough memory to launch the application'
    Break
Case SE_ERR_SHARE
    Set sError = 'Another user has this document open.'
    Break
Case 0
    Set sError = 'The operating system is out of memory or resources'
    Break
Default
    Break


If nRet <=32
If spApplication
    Call SalMessageBox( sError || sCTRL || sCTRL ||
             'File Name =  ' || spFile || sCTRL || sCTRL ||
            'Application Name = ' ||  spApplication , 'Application or File Open Error' , MB_IconStop  |  MB_Ok )
Else
    Call SalMessageBox( sError || sCTRL || sCTRL ||
             'File Name =  ' || spFile , 'File Open Error' , MB_IconStop  |  MB_Ok )
If nRet = SE_ERR_NOASSOC or nRet = SE_ERR_ASSOCINCOMPLETE
    ! Now open the OpenAs dialog from Windows to select an application from a list or browse.
    Call ShellExecuteW( hWndNULL, "open", "rundll32.exe", "shell32.dll,OpenAs_RunDLL " || spFile, STRING_Null, npShowState )
Set bOk = FALSE
Steve Leighton
  • 790
  • 5
  • 15