How can I call notepad.exe from a C program? - c

i have written a time table program in c
#include<stdio.h>
#include<conio.h>
void main()
{
int i=0;
int selection;
char day[20];
char sub1[20];
char sub2[20];
char sub3[20];
FILE *fp;
fp=fopen("aa.txt","w");
textcolor(5);
textbackground(3);
clrscr();
while(i<3)
{
printf("Enter the day ");
scanf("%s",day);
printf("Enter the period 12.30-1:30 ");
scanf("%s",sub1);
printf("Enter the period 1.35-2.40 ");
scanf("%s",sub2);
printf("Enter the period 2.45-3.50 ");
scanf("%s",sub3);
fprintf(fp,"\n %s TIMETABLE IS AS FOLLOWS\n",day);
fprintf(fp,"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
fprintf(fp,"|~~~~~~~~~|~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~|~~~~~~~~~~|\n");
fprintf(fp,"| TIME | 12.30-1.30 | 1.35-2.40 |2.45-3.50 |\n");
fprintf(fp,"|~~~~~~~~~|~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~|~~~~~~~~~~|\n");
fprintf(fp,"| SUBJECT * %s * %s * %s|\n",sub1,sub2,sub3);
fprintf(fp,"|~~~~~~~~~|~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~|~~~~~~~~~~|\n");
i++;
}
printf(" Time table has been Created in the File aa.txt successfully");
getch();
}
when i finish the timetable . the time table is created in a.txt file. i want that file to be opened and show me automatically in a notepad. how to program that in c?

Use
system("notepad.exe aa.txt");

Dani already described the easier way (using system), so I'll just describe the other (more complicated but also more flexible) way to do it using the Windows API. Browsing the API (Overview -> System Services -> Processes and Threads), there's a small example on how to create a process using the CreateProcess() function. In your case:
CreateProcess("notepad.exe", // Name of program to execute
"aa.txt", // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi); // Pointer to PROCESS_INFORMATION structure
And then wait for the Notepad process to exit, as described in the example.

Third way: use the ShellExecute shell function telling to the shell to "just open the file" with the default editor:
#include <windows.h>
#include <Shellapi.h>
// ...
if(ShellExecute(
NULL, // No parent window for error message boxes/...
"open", // Shell action ("verb") to be performed on the file (as opposed to "print", "explore", ...)
"aa.txt", // File to be opened
NULL, // Command-line parameters - not used when opening documents
NULL, // Working directory - the current one is used by default
SW_SHOW // State of the window of the application being launched - SW_SHOW is the default
)<=(HINSTANCE)32 // If ShellExecute returns a value <=32 it means that an error has occurred
)
{
puts("Cannot open aa.txt with the default editor - ShellExecute failed.");
}
This will open aa.txt with the default editor for txt files.
In my opinion, this is the best solution:
it respects the user's choice for the editor (unlike CreateProcess, which just opens notepad.exe); if I set PSPad as the default editor for txt files, it will pop up PSPad and not notepad.
it doesn't have problems with search paths for the editor (where is notepad.exe?)
its behavior is fully defined, unlike the system function, which relies on command.com/cmd.exe, which have subtle differences between Windows versions and don't give you any documented/easy way to check if the operation succeeded;
it doesn't give you any "false feeling of portability" like the system, that will happily compile on a Linux machine but will simply not work at runtime.

Related

AllocConsole issue when manually mapping PE + fetching output

I am working on a project that involves manually mapping and executing a PE inside of the project process. The main project whose code I am using as a basis for this can be found here: https://github.com/aaaddress1/RunPE-In-Memory/blob/master/RunPE-In-Memory/RunPEinMemory/RunPEinMemory.cpp
The project above compiles and runs fine. During the mapping of the PE that this project is used to run, it will hook the API's related to processing commandline arguments, allowing the user to manually specify arguments to the mapped PE rather than the mapped PE trying to use the arguments provided to RunPEinMemory.exe (since this is all happening inside the same process).
The project I am working towards differs from this base project in that:
I (have successfully already) hooked API's like ExitProcess and exit() and redirect them to ExitThread to prevent the mapped PE ending the RunPEinMemory.exe process
I need to eventually send the output from whatever the mapped PE is elsewhere. To do this, I am redirecting stdout/stderr to anonymous pipes that I later read from in RunPEinMemory prior to running the mapped PE.
I am struggling on the second account.
My project needs to be compiled as a GUI app (subsystem=windows) rather than a Console app (subsystem=console).
The issue arises in that in order to manipulate the stdin/stdout/stderr handles, a console needs to be attached to the process. There are numerous StackOverflow posts about this topic that cover using AllocConsole and then reopening the std handles in order to redirect output to the new console (or elsewhere). A prominent post on this matter can be seen here: Redirecting stdout in win32 does not redirect stdout
I have implemented this code and can successfully manually map/run powershell.exe (passing 'gci' as an argument for example). The stdout/stderr is redirected to anonymous pipes and then read, after which is it written out to a file (for testing purposes currently). This successful test is done with my project.exe compiled for subsystem=windows as intended.
This falls apart when I try to do the same thing with cmd.exe (passing '/c dir' as arguments). I this case, the output fails to make it to stdout or stderr, and there are no bytes to read from the anonymous pipes.
Now when I instead compile this project as a Console program (subsystem=console) and I remove the AllocConsole call (so using the console that Windows allocates for me), the program succeeds. I notice that the cmd.exe output goes to stderr, rather than stdout. But regardless, I am able to successfully redirect that output to one of the anonymous pipes, read it, and then write it out to file.
This leads me to believe that I am missing something when it comes to calling AllocConsole, some follow-on step to fully set up the environment so that certain programs can successfully send output to stdout/stderr. This post mentions a bit about cmd.exe using win32Api's to write to stdout/stderr (as opposed to the other ways to do so as mentioned in a previous link), so I'm wondering if I'm not successfully setting something up when manually allocating a console: https://stackoverflow.com/a/66689266/18776214
The relevant code is as such:
//Allocate console. This line is the one that gets commented out between console/windows test
BOOL suc = AllocConsole();
//Reopen streams after allocating console + disable buffering
FILE* fout;
FILE* ferr;
freopen_s(&fout, "CONOUT$", "r+", stdout);
freopen_s(&ferr, "CONOUT$", "r+", stderr);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
//Open anonymous pipes for stdout and stderr
HANDLE hreadout;
HANDLE hwriteout;
HANDLE hreaderr;
HANDLE hwriteerr;
SECURITY_ATTRIBUTES sao = { sizeof(sao),NULL,TRUE };
SECURITY_ATTRIBUTES sae = { sizeof(sae),NULL,TRUE };
CreatePipe(&hreadout, &hwriteout, &sao, 0);
CreatePipe(&hreaderr, &hwriteerr, &sae, 0);
printf("CreatePipe last error: %d\n", GetLastError());
printf("hreadout is: %p\n", hreadout);
printf("hwriteout is: %p\n", hwriteout);
printf("hreaderr is: %p\n", hreaderr);
printf("hwriterr is: %p\n", hwriteerr);
//Set std_output_handle and std_error_handle to the write-ends of anonymous pipes
SetStdHandle(STD_OUTPUT_HANDLE, hwriteout);
SetStdHandle(STD_ERROR_HANDLE, hwriteerr);
//Convert write-ends of anonymous pipes to file descriptors and use _dup2 to set stdout/stderr to anonymous pipes
int fo = _open_osfhandle((intptr_t)(hwriteout), _O_TEXT);
int fe = _open_osfhandle((intptr_t)(hwriteerr), _O_TEXT);
int res = _dup2(fo, _fileno(fout)); //_fileno(fout)
int res2 = _dup2(fe, _fileno(ferr)); //_fileno(ferr)
printf("fo is: %d\n", fo);
printf("fe is: %d\n", fe);
printf("res is: %d\n", res);
printf("res1 is: %d\n", res2);
//Execute manually mapped PE now that stdout/stderr have been redirected
Sleep(2000);
HANDLE hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)retAddr, 0, 0, 0);
WaitForSingleObject(hThread, 5000);
Sleep(2000);
//Reopen streams again to set stdout/stderr back to console
freopen_s(&fout, "CONOUT$", "r+", stdout);
freopen_s(&ferr, "CONOUT$", "r+", stderr);
//check how much data there is to be read from pipe + allocate buffer
DWORD cbBytesAvailOut;
PeekNamedPipe(hreadout, NULL, NULL, NULL, &cbBytesAvailOut, NULL);
printf("PeekNamedPipe last error: %d\n", GetLastError());
printf("stdout bytes avail is: %d\n", cbBytesAvailOut);
DWORD cbBytesAvailErr;
PeekNamedPipe(hreaderr, NULL, NULL, NULL, &cbBytesAvailErr, NULL);
printf("PeekNamedPipe last error: %d\n", GetLastError());
printf("stderr bytes avail is: %d\n", cbBytesAvailErr);
//Allocate buffer based on number of bytes available to read
wchar_t* pipeBuf = calloc(cbBytesAvailErr + 2, sizeof(wchar_t));
char* convertBuf;
Sleep(2000);
//Currently only reading from a single pipe, edit this block as needed to get data when it exists
//Read from pipe
DWORD bytesRead;
printf("right before readfile!\n");
BOOL fSuccess = ReadFile(hreaderr, pipeBuf, (cbBytesAvailErr + 2) * sizeof(wchar_t), &bytesRead, NULL);
printf("fSuccess is: %d\n", fSuccess);
printf("ReadFile last error: %d\n", GetLastError());
printf("wide string: %ls\n", pipeBuf);
printf("normal string: %s\n", pipeBuf);
printf("bytesread is: %d\n", bytesRead);
//Write buffer out to disk
Sleep(2000);
char* filename = "C:\\Users\\User\\Inline-Execute-PE-main\\Inline-Execute-PE\\x64\\Release\\outfile.txt";
DWORD byteswritten;
HANDLE hFileOut = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hFileOut, pipeBuf, bytesRead, &byteswritten, NULL);
So the two scenarios are this:
Compile as console app with the above code with the first line (AllocConsole()) commented out, everything else the same, manually mapping cmd.exe with commandline args "cmd.exe /c dir" -> works, cmd.exe output is sent to stderr pipe and can be read
Compile as windows app with the above code, using AllocConsole(), manually mapping cmd.exe with commandline args "cmd.exe /c dir" -> fails, cmd.exe output is not captured
Again using powershell.exe works just fine. I'm thinking because maybe it uses a different means to write to stdout/stderr than cmd.exe does.
Does anyone have any ideas?
Edit: As an update, I tried putting the AllocConsole() call BEFORE the PE is mapped into memory by the RunPEinMemory project. This results in the output from cmd.exe displaying to the outputted console, however it isn't being redirected to the pipe still. That is progress at least, but it seems like the stdout/stderr from cmd.exe still isn't linked or connected to the overall process for some reason
I was finally able to resolve this problem.
The issue appears to be WHEN I was calling AllocConsole and redirecting the stdout/stderr.
Previously the order was:
Manually map PE
Fix IAT of PE
AllocConsole
Redirect stdout/stderr using freopen_s and SetStdHandle
Transform Win32 handles to C std handles using open_osfhandle and _dup2
CreateThread to run PE
The working order was:
AllocConsole
Redirect stdout/stderr using freopen_s and SetStdHandle
Manually map PE
Fix IAT of PE
Transform Win32 handles to C std handles using open_osfhandle and _dup2
CreateThread to run PE
So it looks like when the IAT of the mapped PE gets fixed/setup the console needs to already be there and properly set up first.

execve(2) system commands exit before execution

I am trying to implement a container, and for that I create a process using the clone(2) system call with the appropriate flags:
if ((child_pid = clone(child_main, process_struct.Stack + process_struct.StackPtr,
CLONE_NEWCGROUP
|CLONE_NEWIPC
|CLONE_NEWNET
|CLONE_NEWNS
|CLONE_NEWPID
|CLONE_NEWUTS
|SIGCHLD, &process_struct, checkpoint)) == -1){
fprintf(stderr,"Failed...%m \n");
exit(EXIT_FAILURE);
}else{
fprintf(stderr,"Done\n");
waitpid(child_pid, NULL, 0);
}
inside child_main() I Change the host name for the process's namespace, also i set the mount namespace, I installed a Linux file system hierarchy on a partition like a normal Linux installation (I did that to create a clean file system image clean of my files and binaries) and then I set the propagation type to MS_UNBINDABLE, then I pivot_root(2) to change my process's root directory.
const int child_main(struct process *process_struct, int *checkpoint){
char c;
fprintf(stderr,"=> IPC setup...");
//double check the IPC
close(checkpoint[1]);
fprintf(stderr,"Done\n");
if ( sethostname(process_struct->Hostname,
strlen(process_struct->Hostname)) || mounting(process_struct)){
return -1;
}
// startup the IPC pipes
read(checkpoint[0], &c, 1);
if(execve("/bin/bash", (char*)0, NULL) == -1 ){
fprintf(stderr,"--> Launching process Failed %m\n");
return -1;
}
return 0;
}
The problem is that my system goes over the execve(2) and does not launch the /bin/bash and the program flows without errors. When I add system(2) statement before the execve(2) : system("ls"); it lists the appropriate file system and current working directory. Also when I change the execve(2) paramters to either:
execve("/bin/ls", (char*)0, NULL) or execve("/bin/pstree", (char*)0, NULL) or any other parameter it will return an error of: No such file or directory or A NULL argv[0] was passed through an exec system call, also when I strace my program at the execve(2) system call it gives: NULL, 0, NULL) = 17992
The error has nothing to do with the file system image, I have performed more tests and are as the follwoing, I used for my mount namespaces my system's filesystem not the one I installed on a partition and running /bin/bash doesn't still work, I created a simple C program and compiled it, and it ran fine so there is something wrong that prevent bin/bash from being executed, to further test these results I reused for my mount namespaces the file system from my I moved the same executable to the file system first under "/" and second under the same path
my main system path to the executable= /home/omar/docs/test.out
my mounted file system from the partition path to the executable= /home/omar/docs/test.out
since I wanted to check if the same path might have caused a confusion while adding to each executable a statment so can tell which path did my program take, and it worked fine without any problem and correctly as expected, so the problem is just that system essential commands will not work.
You need to pass a proper argv array to execve. And if you just want to pass on the current environment, use execv rather than execve.
char *argv[] = {"bash", NULL};
if(execv("/bin/bash", argv) == -1 ){
perror("execv");
return -1;
}

How to work with C redirection in Xcode?

I'd like to redirect the Standard Input in C so that I can get a number from a CSV file with scanf and display it in the console using printf. This is what my code looks like:
int main() {
int number;
printf("Number:\n");
scanf("%d", & number);
printf("The number is %d", number);
return 0;
}
I'd like to specify the location of the folder containing the CSV file and the CSV file for the redirection in advance with
> ./myProject < myCSV.csv
But straight after I run the program, the console looks like this:
Number:
When I type the above code I suppose scanf eats > ./myProject < myCSV.csv up. What am I doing wrong?
If you're running your program from within Xcode then use Product => Scheme => Edit Scheme... (shortcut Command<) to set the command line arguments (including any I/O redirection). You can also set additional environment variables here, if needed.
Note that if you plan to specify relative paths as command line arguments then the working directory may need to be set appropriately - this option is found in the Options tab, to the right of the Arguments tab in the Edit Scheme... dialog.
UPDATE
Unfortunately it seems that a bug introduced in Xcode 4 is still present in at least Xcode 6.4, which means that I/O redirection specified using the above method currently does not work correctly (oddly it worked correctly in Xcode 3 and earlier).
To work around this I suggest specifying an optional input file name on the command line, and then explicitly handle this in your code, e.g.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[])
{
int number;
if (argc > 1)
{
FILE * fp = freopen(argv[1], "r", stdin);
if (fp == NULL)
{
perror(argv[1]);
exit(1);
}
}
printf("Number:\n");
scanf("%d", &number);
printf("The number is %d\n", number);
return 0;
}
If you don't supply a command line argument then stdin will be read as normal, but if you do specify a file name then this will be used in place of stdin, e.g.
$ ./my_program # reads from stdin
$ ./my_program numbers.csv # reads from numbers.csv
As described above in the original answer (left for posterity, in case this bug gets fixed in Xcode 7 or later) you can set the command line argument in the Edit Scheme... dialog:
As also noted above you should also set the working directory appropriately - I usually set it to $(PROJECT_DIR), so that it's at the project root directory, but you can set it to anything you like:

Why is the data write not reflected to the file using fprintf file stream

This is my program:
#include <stdio.h>
int main() {
FILE *logh;
logh = fopen("/home/user1/data.txt", "a+");
if (logh == NULL)
{
printf("error creating file \n");
return -1;
}
// write some data to the log handle and check if it gets written..
int result = fprintf(logh, "this is some test data \n");
if (result > 0)
printf("write successful \n");
else
printf("couldn't write the data to filesystem \n");
while (1) {
};
fclose(logh);
return 0;
}
When i run this program, i see that the file is getting created but it does not contain any data. what i understand i that there is data caching in memory before the data is actually written to the filesystem to avoid multiple IOs to increase performance. and I also know that i can call fsync/fdatasync inside the program to force a sync. but can i force the sync from outside without having to change the program?
I tried running sync command from Linux shell but it does not make the data to appear on the file. :(
Please help if anybody knows any alternative to do the same.
One useful information: I was researching some more on this and finally found this, to remove internal buffering altogether, the FILE mode can be set to _IONBF using int setvbuf(FILE *stream, char *buf, int mode, size_t size)
The IO functions usingFILE pointers cache the data to be written in an internal buffer within the program's memory until they decide to perform a system call to 'really' write it (which is for normal files usually when the size of the data cached reaches BUFSIZ).
Until then, there is no way to force writing from outside the progam.
The problem is that your program does not close the file because of your while statement. Remove these lines:
while (1) {
};
If the intent is to wait forever, then close the file with fclose before executing the while statement.

Open a file for edit with $EDITOR variable from a C program

I'm writing a C program and I want to open a file with the $EDITOR variable to make changes to it.
Assuming that I already checked if the $EDITOR is not set and that the part missing is to open the file for edit, is execl() the best option or should I use a different function?
I'm working under Arch linux.
Provided you are reasonably sure that you are in a single-threaded program, you have standard input and standard output (and probably standard error too) going to a terminal, and you aren't going to be upset by the signal handling imposed on you by system(), you can use system() to execute the command via a shell.
If you don't want to trust system(), then one of the exec*() family of functions (plus fork()) will do what you need. You still need to be reasonably sure about the standard I/O channels — some editors do not react well to being given random files or piped input. You get to choose what signal handling to use — and how it is installed. You can get to deal with any thread-safety issues. It is a moderate amount of work.
You probably want to think carefully about whether you give the user the 'real' file to edit or a copy of it. Your code should probably recognize whether the editor exited successfully (and should probably ignore the output file if it did not exit successfully). You may also want to check whether the new version of the file is sensibly sized (not zero bytes, for example — but maybe that doesn't matter; it depends on the context). If the file being edited is a precious configuration file, you worry about this; if it is some previous commands to be re-executed (a history mechanism), you worry less about some of these details.
This is the history 'edit' command in a program of mine. It allows a user to specify a range of commands to be copied into a file, which is then edited, and the result (which may be empty) is then executed. It is code verbatim. Most of the function calls are to program-specific functions, but most of the names should be interpretable (I think). The ctxt_*() family of functions handle 'context', the current settings for the program. It works with more environment variables than yours needs to. The sql_file() function executes the commands from the input file in the current context — this code creates a new context in which to run the commands.
/* Edit history command(s) */
static void do_edit(char *s)
{
FILE *fp;
long c1;
long c2;
char tmpfname[BUFSIZ];
char sys[BUFSIZ];
const char *editor;
if (ctxt_gethistory() != OP_ON)
{
cmd_warning(E_HISTORYOFF, "");
return;
}
s = skipblanks(s);
c1 = c2 = 0;
if (sscanf(s, "%ld%ld", &c1, &c2) != 2)
c2 = c1;
if ((fp = fopen_namedtmpfile(tmpfname, sizeof(tmpfname))) == 0)
{
cmd_warning(E_FAILCREATETMPFILE, "");
return;
}
hist_output(fp, c1, c2, H_COMMAND);
fclose(fp);
if ((editor = getenv("DBEDIT")) == NIL(char *) &&
(editor = getenv("VISUAL")) == NIL(char *) &&
(editor = getenv("EDITOR")) == NIL(char *))
editor = DEF_EDITOR;
esnprintf(sys, sizeof(sys), "%s %s", editor, tmpfname);
system(sys);
fp = fopen(tmpfname, "r");
unlink(tmpfname);
if (fp == 0)
{
cmd_warning(E_FAILREOPENTMPFILE, tmpfname);
}
else
{
/* Copy file to history log */
if ((c1 = hist_input(fp)) > 0)
cmd_set_promptnum(c1);
fseek(fp, 0L, SEEK_SET);
ctxt_newcontext();
ctxt_newinput(fp, "<<temp>>");
ctxt_sethistory(op_off);
sql_file();
ctxt_endcontext();
}
}

Resources