I wrote a c++ program that can save its internal state to the disk in a file of a custom type. How can I get windows to run my program upon a file of this type being double clicked? Is there a method of passing arguments to main() so the program knows what file was selected?
If you use "Run with..." from the Windows explorer context menu, you can select your application binary.
Windows will supply the absolute file path as the first argument to your application.
int main(int argc, char **argv)
{
if (argc < 2)
std::cout << "No argument" << std::endl;
else
std::cout << "Filename is " << argv[1] << std::endl;
}
Why 2 arguments? Because arguments always start in argv[1]. argv[0] usually contains the path to your application binary.
If you call "d:\MyApp.exe c:\MyImage.bmp" then
argc == 2
argv[0] == "d:\MyApp.exe"
argv[1] == "c:\MyImage.bmp"
Related
I'm trying to run a simple calculator program by passing it the numbers and the operation from the command line, such as "25.2 + 4.87". It works fine when using the default values but once I pass in the arguments, it throws the following message: "Exception thrown: read access violation. argv was 0xFEFEFEFE"
Here's the code:
//Valores por default
char num1[] = "0.5";
char num2[] = "10.25";
char operacion = '/';
if (argv[1] && argc ==4) {
std::cout << argv[1] << std::endl;
std::cout << argv[2] << std::endl;
std::cout << argv[3] << std::endl;
strcpy_s(num1, 100, argv[1]);
strcpy_s(num2, 100, argv[3]);
operacion=*argv[2];
}
It prints out the arguments fine but after running the program it throws the error I mentioned earlier after executing the second strcpy_s:
strcpy_s(num2, 100, argv[3]);
The first strcpy_s works fine and num1 gets assigned the first number I passed in the arguments, but anything else I do after that throws the error.
While debugging line by line I noticed that the variable "argv" has the correct path for my executable file, but after executing the first strcpy_s, the content changes from the correct file path to
0xfefefefe
I've looked for this error but all of them had a nullptr error, I couldn't find any information on this. I would greatly appreciate your help, thanks.
I have a program that runs indefinitely. For testing purposes I have made a wrapper program that kills the other after a specified amount of time (specified via command line/terminal args). The program being forked requires that it is passed two folders with the same name (I have no control over this), so I simply pass it the same arg twice as can be seen here:
pid_t pid = fork();
if(pid == 0)
{
//build the execution string
char* test[2];
test[0] = argv[2];
test[1] = argv[2];
test[2] = NULL;
cout << "test[0] is " << test[0] << endl;
cout << "test[1] is " << test[1] << endl;
cout << "argv[1] is " << argv[1] << endl;
execvp(argv[1],test);
}
The problem is that the program being passed in argv[1] keeps segmentation faulting. If I call the by itself via the terminal it runs with no problems. I am passing the same folder in both cases. Can anyone tell me why it isn't working for execvp?
I should mention a co-worker ran it on his computer as well, and it will stand up fine the first time, but each time after that, it will seg fault.
edit: I have added a null term to test, however, this has not fixed the issue.
The command's form is exactly:
<executable> <wrapped prog> <folder> <duration>
In relative paths it's:
Intel/debug/Tester.exe <program> test 10
If the length of the array is static, you might be better off with
execlp
execlp(argv[1], argv[1], argv[2], argv[2], (char*)0);
As for execvp, the array should start with the name of the executable and end with NULL.
execvp
char* args[] = { argv[1], argv[2], argv[2], NULL };
execvp(argv[1], args);
runWithTimeout
In any case, if all you want is a simple wrapper that runs a single child with a timeout, then your program could be very simple and general if only you'd be willing to start with the timeout argument:
/*runWithTimeout.c
compile with: make runWithTimeout
run with: ./runWithTimeout seconds program arguments...
*/
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
int main(int argc, char** argv)
{
assert(argc >= 1+2);
int pid, status = 1;
if((pid = fork()) == 0) {
alarm(atoi(argv[1]));
execvp(argv[2], argv + 2);
/*^the child ends here if execvp succeeds,
otherwise fall-through and return the default error status of 1
(once in child (which has no one to wait on) and
then in the parent (which gets the status from the child))*/
perror("Couldn't exec");
}else if(pid < 0){ perror("Couldn't fork"); };
wait(&status);
return status;
}
Array passed as arguments should be null-terminated. For example:
char *test[3]={0};
...
You can turn on core dumps ( make sure to shut them off when done ) ulimit -c unlimited . Run it before you run your main process. ( I would be leary of running it in the fork though you probably can. )
When your program crashes this will produce a core dump which you can examine with gdb.
For help with core files, you can just google them.
Other then that. You can make a script which launches your file. You can use the script to log stuff.
You want:
char* test[3];
test[0] = argv[2];
test[1] = argv[2];
test[2] = NULL;
You need a NULL parameter to mark the end of the parameter list.
Given the specification:
The command's form is exactly:
<executable> <wrapped prog> <folder> <duration>
In relative paths it's:
Intel/debug/Tester.exe <program> test 10
and also:
The program being forked requires that it is passed two folders with the same name…
then, assuming you've checked that the wrapper is passed 4 arguments, the code you need is:
pid_t pid = fork();
if (pid == 0)
{
//build the execution string
char *test[4]; // Note the size!
test[0] = argv[1]; // Program name: argv[0] in exec'd process
test[1] = argv[2]; // Directory name: argv[1] …
test[2] = argv[2]; // Directory name: argv[2] …
test[3] = NULL; // Null terminator
cout << "test[0] is " << test[0] << endl;
cout << "test[1] is " << test[1] << endl;
cout << "test[2] is " << test[2] << endl;
execvp(test[0], test);
cerr << "Failed to exec '" << test[0] << "': " << strerror(errno) << endl;
exit(1); // Or throw an exception, or …
}
There is seldom (but not never) a reason to invoke execvp() other than using the idiom execvp(argv[0], argv) for the array of arguments in argv.
Note that this code ensures that the control flow doesn't escape from the statement block that is supposed to represent the child. Having the child process continue afterwards, usually in effect thinking it is a parent process, leads to confusion. Always make sure the child execs or exits. (That's a rhetorical over-statement — yes; but there's a large chunk of truth behind the idea too.) Also, since this is C++, you may need to consider How to end C++ code?. That complicates life. The crucial thing is that if the child process fails to exec, it does not continue as if it was a parent process.
I'm working on a (C++) program that more or less revolves around renaming files. I would like to make it so that you can select a file, right-mouse click it and select "Open With" and then select my application.
I got the context menu part figured out, I just don't know how to do the C++ part.
In other words, how to make a program (in C++) that can be opened together with a file (so by context menu or directly opening it) and process this file?
Example:
In my Windows, I associate the ".roberto" extension with "C:\Program Files\MyProgram\MyProgram.exe". So if I open a ".roberto" file, a command prompt pops up, only displaying the name of the selected file.
I hope this is clear, I am not sure how to explain this. I also had some trouble with searching on this question, so please forgive me if this has been asked before.
Thanks.
On Windows platform in MFC-based application this is done automatically by framework in InitInstance() method of your application class:
EnableShellOpen();
RegisterShellFileTypes(TRUE);
IMPORTANT: In general this functionality is framework dependent and OS speicific.
I figured it out!
Using the arguments given to main was the clue. The following program prints one line if opened directly, this line is the path of the program itself, and if opened with the 'Open with...' options it also shows the selected file.
#include "stdafx.h"
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
cout << "Argument count: " << argc << endl << endl;
for (int i = 0; i < argc; i++)
{
cout << argv[i] << endl;
}
cout << endl << endl << endl << endl;
system("pause");
return 0;
}
I'm somehow having issues parsing command-line arguments on Windows in C++.
I tried using this
int main(int argc, char **argv)
{
std::cout << "Command-line argument count: " << argc << " \n";
std::cout << "Arguments:\n";
for (int i = 0; i < argc; i++)
std::cout << " argv[" << i << "] "
<< argv[i] << "\n";
return 0;
}
as well as this
int main(int argc, char *argv[])
{
std::cout << "Command-line argument count: " << argc << " \n";
std::cout << "Arguments:\n";
for (int i = 0; i < argc; i++)
std::cout << " argv[" << i << "] "
<< argv[i] << "\n";
return 0;
}
The variables argc and argv seem to be somehow uninitialized.
That's what launching the program returns to me:
Z:\Dev\ProcessSuspender\Debug>ProcessSuspender a
Command-line argument count: 2130558976
Arguments:
argv[0]
argv[1] ╠ÉÉÉÉÉj↑h╚♂YwÞØ÷■ âe³
argv[2]
(crash following)
I compiled it with MSVC12 using the /SUBSYSTEM:CONSOLE linker option.
What could be the cause of this issue?
I've manually set the entry point to main. Whether I use the default project setting (_tmain) or not, the issue persists.
In general, you should not do that unless you know the consequences. The typical values of the entry point (/ENTRY) should be either:
[w]mainCRTStartup, which calls [w]main, or
[w]WinMainCRTStartup, which calls [w]WinMain, or
_DllMainCRTStartup, which calls DllMain.
Why is this needed? Well, the …CRTStartup-family of functions do a couple crucial things, including the initialization of:
the C runtime (CRT),
any global variables, and
the arguments argc and argv, as you've accidentally found out.
So for a typical program you probably want it to do its job. In the Linux world, there is an equivalent function called _start that is needed to do the same initialization tasks as well, which can be overridden with -e while linking.
The confusion here probably stems from difference in ambiguous meaning of the word "entry point": there is the meaning of "apparent entry point" from the perspective of the language (which is main and its ilk), and the meaning of the "true entry point" from the perspective of the language implementation (which is …CRTStartup or _start).
Note that using the …CRTStartup functions is not absolutely essential, as you can certainly write a program that avoids using them. It does come with a cost, however:
you can't use the C runtime, so you can't use most of the standard library,
you need to manually initialize any global variables, and
you need to manually obtain argc and argv using the Windows API (GetCommandLineW and CommandLineToArgvW).
Some do this to avoid dependency on the CRT, or to minimize the executable size.
I tried your project on VS 2012 and it is working smoothly.
I added a getchar(); command as below:
#include <iostream>
int main(int argc, char *argv[])
{
std::cout << "Command-line argument count: " << argc << " \n";
std::cout << "Arguments:\n";
for (int i = 0; i < argc; i++)
std::cout << " argv[" << i << "] "
<< argv[i] << "\n";
getchar();
return 0;
}
so that i could see the output.
Right-click on Project -> Properties -> debugging -> Command
Arguments.
This was empty in my project and i added the character a to simulate your problem.
Here is the output i am getting:
Right click on the project -> Debug -> Start new Instance -> would you
like to build it -> yes
Output:
Command-line argument count: 2
Arguments:
argv[0] <my macines path>\helpingStack1.exe
argv[1] a
Please check this again. I hope this helps.
1) I am suspecting that your binaries are not up to date when you run this script so please do a clean build and verify that you are indeed running the same exe as the one you are building. Please check the configuration - Debug/Release.
2) go to the folder where you have created the project and righclick on the project folder, and change property -> ensure read only is not checked in the check box.
Obviously, Something is wrong with the IDE or project or maybe anything else's setup on your system only.
The code is perfect.
Have you tried directly and independently running your output exe, by executing it through command prompt ??
Run your exe with command prompt by supplying some arbitrary arguments, and check the output.
its worth to check your character set in project properties->General.
This question already has answers here:
Get path of executable
(25 answers)
Closed 4 years ago.
I want to get the full path of the current process.
I use _getcwd to get the current working directory. But it not includes file name.
How can I get file name like: filename.exe?
argv[0] of your main function is your filename.
A simple code snippet:
#include<stdio.h>
int main(int argc, char** argv)
{
//access argv[0] here
}
If you cannot access/change code in main(), you can do something like this:
std::string executable_name()
{
#if defined(PLATFORM_POSIX) || defined(__linux__) //check defines for your setup
std::string sp;
std::ifstream("/proc/self/comm") >> sp;
return sp;
#elif defined(_WIN32)
char buf[MAX_PATH];
GetModuleFileNameA(nullptr, buf, MAX_PATH);
return buf;
#else
static_assert(false, "unrecognized platform");
#endif
}
On windows you can use:
TCHAR szExeFileName[MAX_PATH];
GetModuleFileName(NULL, szExeFileName, MAX_PATH);
szExeFileName will contain full path + executable name
[edit]
For more portable solution use argv[0] or some other platform specific code. You can find such aproach here: https://github.com/mirror/boost/blob/master/libs/log/src/process_name.cpp.
On Linux, the filename of your binary is the destination of a symlink at /proc/self/exe. You can use the readlink system call to find the destination of a symlink.
Note that this tells you the actual location on disk where the binary is stored, not simply the command the user used to start your program.
Here's a cross-platform way using boost (https://www.boost.org/)
#include <iostream>
#include <boost/dll.hpp>
int main( int argc, char **argv ) {
std::cout << "hello world, this is [" << boost::dll::program_location().filename().string() << "]" << std::endl;
std::cout << "or [" << boost::dll::program_location().string() << "] if you're not into the whole brevity thing." << std::endl;
return 0;
}
compiled via
g++ -o hello_world hello_world.cpp -lboost_filesystem -lboost_system -ldl
results in the output
hello world, this is [hello_world]
or [/home/gjvc/tmp/hello_world] if you're not into the whole brevity thing.
As others have mentioned, the name of your executable is contained in argv[0]. If you need that, you could:
cout << argv[0] << endl;
If you need the name of a source file of the executable, C++ has a predefined macro you can use:
cout << __FILE__ << endl;
Go to here and scroll to "Predefined macro names"
You can use program_invocation_name from errno.h
https://linux.die.net/man/3/program_invocation_short_name
In Linux (POSIX?) there is an enviroment variable called _ that contains the current process.
$ echo $_
echo
In C++
#include <stdlib.h> /* getenv */
#include<iostream>
int main(){
std::cout << getenv("_") << '\n';
return 0;
}
compile
$ c++ a.cpp -o a.out
$ ./a.out
prints ./a.out (or whatever is the executed line, including path).
This has certain advantages over the other approaches, it can be read globally (not passing argv[0]) and doesn't need file handling.
You can usually get the executable file name from argv[0]:
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("Running: %s\n", argv[0]);
return 0;
}
Indeed, there are ways for an application to execl() another application (or another similar function) and override this argument. It still is unconventional for the system to change it for that sort of application.