Monday, August 18, 2025

Run...

 

Snip of the week   
Written using C++ Builder 6 ENT 

ShellExecuteEx( ) - When you want to launch another program from your program.



I have a program I test my code snips from. One of the features is a custom "launch" menu. Some of the items are predefined, some are user defined.
OnClick for these menu items, I set the program's name and parameter, and send them to a function that runs ShellExecuteEx( ). For example:


void __fastcall TShellWnd::Calculator1Click(TObject *Sender)//MenuItem
{
//calculator
AnsiString sProg = "c:\\windows\\system32\\calc.exe";//path to calculator
AnsiString sParams = "";//usually null
LaunchProgram(Sender, sProg, sParams);
}
I can send all my "Launch" clicks to the same function

bool __fastcall TShellWnd::LaunchProgram(TObject *Sender, AnsiString Program, AnsiString Params)
{
//------------------------ Launch Menu Click--------------//
if(FileExists(Program))
	{
     AnsiString sExe = Program.c_str();
     MessageBeep(0);
     SHELLEXECUTEINFO execinfo ;
     memset (&execinfo, 0, sizeof (execinfo)) ;
     execinfo.cbSize = sizeof (execinfo) ;
     execinfo.lpVerb = "Open" ;// [  |   |  ]
     execinfo.lpFile = sExe.c_str() ;
     execinfo.lpParameters = "Params" ;//as needed
     execinfo.fMask = SEE_MASK_NOCLOSEPROCESS ;// see shellapi.h (lines 346-368)
     execinfo.nShow = SW_SHOW;// [ SW_HIDE | SW_SHOWMINNOACTIVE | SW_MINIMIZE ]
     if (! ShellExecuteEx (&execinfo))
          {
          ShowMessage("ERROR::0x0020\nCould not create process : " + Program);
          return -1 ;//change to your error value
          }
     }
return true;
}

 
For the custom menu items, I use an INI file to store the information I need, that I set from a preferences dialog.

The INI reads like this:


[Menu]
----snip----
Custom5Caption=PhotoShop 5.5
Custom5Path=C:\Program Files\Adobe\Photoshop 5.5\Photoshp.exe
----snip----
The main form's OnCreate event:

TIniFile *ini;
          ini = new TIniFile( ChangeFileExt( Application->ExeName,".ini") );
----snip----
	     Custom51->Caption   =  ini->ReadString( "Menu", "Custom5Caption",  "");
	     sCustomPath5        =  ini->ReadString( "Menu", "Custom5Path",     "");
----snip----
		delete ini;

MenuItem - "Custom51" OnClick:


void __fastcall TShellWnd::Custom51Click(TObject *Sender)//MenuItem
{
// Custom5
if(Custom51->Caption != "")//invisible
     {
     if(Custom51->Caption != "Custom 5")//designtime text
          {
          if(sCustomPath5 != "")//blank lpfile (command string)
               {
               LaunchProgram(Sender, sCustomPath5, NULL);
               }
          }
     }
}

The lpfile doesn't have to be an executable program. ShellExecuteEx( ) will take files with registered extentions and open them in their associated applications (.txt, .doc, .wav, etc)
On the other hand, if there is no association, or you want to do something different with the file, to can usually use the "filename.ext" as a parameter. For example, Windows 7 associates .jpg files to Internet Explorer, but I want to edit the image... so:


SetCurrentDir(sWorkingDir);
OpenPicDlg->InitialDir = sWorkingDir;
if(OpenPicDlg->Execute())
     {
     AnsiString sFile = OpenPicDlg->FileName;
     if(FileExists(sFile))
     	{
          AnsiString sExe = "mspaint.exe";//open  ms-paint
          SHELLEXECUTEINFO execinfo ;
          memset (&execinfo, 0, sizeof (execinfo)) ;
          execinfo.cbSize = sizeof (execinfo) ;
          execinfo.lpVerb = "Open" ;
          execinfo.lpFile = sExe.c_str() ;
          execinfo.lpParameters = sFile.c_str() ;//file to open in ms-paint
          execinfo.fMask = SEE_MASK_NOCLOSEPROCESS ;
          execinfo.nShow = SW_SHOW;
          if (! ShellExecuteEx (&execinfo))
               {
               ShowMessage("ERROR::0x0022\nCould not create process - Open (Image)");
               return  ;
               }
          }
     }


You'll find the definition in shellapi.h (line numbers)
Include\shellapi.h(321): ////  Begin ShellExecuteEx and family
Include\shellapi.h(324): /* ShellExecute() and ShellExecuteEx() error codes */
Include\shellapi.h(346-368) fmask defined (#define SEE_MASK_CLASSNAME 0x00000001) for example
Include\shellapi.h(442): SHSTDAPI_(BOOL) ShellExecuteExA(LPSHELLEXECUTEINFOA lpExecInfo);
Include\shellapi.h(443): SHSTDAPI_(BOOL) ShellExecuteExW(LPSHELLEXECUTEINFOW lpExecInfo);
Include\shellapi.h(445): #define ShellExecuteEx  ShellExecuteExW
Include\shellapi.h(447): #define ShellExecuteEx  ShellExecuteExA
Include\shellapi.h(479): ////  End ShellExecuteEx and family


typedef struct _SHELLEXECUTEINFOA
{
        					// Required fields
        DWORD 		cbSize;
        ULONG 		fMask;
        HWND 		hwnd;
        LPCSTR		lpVerb;
        LPCSTR  	lpFile;
        LPCSTR		lpParameters;
        int 		nShow;
        HINSTANCE	hInstApp;
        					// Optional fields
        LPCSTR		lpDirectory;
        LPVOID		lpIDList;
        LPCSTR		lpClass;
        HKEY		hkeyClass;
        DWORD		dwHotKey;
        union
		{
		HANDLE	hIcon;
		HANDLE	hMonitor;
		} DUMMYUNIONNAME;
        HANDLE		hProcess;
} SHELLEXECUTEINFOA, *LPSHELLEXECUTEINFOA;


to the top

No comments:

Post a Comment