Process name missing from GetCommandLine() - winapi

I have a problem with the GetCommandLine() API.
It usually returns the executable name followed by a space and arguments. As documentation says, the first token may not have the complete path to the image and blah blah blah.
I never had problems until now that I used CreateProcess with lpApplicationName not NULL.
If I use:
CreateProcess(NULL, "\"c:\\myexe.exe\" param1 param2", ...)
GetCommandLine returns "c:\myexe.exe param1 param2" as expected.
But if I use:
CreateProcess("C:\myexe.exe", "param1 param2")
GetCommandLine returns only "param1 param2".
How do I know if the executable name is given on the command line if another application launches mine?
Also, MFC startup code assumes that the first token on the command line is the executable name and skips it. But if you launch a MFC application with the second CreateProcess API example, MFC's code will skip the first argument.

Not your problem. It's the job of the other application to construct the command line properly. You should simply assume that the first argument is an executable name as expected and skip over it.

I have a workaround which can be helpful in a case like this.
I guess we always be able to check how our module was been started.
In this case we should check first argument.
I will write code because I have some problem with English.
Here two ways:
The first case. we can compare module name with first command line argument.
something like this:
const TCHAR* csCommandLine = ::GetCommandLine();
// Attention!!! the first symbol can be quete
if (*csCommandLine == _T('\"'))
csCommandLine++;
TCHAR sModuleFileName[MAX_PATH];
DWORD dwModuleFileName = ::GetModuleFileName(NULL, sModuleFileName, MAX_PATH);
if (dwModuleFileName && !_tcsncmp(csCommandLine, sModuleFileName, dwModuleFileName)) {
// The command line contains the module name.
}
The second case. we can try to get file attributes for the first command line argument
something like this:
// Attention!!! don't use it case if you are going to pass a file path in command line arguments.
int nArgc;
LPTSTR* szArglist = ::CommandLineToArgvW(::GetCommandLine(), &nArgc);
if (nArgc && ::GetFileAttributes(szArglist[0]) != INVALID_FILE_ATTRIBUTES) {
// The command line contains the module name.
}
::LocalFree(szArglist);
I hope it can be helpful someone.
Regards, Vladimir

Related

How to pass command line arguments to Deno?

I have a Deno app, that I wish to pass some command line args to. I searched the manual, but found nothing.
I tried to use the same commands used in Node.js, assuming they might be sharing some for the std libraries, but it didn't work as well.
var args = process.argv.slice(2);
// Uncaught ReferenceError: process is not defined
Any suggestions?
You can access arguments by using Deno.args, it will contain an array of the arguments passed to that script.
// deno run args.js one two three
console.log(Deno.args); // ['one, 'two', 'three']
If you want to parse those arguments you can use std/flags, which will parse the arguments similar to minimist
import { parse } from "https://deno.land/std/flags/mod.ts";
console.log(parse(Deno.args))
If you call it with:
deno run args.js -h 1 -w on
You'll get
{ _: [], h: 1, w: "on" }
You can use Deno.args to access the command line arguments in Deno.
To try it create a file test.ts :
console.log(Deno.args);
And run it with deno run test.ts firstArgument secondArgument
It will return you with an array of the passed args:
$ deno run test.ts firstArgument secondArgument
[ "firstArgument", "secondArgument" ]
If you take a stroll through the standard library, you will find a library named flags, which sounds like it could be library for command line parsing. In the README, you will find your answer in the very first line:
const { args } = Deno;
Also, if you look at the Deno Manual, specifically the Examples section, you will find numerous examples of command line example programs that perform argument parsing, for example, a clone of the Unix cat command (which is also included in the First Steps section of the Deno Manual), where you will also find your answer in the first line:
for (let i = 0; i < Deno.args.length; i++)
So, in short: the command line arguments are a property of the global Deno object, which is documented here:
const Deno.args: string[]
Returns the script arguments to the program. If for example we run a program:
deno run --allow-read https://deno.land/std/examples/cat.ts /etc/passwd
Then Deno.args will contain:
[ "/etc/passwd" ]
Note: According to the Manual, all non-web APIs are under the global Deno namespace.

Show error message for every argument that is not defined in Ruby program

I'm creating a program in Ruby for replacing content of multiple files in one directory, and there are four arguments:
dir for defining directory
ext for defining extension
find for defining string to find
replace for defining string that replace string defined as find
Right now, this is start of the program:
dir, ext, find, replace = ARGV
dir, ext, find, replace = ARGV.shift
raise "Missing argument for directory" unless dir
raise "..." unless ext
#etc
However, when I run this program without defining arguments, it shows only first argument that is not defined (directory) with RuntimeError and imediatelly closes program. Is there any different approach for this?
I can offer you such variant:
missing_parameters = ["dir","ext","find","replace"].select{|name| eval(name).nil?}
raise "Missing parameters for #{missing_parameters.join(',')}" unless missing_parameters.empty?
But frankly speaking, i don't like the usage of eval :)

calling Qprocess with arguments containing spaces - Windows

I am trying to call an executable with qprocess and pass some arguments which might (and most probably will) contain spaces (not all of them).
The executable is a python script that has been packaged with Py2exe. The python script uses optparse to parse the arguments.
If I call the py2exe.exe in cmd.exe the call is like this:
pythonExecutable.exe -aarg_a -barg_b -c"path with spaces" -darg_d
A call like this will be successful.
I want to do this through a Qt application using Qprocess, but I can't find a way to do it because Qprocess will strip any quotes("") leaving the arguments broken wherever spaces appear.
I seem to be missing something, can anyone help with this issue?
that won't be much of an issue if u use the QProcess in a more proper way
QString program = "pythonExecutable.exe";
QStringList arguments;
arguments <<"-aarg_a"<< "-barg_b"<< "-c\"path with spaces\""<< "-darg_d";
QProcess *myProcess = new QProcess(parent);
myProcess->start(program, arguments);
normaly when u have arguments with space and do't need a " symbol
you just have to pass the argument in a QStringList
QString program = "pythonExecutable.exe";
QStringList arguments;
arguments <<"a"<< "path with spaces";
QProcess *myProcess = new QProcess(parent);
myProcess->start(program, arguments);
this program is a modified version of example program listed in the Qt docs Here

Wrap an executable to diagnose it's invocations

I have a Windows executable (whoami) which is crashing every so often. It's called from another process to get details about the current user and domain. I'd like to know what parameters are passed when it fails.
Does anyone know of an appropriate way to wrap the process and write it's command line arguments to log while still calling the process?
Say the command is used like this:
'whoami.exe /all'
I'd like a script to exist instead of the whoami.exe (with the same filename) which will write this invocation to log and then pass on the call to the actual process.
From a batch file:
echo Parameters: %* >> logfile.txt
whoami.exe %*
With the caveat that you can have problems if the parameters contain spaces (and you passed the in escaping with "), because the command-line parser basically de-escapes them and they should be re-escaped before passed to an other executable.
You didn't note which programming language. It is not doable from a .bat file if that's what you wanted, but you can do it in any programming language. Example in C:
int main(int argc, void **argv)
{
// dump contents of argv to some log file
int i=0;
for (i=0; i<argc; i++)
printf("Argument #%d: %s\n", argv[i]);
// run the 'real' program, giving it the rest of argv vector (1+)
// for example spawn, exec or system() functions can do it
return 0; // or you can do a blocking call, and pick the return value from the program
}
I don't think using a "script" will work, since the intermediate should have a .exe extension for your ploy to work.
I would write a very small command line program to do this; something like the following (written in Delphi/Virtual Pascal so it will result in a Win32 executable, but any compiled language should do):
program PassThrough;
uses
Dos; // Imports the Exec routine
const
PassTo = 'Original.exe'; // The program you really want to call
var
CommandLine: String;
i: Integer;
f: Text;
begin
CommandLine := '';
for i := 1 to ParamCount do
CommandLine := CommandLine + ParamStr(i) + ' ';
Assign(f,'Passthrough.log');
Append(f);
Writeln(f, CommandLine); // Write a line in the log
Close(f);
Exec(PassTo, CommandLine); // Run the intended program
end.
Can't you just change the calling program to log the parameters it used to call the process, and the exit code?
This would be way easier than trying to dig into whoami.exe
Look for whoami.exe, BACK IT UP, replace it with your own executable and see do whatever you like with it's parameters (maybe save them in a text file).
If you can reproduce the crash, use Process Explorer before crashed process is terminated to see its command line.
http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx

Alternative to system() and _popen() on Windows

This is related to: How do I read the results of a system() call in C++?
I am trying to do the exact the same thing only that my program needs to pass 'multiple parameters with spaces' to the command. I need the command line output and the exit code from the process.
Example: An example with Textpad. The application I'm really using prints stuff on stdout.
string command1 = "\"C:\Program Files\TextPad 5\Textpad.exe\" C:\readme0.txt";
string command2 = "\"C:\Program Files\TextPad 5\Textpad.exe\" \"C:\read me2.txt\"";
cout << system(command1.c_str()) << endl;
cout << system(command1.c_str()) << endl;
Output:
0
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
1
The first call to system passes and second one fails with the error above. _popen in Windows works similarly on Windows so no help there. I can easily do this on Linux as I can escape spaces in the parameters without having to use quotes.
An alternative is to write a huge chunk of non-cross-platform code as listed here:
http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx
But in case I want to avoid that, are there any alternatives to system() and _popen() on Windows?
Thanks!
The lowest level Windows API function used by _popen() and system() is CreateProcess().
However CreateProcess() is not that simple to use - especially when you want to get the process'es output or write to the process'es input.
CreateProcess() will definitely work with file names that contain space characters (as long as they are written in quotation marks the way you did that).
The following solves the spaces in the path problem. Catching the output of the command is much more difficult, however:
#include <string>
#include <cstdlib>
using namespace std;
int main() {
string cmd = "\"c:\\program files\\notepad++\\notepad++.exe\"";
system( cmd.c_str() );
return 0;
}
A bunch of utility libraries have taken that chunk of non-portable code and wrapped it up with a portable interface. For an example, see Qt's QProcess.
I do this (note - this is VB.NET code), so I can write the output of the command to my log file (it's wrapped in a RunCommand() method):
Try
Dim myprocess As New Process()
myprocess.StartInfo.FileName = "C:\Program Files\TextPad 5\Textpad.exe"
myprocess.StartInfo.RedirectStandardOutput = True
myprocess.StartInfo.UseShellExecute = False
' inArgs are the arguments on the command line to the program
myprocess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
myprocess.StartInfo.Arguments = "C:\readme0.txt"
' the dir to set as default when the program runs
Then myprocess.StartInfo.WorkingDirectory = "C:\Program Files\TextPad 5\"
myprocess.Start()
' grab a reader to the standard output of the program
procReader = myprocess.StandardOutput()
' read all the output from the process
While (Not procReader.EndOfStream)
procLine = procReader.ReadLine()
' write the output to my log
writeNotes(procLine)
End While
procReader.Close()
Catch ex As Exception
' Write the error to my log
writeErrors("Couldn't execute command "C:\Program Files\TextPad 5\Textpad.exe", ex)
End Try
I think ShellExecute() is what you're looking for.
Never use system() in Windows !
Just redirect i/o handles.

Resources