I have used a number of programs where I am able to use the programs functions by simply dragging and dropping a file onto the executable. For example, if there is a program that formats text files, simply dragging a text file onto the executable will make it run and use the text file as the target.
What does the main function look like for a program that allows this?
Dropped files are usually just given as command line parameters to the program:
int main(int argc, char** argv)
{
if (argc > 1)
{
// do sth. with argv[1] == first dropped file name
}
}
Related
Many of you have probably wondered- how can I get rid of a font or any other single file from the drive when using a library like SFML, which needs to load a font from a file path.
So, how do I embed that data into the executable, so the resulting executable does not depend on those resource files anymore?
First of all, we have to get our resource. I have downloaded "BalooBhaijaan-Regular.ttf" font from google fonts.
Then, one should get the binary data of the given font. The easiest way to achieve this in my opinion is to use the linux "xxd" command with -i parameter which outputs in a C-style array.
Let's redirect the output to a file because It is usually going to be long if we are talking about true type fonts or larger images:
xxd -i BalooBhaijaan-Regular.ttf > font_data.txt
Create an empty C/C++ header or put the font data into an already existing file. I prefer using new header files as the output is going to be really long.
Of course, after pasting into your IDE you can change the array type to const as the content of a font usually doesn't change.
This is how it looks in my IDE:
You might of course wonder why is this a char array - simply because in a char array each "field" represents one byte.
As you might have noticed, xxd also creates another variable for us - the last variable in the font_data.txt is an unsigned int which informs us about the length of the array. We will need this later. Name of the "length-informing" integer is same as name of the array with "_len" suffix
Now, there are two ways to proceed:
1. load font from the memory using a builtin method (some libraries support it, SFML does)
2. create a "fake" file and load it
Lets talk about both cases
1.
This one is fairly simple, sfml supports loading file from memory given it's address and size, so we can just do this:
#include "BalooBhaijaanFont.hpp"
#include <SFML/Graphics.hpp>
int main(int argc, char** argv) {
sf::RenderWindow mainWindow(sf::VideoMode(200,100), L"TEST");
sf::Font fromMem;
fromMem.loadFromMemory(&BalooBhaijaan_Regular_ttf, BalooBhaijaan_Regular_ttf_len);
sf::Text text("WORKS!", fromMem);
while(mainWindow.isOpen()){
mainWindow.draw(text);
mainWindow.display();
}
return 0;
}
As you can see, loading it with a builtin function is really easy.
2.
Now it's time for a temporary file approach which i really do NOT recommend - most libraries support loading from memory and if you are making your own library you are going to end with having a memory load function anyway.
Whilst it is still possible to create a file just to read it to a font class and then remove it, I do not see any sense of using this method unless you are extremely annoyed by additional files in your folders.
Just for reference:
#include "BalooBhaijaanFont.hpp"
#include <SFML/Graphics.hpp>
int main(int argc, char** argv) {
sf::RenderWindow mainWindow(sf::VideoMode(200,100), L"TEST");
sf::Font fromFile;
{
FILE * tempFile = fopen("tmpfont.ttf", "wb");
fwrite( BalooBhaijaan_Regular_ttf, sizeof(char), BalooBhaijaan_Regular_ttf_len, tempFile );
fclose(tempFile);
fromFile.loadFromFile("tmpfont.ttf");
std::remove("tmpfont.ttf");
}
sf::Text text("WORKS!", fromFile);
while(mainWindow.isOpen()){
mainWindow.draw(text);
mainWindow.display();
}
return 0;
}
For Windows you can do xxd -i Roboto-Bold.ttf > font_data.txt in git bash. This gives you a file with data that can be imported straight into your project.
I'm working on a realtime virus scanner on OSX. The OSX's command line command fs_usage can be used to determine folder access in the following way (and can only be run as root user):
fs_usage -w -f pathname | grep '/Users/.*/Documents\|/Users/.*/Downloads' | grep mds
Then, just scan for a line containing the phrase:
open
(4 spaces in front, 4 spaces after)
This will emit when a file is downloaded into the Documents or Downloads folder. You can then do a file hash (sha256 is best) on that and use a SQLite database to check whether you've already previously scanned that file or not. If not, then you can scan that file.
Okay, that's interesting, but what's the C++ or Objective C way to determine folder access like that? I mean, surely the fs_usage command is using some kind of API for that, right?
One clue I have I think is the Apple File System Events API. However, I just don't quite grasp it from the examples given for my particular scenario.
The following code must be in a main.m and not a main.mm or it won't compile. (SEE ADDENDUM BELOW for C++ (main.mm).) The following code runs in a loop, watching new file creations in /Users/mike/Documents and /Users/mike/Downloads. (Sorry, it doesn't support wildcards on those paths -- I wish it did!) Press CTRL+C to exit the run loop.
Note in the output, if you download a file, you'll see a consistent flag ID of 125184. If a new file is copied into a folder from the same folder, the flag ID is 128256. If a new file is created fresh (like from an editor), the flag ID is 108544. If an existing file is dragged into a folder, the flag ID is 67584. You'll need to keep experimenting with IDs to see what events you want to trap. For instance, if coding a real-time virus scanner, you'd probably want to detect files moved either by command line, drag and drop, cut/paste, or downloaded from the web to a particular folder. Try various scenarios and subfolders, see the IDs you get, and write code that traps those flag IDs.
#import <Foundation/Foundation.h>
void detectNewFile (
ConstFSEventStreamRef streamRef,
void *clientCallBackInfo,
size_t numEvents,
void *eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[])
{
int i;
char **paths = eventPaths;
printf("GOT AN EVENT!!!!\n");
for (i=0; i<numEvents; i++) {
printf("Change %llu in %s, flags %u\n", eventIds[i], paths[i], (unsigned int)eventFlags[i]);
}
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
short nPathCount = 2;
CFStringRef mypath[nPathCount];
mypath[0] = CFSTR("/Users/mike/Documents");
mypath[1] = CFSTR("/Users/mike/Downloads");
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, nPathCount, NULL);
void *callbackInfo = NULL;
CFAbsoluteTime latency = 1.0; // seconds
FSEventStreamRef hStream = FSEventStreamCreate(NULL,
&detectNewFile,
callbackInfo,
pathsToWatch,
kFSEventStreamEventIdSinceNow,
latency,
kFSEventStreamCreateFlagFileEvents
);
FSEventStreamScheduleWithRunLoop(hStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
FSEventStreamStart(hStream);
printf("Waiting on new file creations...\n");
CFRunLoopRun(); // runs in an endless loop, only letting the callback function run
} // end autorelease pool
return 0;
}
Addendum
If you need this to work with main.mm and thus C++, you need to add CoreServices.framework library to the build steps. Then, change this line:
char **paths = eventPaths;
...to this line:
char **paths = (char **)eventPaths;
Then change this line:
void *callbackInfo = NULL;
...to this line:
FSEventStreamContext *callbackInfo = NULL;
Then change this line:
CFAbsoluteTime latency = 1.0; // seconds
...to this line:
CFTimeInterval latency = 1.0; // seconds
Persay, if I wanna change the .exe on runtime of my program (Like its original name would be: someexe.exe and after you have closed it will change to something random or similiar)
I've seen it happen before and I'm very much interested in implementing it just for fun!
Thanks :)
I'm not 100% sure, but the regular rename function should work. However, I'm not sure if it's possible to rename a file that is currently held open by the OS (and I have no Windows system that I can test on right now).
If you can't do it on "your own executable", then you'd have to rename the file by running another program [or batchfile] and then resuming your own program [e.g. let the rename program start your program again, and it recognising somehow that it's now the new name and can continue.
Possible code
#include <iostream>
#include <windows.h>
int main(int argc, char** argv)
{
system("title a.exe");
std::cout<<"a.exe is the current name of your .exe file\n";
//do your stuff
std::cout<<"a.exe is changing to b.exe\n";
system("RENAME C:\\path\\a.exe b.exe");
system("title b.exe");
//do your stuff
std::cout<<"now b.exe is changing to a.exe\n";
system("title a.exe");
system("RENAME C:\\path\\b.exe a.exe");
//do you stuff
return 0;
}
But using systemcommand is considered to be bad practise therefore you should use rename command ,, code :
#include <stdio.h>
int main(int argc , char** argv)
{
rename("a.exe","bii.exe");
//do your stuff
rename("bii.exe","a.exe");
//do your stuff
return 0;
}
You have to make a copy of the executable file. Then you can rename that file and when you close your current program file you need to transfer control to another program preferably a batch file which deleted the original executable.
in windows system() should be able to do these stuff.
you also need to write your own batch file with code to delete thr program that calls it.
I have a C++ program which has the prototype of the main function as follows:
int main(int argc, char * argv[])
The code hasn't been written by me, but this is a single C file available here.
When I compile this code, and through the command line run it as:
someexe in.txt > out.txt
This gives me an output out.txt which is generated in the same directory by operating on some input from in.txt.
someexe in.txt out.txt
This gives me an output on the command line itself. (without using > operator)
However, instead of passing the command line argument and without using the output redirection > operator, I have been trying to call the main function from another function and passing the parameters myself. If I pass an array of char* {fileDirName, in.txt}, I am not sure how to go about generating an out.txt (since I think > output redirection is an operating system level function available in command line).
Any suggestions would be greatly appreciated
The program in the link is readily available as copy paste and can be tried (main function is written at the last in the above program)
Assuming the aim is to mimic the output redirection feature (> out.txt) of the shell you can do something like:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <iostream>
int main() {
int fd = open("out.txt", O_WRONLY|O_CREAT|O_TRUNC, 0660);
assert(fd >= 0);
const int ret = dup2(fd, 1);
assert(ret >= 0);
std::cout << "Hello redirected world!" << std::endl;
close(fd);
}
You can do similar for stdin also, to mimic the input redirection (< in.txt). These will be preserved across calls to exec() too.
Of course it would be simpler to modify the program to write to the place you wanted given you have the source available.
Note though that dup2(), which "swap" the stdout fd for the one we just opened is non-portable. IIRC open() (as opposed to fopen()) is UNIX specific also)
You can't call another main() from inside the source another program - main() is special.
If you want to reuse this source code as a library you need to rename main() to something else.
However if it is handling input from either a pipe or a file (eg myprog < input.txt or myprog input.txt) in the normal Unix way then that's a little trickier to handle transparently.
The best way would be to call the compiled program as a separate process from within your new program, passing the correct commandline parameters - see the exec() family of calls
I have a console program written in C++. Now I want to open a manual document(in .txt or .pdf) everytime a user of the program types 'manual' in console. How can I do this? Any links to a tutorial would be helpful.Thanks
Try to compile this code (Open.cpp) to Open.exe
Then, you can execute it with (for example) these parameters :
Open "C:\your file.doc"
Open "C:\your file.exe"
Open notepad
#include "windows.h"
int main(int argc, char *argv[])
{
ShellExecute(GetDesktopWindow(), "open", argv[1], NULL, NULL, SW_SHOWNORMAL);
}
Explanation of the program :
You should first include windows
library (windows.h) to get
ShellExecute and GetDesktopWindow function.
ShellExecute is the function to execute the file with parameter
argv[1] that is path to the file to be opened
Another option for lpOperation
arguments instead of "open" is
NULL. "explore" and "find" are
also the options but they are not
for opening a file.
SW_SHOWNORMAL is the constant to
show the program in normal mode (not
minimize or maximize)
Assuming you're on Windows, you're looking for the ShellExecute function. (Use the "open" verb)
In standard, platform independent, C and C++ you can use the system function to pass the name of an application to open your files.
For example, using Windows:
const char text_filename[] = "example.txt";
const char text_application[] = "notepad.exe";
std::string system_str;
system_str = text_application;
system_str += " ";
system_str += text_filename;
// Execute the application
system(system_str.c_str());
The text you send to the system function is platform specific.
In Managed C++ is its very easy
System::Diagnostics::Process::Start(path);
done !