Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29235 Discussions

programmatically launch a program when location is unknown

dboggs
New Contributor I
1,704 Views

I need my program to launch an app, as though from a command line. The problem is that I don't know the path to the app. I have tried various forms of SYSTEM, RUNQQ, FINDFILEQ, and FULLPATHQQ to no avail.

The particular present example is launching Adobe Reader, so I need to execute the file AcroRead32.exe. As far as I can see, my program needs the complete to this file in order to launch it. 

I know that I can do a SYSTEM call like "Dir C:\AcroRead32.exe /s > parsethis.txt", and then write code to extract the path from this txt output file. But surely there must be a better way? Even this solution assumes that the app is in the C: drive.

Isn't there some way to return the path to an arbitrary filename from within Fortran?

0 Kudos
8 Replies
NotThatItMatters
Beginner
1,704 Views

Have you checked for this on CodeProject?  I "requisitioned" some of their code for a VB app I wrote to find an executable.

0 Kudos
Steven_L_Intel1
Employee
1,704 Views

What you really want is ShellExecute - and open the file not the application. This is the same as if you had double-clicked on the PDF (or whatever) file and uses the users file association.

0 Kudos
Paul_Curtis
Valued Contributor I
1,704 Views

Here's some code which launches Acrobat to open a selected pdf file.  First the pdf file is selected from a directory (which lives at a standard offset in the calling program's directory tree), then the full pathname to the selected file, which will be something like

AdobePath = 'C:\Program Files\Adobe\Acrobat 6.0\Reader\AcroRd32.exe'//CHAR(0)

is submitted to CreateProcess() using the class name for Adobe (which is presumed to be already installed on the computer):

SUBROUTINE ViewPDF
	USE ShellOut
	USE CmnDlgs
	USE charfunc
	IMPLICIT NONE
	INTEGER                         :: nc, np
	CHARACTER(LEN=256)				:: findpdf
    CHARACTER(LEN=200), PARAMETER   :: pdfFilter = "PDF files (*.pdf)"c//"*.pdf"c//""c

	CALL full_path (RootPath, "docs", "*", "pdf", fpname)
    IF (.NOT.CmnDlgOpenFile(ghwndMain, pdfFilter, fpname)) RETURN

	nc = INDEX(fpname, CHAR(0))
	IF (chcnt(AdobePath, LEN(AdobePath)) > 0) THEN
	    np = INDEX(AdobePath, CHAR(0))
	    findpdf = AdobePath(1:np-1)//" "//fpname(1:nc)
	    
	    !   the Adobe acrobat classname has evidently changed since
	    !   version 6, and the new class name is 'AcrobatSDIWindow'
	    !CALL Launch (findpdf, 'AdobeAcrobat'C)  ! classname discovered with Spy++
	    CALL Launch (findpdf, 'AcrobatSDIWindow'C)  ! classname discovered with Spy++
	ELSE
        np = MessageBox (ghwndMain, 'PDF reader not initialized'c, 'Error'c, MB_OK)		
	END IF
	
END SUBROUTINE ViewPDF

 

and where

 

SUBROUTINE Launch (progname, classname)
	IMPLICIT NONE
	CHARACTER(LEN=*), INTENT(IN)   :: progname, classname
	
	INTEGER                        :: rval
	!CHARACTER(LEN=8), PARAMETER	   :: dllname = 'rsc.dll'c
	CHARACTER(LEN=40)              :: emsg
	TYPE(T_STARTUPINFO)			   :: si
	TYPE(T_PROCESS_INFORMATION)	   :: pi

	!     TYPE T_PROCESS_INFORMATION
	!     SEQUENCE
	!       integer(HANDLE) hProcess ! knowns  HANDLE 
	!       integer(HANDLE) hThread ! knowns  HANDLE 
	!       integer(DWORD) dwProcessId ! knowns  DWORD 
	!       integer(DWORD) dwThreadId ! knowns  DWORD 
	!     END TYPE

	!	disallow multiple child processes; previous shellouts
	!	must have been already terminated by the user
	IF (IsWindow(hwnd_ChildProcess) == 0) THEN

		CALL ZeroMemory (LOC(pi), SIZEOF(pi))
		CALL ZeroMemory (LOC(si), SIZEOF(si))

		si%cb		   = SIZEOF(si)
		si%dwFlags	   = STARTF_USESHOWWINDOW
		si%wShowWindow = SW_SHOWNORMAL

		IF (CreateProcess (NULL,						& ! process name
						   progname,					& ! command line			
						   NULL_SECURITY_ATTRIBUTES,	& ! security attributes		
						   NULL_SECURITY_ATTRIBUTES,	& ! thread attributes
						   FALSE,						& ! handle inheritance
						   0,							& ! creation flags
						   NULL,						& ! environment block
						   NULL,						& ! initial working path
						   si,							& ! startup info
						   pi) ) THEN  					  ! process info			

			!	let the process load itself
			rval = WaitForInputIdle (pi%hProcess, 2000)

			!	get its window handle from the classname
			hwnd_ChildProcess = FindWindow (classname, NULL)
			
			!   if this fails we must never hook the main
			!   Kiltel window, or the system will be unreachable
			IF (hwnd_ChildProcess == ghwndMain) hwnd_ChildProcess = 0
		    CALL mousehook (hwnd_ChildProcess)
		    
			rval = CloseHandle (pi%hProcess)
			rval = CloseHandle (pi%hThread)
		
		!	problem creating new process
		ELSE
			rval = GetLastError()
			SELECT CASE (rval)
			CASE (ERROR_FILE_NOT_FOUND)
			    emsg = 'FILE NOT FOUND'C
			CASE (ERROR_DIRECTORY)
				emsg = 'DIRECTORY NOT FOUND'C
			CASE (ERROR_PATH_NOT_FOUND)
				emsg = 'PATH NOT FOUND'C
			CASE (ERROR_BAD_PATHNAME)
				emsg = 'BAD PATH NAME'C
			CASE DEFAULT
				emsg = 'Cannot create process'c
			END SELECT
            rval = MessageBox (ghwndMain, emsg, "Launch Error"C, &
                               IOR(MB_OK,MB_ICONERROR))
		END IF
	END IF
END SUBROUTINE Launch

 

0 Kudos
andrew_4619
Honored Contributor III
1,704 Views

@paul , I used to do things like in your code but Dr Fortran's method using shellexecute is much better in my opinion. It is a one liner, you tell windows to open the pdf file and let windows chose the application that is set up for opening pdfs. I found I had to otherwise 'fix' the code from time to time as windows and/or acrobat was updated.

ret = ShellExecute (&
    hwnd = NULL, &  !!2
    lpOperation = "open"C, & !!3
    lpFile = trim(filename)//char(0), & !!4
    lpParameters = NULL_CHARACTER, & !!5
    lpDirectory = NULL_CHARACTER, & !!6
    nShowCmd = SW_SHOWNORMAL) !!7

 

0 Kudos
IanH
Honored Contributor III
1,704 Views

ShellExecute also honours any customisations that the user has made - if they have associated PDF files with a viewer other than acrobat reader, they are going to be a little annoyed when your program arbitrarily ignores that association.

0 Kudos
Steven_L_Intel1
Employee
1,704 Views

ianh wrote:

ShellExecute also honours any customisations that the user has made - if they have associated PDF files with a viewer other than acrobat reader, they are going to be a little annoyed when your program arbitrarily ignores that association.

Yeah, I get annoyed when apps open web pages in MSIE when I have Chrome set as default. ShellExecute is really useful for a lot of things.

0 Kudos
dboggs
New Contributor I
1,704 Views

Steve, you are absolutely right--at least for my present application, ShellExecute does exactly what I need. Tried it and it worked the first time. Thanks for posting it and the link to your excellent documentation.

For other apps I will hold the Dir c:\---- /s > LookHere.txt in reserve.

0 Kudos
Steven_L_Intel1
Employee
1,704 Views

The problem with trying to do a DIR is that executable file names can change and such a DIR command can take a long time. If there's a particular application you need and ShellExecute doesn't suffice, see if the application provider offers a way to get the installed location from the registry or environment variables. There are so many things that can go wrong with a "big hammer" DIR approach.

0 Kudos
Reply