Hello there
I'm using a large number of portable programs for a long time(including Multi Commander).
Some of them are console, the others are GUI, but most of them accept arguments.
Sometimes it's very handy to use MC tools for shortcuts/buttons/file type setup, but in most cases this is not enough for me, therefore, I decided to make a tiny tool which finds and executes specified filename(or even the beginning of the filename). First version was written in Batch script, it had worked pretty slow and I've rewritten it to C(the code is below).
This tool (let's call it just "run") supports executing .bat, .cmd, .exe, .vbs and any other extension located in PATHEXT global variable
It tries to find specified file recursively, starting with root to itself folder. This is especially useful with portable devices where all paths should be relative. That's how portable programs approximately organized in my PC:
X:\data\exec\!run.exe <--- Our tool. I called it "!run" because I have another program called "run"
X:\data\exec\script1.vbs <---vbs script
X:\data\exec\script2.bat <---batch script
X:\data\exec\mc\MultiCommander.exe
X:\data\exec\firefox\firefox.exe
X:\data\exec\sysinternals\procmon\procmon.exe
And so on
To execute any of them with any arguments, I only need to "!run <filename> [args]"
For example:
"!run upx -9 target.exe" - run upx\upx.exe with arguments "-9 target.exe"
or
"!run proc" - run sysinternals\procmon\procmon.exe
or
"!run multi" - run mc\multicommander.exe
Using this tool with MC is very useful because you can easily copy filepaths and pass them as arguments. (
Don't forget to wrap path arguments with spaces in quotation marks, otherwise your programs will parse them as different arguments)
Keep in mind that MC command line is limited to visible borders, but I hope this will be changed in future.
Well, let's integrate our tool with Multi Commander:
1. Add new script
function GetArgs()
{
@var $args = "";
@var $n;
@var $a;
for( $n = 1; $n < $argcount; $n = $n + 1 )
{
$a = $arg($n);
$args += ' "' + $a + '"';
}
return $args;
}
@var $cmd = GetTagValue("${mcinstallpath}") + "\\..\\!run.exe"; //change this line to your !run.exe path if needed!!!
@var $cmdargs = StrTrimLeft($arg(0), ":") + GetArgs();
if( StrFind($arg(0), ":", 0) == 0 )
MC.Run CMD="{$cmd}" ARG="{$cmdargs}" ADMIN
else
MC.Run CMD="{$cmd}" ARG="{$cmdargs}"
Note that script also allow you to run our tool with Admin rights by prefixing filename with ':'
2. Make alias for that script. Personally, I use just "r"
3. Use it!
Same examples using MC:
r firef - run X:\data\exec\firefox\firefox.exe
r upx -9 "C:\Program Files\Test\Test.exe" - run X:\data\exec\upx\upx.exe with arguments "-9 "C:\Program Files\Test\Test.exe""
r
:procm - run X:\data\exec\sysinternals\procmon\procmon.exe
with admin rightsNote that you can use it the same way everywhere - just locate !run.exe in program files for example, and modify path to !run.exe in MC scripts(or make additional script)I hope it will be helpful for someone
And sorry for my bad English
Source code for "run" tool (compiles with any VS version):#include <stdint.h>
#include <string.h>
#include <Windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi")
LPWSTR lpCmd;
LPWSTR *szArgList;
#define UNC_PREFIX L"\\\\?\\"
#define MAX_PATH_UNC (INT16_MAX-sizeof(UNC_PREFIX))
int ExecuteFile(const LPWSTR szPath)
{
WCHAR szCurPathUNC[INT16_MAX];
wcscpy(szCurPathUNC, UNC_PREFIX);
LPWSTR szCurPath = szCurPathUNC+4;
if (szPath)
{
if (wcscpy_s(szCurPath, MAX_PATH_UNC, szPath))
return FALSE;
}
else
{
GetModuleFileNameW(GetModuleHandle(NULL), szCurPath, MAX_PATH_UNC);
*wcsrchr(szCurPath, L'\\') = L'\0';
}
PathAddBackslashW(szCurPath);
size_t nLen = wcslen(szCurPath);
if (wcscat_s(szCurPath, MAX_PATH_UNC, szArgList[1]) ||
wcscat_s(szCurPath, MAX_PATH_UNC, L"*"))
return FALSE;
WIN32_FIND_DATAW ffd;
HANDLE hFind = FindFirstFileW(szCurPathUNC, &ffd);
szCurPath[nLen] = '\0';
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
LPWSTR pExt = PathFindExtensionW(ffd.cFileName);
static WCHAR szPathExt[1024];
if (!szPathExt[0])
GetEnvironmentVariableW(L"PATHEXT", szPathExt, sizeof(szPathExt));
PWCHAR buf, pPathExt = wcstok(szPathExt, L";", &buf);
while (pPathExt != NULL)
{
if (_wcsicmp(pExt, pPathExt) == 0)
{
if (wcscat_s(szCurPath, MAX_PATH_UNC, ffd.cFileName))
return FALSE;
PWCHAR pArgs = wcschr(lpCmd, L' ');
if (pArgs != NULL)
pArgs++;
ShellExecuteW(NULL, NULL, szCurPath, pArgs, NULL, SW_SHOW);
return TRUE;
}
pPathExt = wcstok(NULL, L";", &buf);
}
}
} while (FindNextFileW(hFind, &ffd) != 0);
}
if (wcscat_s(szCurPath, MAX_PATH_UNC, L"*"))
return FALSE;
hFind = FindFirstFileW(szCurPathUNC, &ffd);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (wcscmp(ffd.cFileName, L".") != 0 && wcscmp(ffd.cFileName, L"..") != 0)
{
szCurPath[nLen] = '\0';
if (wcscat_s(szCurPath, MAX_PATH_UNC, ffd.cFileName))
return FALSE;
if (ExecuteFile(szCurPath))
return TRUE;
}
}
} while (FindNextFileW(hFind, &ffd) != 0);
}
return FALSE;
}
int WINAPI wWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nCmdShow)
{
int nArgCount;
szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgCount);
lpCmd = lpCmdLine;
if (nArgCount == 1)
{
MessageBoxW(NULL, L"Usage: run <(beginning of)filename> [args]", L"Error", MB_ICONHAND);
return EXIT_FAILURE;
}
if(!ExecuteFile(NULL))
{
MessageBoxW(NULL, L"File not found", L"Error", MB_ICONASTERISK);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}