trying to delete a file in Temp dir using CreateProcessA - c++

Hello I am trying to delete a file using following code:
CreateProcessA(NULL, (LPSTR)"del /f C:\\Users\\samee\\AppData\\Local\\Temp\\tempFile.txt", 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi);
however this is not working. What am doing wrong here?

del is not an executable that you can run directly. It is a built-in command of the cmd.exe shell. So, you would need to run cmd.exe instead, using its /C or /K parameter to execute shell commands, eg:
char cmdLine[] = "cmd.exe /C del /f C:\\Users\\samee\\AppData\\Local\\Temp\\tempFile.txt";
CreateProcessA(NULL, cmdLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
But why do that? The Win32 API has a DeleteFileA() function, you should use that instead, eg:
DeleteFileA("C:\\Users\\samee\\AppData\\Local\\Temp\\tempFile.txt");
Note that the /f parameter of del allows for deleting a read-only file. If DeleteFileA() fails because the file is read-only, then simply remove the read-only flag, eg:
char fileName[] = "C:\\Users\\samee\\AppData\\Local\\Temp\\tempFile.txt";
DWORD attr = GetFileAttributesA(fileName);
if ((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_READONLY))
SetFileAttributesA(fileName, attr & ~FILE_ATTRIBUTE_READONLY);
DeleteFileA(fileName);

Related

Define in C++ new environment variable and use it in bat file

It is very simple, I want to define a new environment variable in C++ using SetEnvironmentVariable, and then call a bat file that use it. This is my c++ code;
PROCESS_INFORMATION processInformation = { 0 };
STARTUPINFO startupInfo = { 0 };
SetEnvironmentVariable("GSDebbugingDir", "Hello");
BOOL result = CreateProcess(NULL,
"dummy.bat"),
NULL,
NULL,
FALSE,
CREATE_NO_WINDOW,
NULL,
NULL,
&startupInfo,
&processInformation);
And my dummy.bat file is :
#echo off
echo GSDebbugingDir = %GSDebbugingDir%
if defined GSDebbugingDir mkdir c:\temp\dummy
pause
But this didn't out the value of GSDebbugingDir variable. What is the problem?
CreateProcess documentation says:
To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file.
Which makes sense because a .bat file by itself is not an executable module by itself.
But, contrary to what the doc says the following code worked for me with UseApplicationName NOT #defined, i.e. with "cmd.exe" placed into commandLine
Also, to see the output of the bat file you probably want to remove that CREATE_NO_WINDOW flag
//#define UseApplicationName
#ifdef UseApplicationName
TCHAR commandLine[] = _T(" /c dummy.bat");
#else
TCHAR commandLine[] = _T("cmd.exe /c dummy.bat");
#endif
BOOL result = CreateProcess(
#ifdef UseApplicationName
_T("cmd.exe"),
#else
NULL,
#endif
commandLine,
NULL,
NULL,
FALSE,
0, //CREATE_NO_WINDOW,
NULL,
NULL,
&startupInfo,
&processInformation);
BTW pay attention that
The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string).

How to execute a command in cmd using CreateProcess?

I'm trying to launch the command line through my c++ program and then have cmd run a command. I'm not sure what I'm doing wrong. I've looked at the MSDN documentation but I'm unable to understand what to change in my code.
Below is the chunk of code that I have written. I'm trying to launch cmd and then run the command in cmdArgs. However, on running the program it just launches the cmd without running the nslookup part of it. I've tried with other commands as well like ipconfig, but they do not get executed. Could someone help me understand what I'm doing wrong.
When I launch the program, it just opens up cmd. What I'm trying to do is have the cmdArgs runs and view the output on the cmd screen.
I'm new to c++, so if this is trivial I apologize. I've looked at other questions on the site, but it seems that the format of cmdArgs is correct - program name followed by the arg.
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
LPTSTR cmdPath = _T("C:\\Windows\\System32\\cmd.exe");
LPTSTR cmdArgs = _T("C:\\Windows\\System32\\cmd.exe nslookup myip.opendns.com. resolver1.opendns.com");
if (!CreateProcess(cmdPath, cmdArgs, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
std::cout << "Create Process failed: " << GetLastError() << std::endl;
return "Failed";
}
Your program does exactly what you asked it to to: you just start the cmd.exe executable. Just test in a console windows:
C:\Users\xxx>start /w cmd ipconfig
C:\Users\xxx>cmd ipconfig
Microsoft Windows [version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. Tous droits réservés.
C:\Users\xxx>exit
C:\Users\xxx>
So cmd.exe ipconfig just pushed a new cmd.exe without executing the remaining of the line. It is then waiting for commands coming from its standard input.
You must use cmd.exe /c ipconfig to ask the new cmd.exe to execute a command, or cmd.exe /K ipconfig if you want cmd not to exit after first command:
C:\Users\serge.ballesta>cmd /c ipconfig
Configuration IP de Windows
...
So you should write in your code:
...
LPTSTR cmdArgs = _T("C:\\Windows\\System32\\cmd.exe /k nslookup myip.opendns.com. resolver1.opendns.com");
...
Try using this:
wchar_t command[] = L"nslookup myip.opendns.com. resolver1.opendns.com";
wchar_t cmd[MAX_PATH] ;
wchar_t cmdline[ MAX_PATH + 50 ];
swprintf_s( cmdline, L"%s /c %s", cmd, command );
STARTUPINFOW startInf;
memset( &startInf, 0, sizeof startInf );
startInf.cb = sizeof(startInf);
PROCESS_INFORMATION procInf;
memset( &procInf, 0, sizeof procInf );
BOOL b = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &startInf, &procInf );
DWORD dwErr = 0;
if( b )
{
// Wait till process completes
WaitForSingleObject( procInf.hProcess, INFINITE );
// Check process’s exit code
GetExitCodeProcess( procInf.hProcess, &dwErr );
// Avoid memory leak by closing process handle
CloseHandle( procInf.hProcess );
}
else
{
dwErr = GetLastError();
}
if( dwErr )
{
wprintf(_T(“Command failed. Error %d\n”),dwErr);
}

grep: input file ">":System cannot find the file specified

when I tried to execute a grep command in c++, I got the following error:
grep: Input file: ">":System cannot find the file specified
Can anyone help me to resolve this?
wchar_t* grepArg= L"\"D:\\grep\" -f \"C:\\Users\\ic014733\\AppData\\Local\\Temp\\patterns.tmp\" \"D:\\LOG2014_10_05.LOG\" >\"D:\\share\\result.txt\"";
if ( !CreateProcessW(NULL, grepArg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) )
{
DWORD errorMessageID = ::GetLastError();
}
else
{
DWORD res = WaitForSingleObject(pi.hProcess, INFINITE);
TerminateProcess(pi.hProcess, 0);
PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0) ;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
You gave the answer in your comment : Error is like, grep considers '>' too as input file. Of course it does! Why should it not?
Let me explain a little: When you write grep -f strings_file file > result at a shell prompt (or cmd prompt under Windows), the shell parses the input line, indentifies the > redirection and processes the redirection:
open result file
start program grep with arguments (or command line for Windows) -f strings_file file and standard output redirected to result
But you are just starting the grep program with all the arguments in its command line, so no redirection can happen.
So what can you do? As none of your path contains spaces, you could just make cmd.exe do the redirection for you :
wchar_t* grepArg= L"cmd.exe /C \"D:\\grep -f C:\\Users\\ic014733\\AppData\\Local\\Temp\\patterns.tmp D:\\LOG2014_10_05.LOG > D:\\share\\result.txt";
That means that you start a new cmd.exe program with two parameters: /c saying execute that and your original command enclosed in quotes. But I never found the way to cleanly include quotes in quotes in Windows. That's the reason why I removed all the inner quotes from your command. It was possible because there was no space in any path.
The alternative would be to do the redirection by hand: open the output file, pass its handle in the hStdOutput member of si and declare it by setting STARTF_USESTDHANDLES in dwFlags member of same struct:
wchar_t* grepArg= L"\"D:\\grep\" -f \"C:\\Users\\ic014733\\AppData\\Local\\Temp\\patterns.tmp\" \"D:\\LOG2014_10_05.LOG\"";
HANDLE hstdout = CreateFile("D:\\share\\result.txt", "GENERIC_WRITE", 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// control hstdout is not null...
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdOutput = hstdout;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); // stdinput and stderr unchanged
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if ( !CreateProcessW(NULL, grepArg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) ) {
...

File re-direction operator ">" doesn't work with CreateProcess() API

I've a SupportApp.EXE which if I launch manually from windows CMD prommpt like this ::
SupportApp.EXE -t 100 > AFile.csv
works perfcetly fine & it generates a CSV file for me.
Now I want to automate same thing inside a VC++ code.
So, I use CreateProcess() API for this.
Code snippet below ::
TCHAR launcher[512];
_tgetcwd(launcher, _MAX_PATH);
TCHAR workDir[512];
_tgetcwd(workDir, _MAX_PATH);
_tcscat(launcher, "\\App\\SupportApp.exe");
TCHAR cmdlineoption[512];
_tcscpy(cmdlineoption, " -t 120 > AFile.csv");
LPTSTR appPath = (LPTSTR)cmdlineoption;
STARTUPINFO sInfo;
memset(&sInfo, 0, sizeof(sInfo));
sInfo.cb = sizeof(sInfo);
sInfo.dwFlags = STARTF_USESHOWWINDOW;
sInfo.wShowWindow = SW_SHOWMAXIMIZED;
PROCESS_INFORMATION pInfo;
memset(&pInfo, 0, sizeof(pInfo));
if (!CreateProcess(launcher, appPath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, workDir, &sInfo, &pInfo))
{
... // log error
}
// success
I see that CreateProcess() API succeeds and also i see that the -t 120 option I'm giving is also taken by this "SupportApp.exe"
BUT the file redirection operator ">" is not working with CreateProcess() API.
Instead the output is directed to CMD itself. But I want output to be sent to a CSV file.
Can anyone please help me in how do I redirect the output of my
"SupportApp.exe" to a file using CreateProcess() API from within my
VC++ code ?
UPDATE 2:
The inputs given by reviewers are incorporated in this & the modified code snippet is below which takes the file hnadle in STARTUPINFO structure as follows::
The file is getting created but the file is empty & it doesn't have any contents from createProcess()?
TCHAR launcher[512];
_tgetcwd(launcher, _MAX_PATH);
TCHAR workDir[512];
_tgetcwd(workDir, _MAX_PATH);
_tcscat(launcher, "\\App\\SupportApp.exe");
TCHAR cmdlineoption[512];
_tcscpy(cmdlineoption, " -t 120 > AFile.csv");
LPTSTR appPath = (LPTSTR)cmdlineoption;
STARTUPINFO sInfo;
memset(&sInfo, 0, sizeof(sInfo));
sInfo.cb = sizeof(sInfo);
sInfo.dwFlags |= STARTF_USESTDHANDLES; //newly added
sInfo.wShowWindow = SW_SHOWMAXIMIZED;
PROCESS_INFORMATION pInfo;
memset(&pInfo, 0, sizeof(pInfo));
sInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
sInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa, sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
HANDLE hn;
if(INVALID_HANDLE_VALUE != (hn = CreateFile(L"DoneDone.csv", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)))
{
sInfo.hStdOutput = =hn;
}
if (!CreateProcess(launcher, appPath, NULL, NULL, FALSE, 0, NULL, workDir, &sInfo, &pInfo))
{
... // log error
}
// success
Output redirection is a shell feature, i.e. the shell sets that up before starting the child.
You're not using a shell, instead going directly to the kernel asking it to start a process, so you don't get that service.
You need to set up the required redirection yourself. This is done in the STARTUPINFO's hStdOutput member. See the documentation, of course.
That's because the redirection operations (as well as the pipe operation) is part of the command prompt program, not part of the CreateProcess call.
However, you can do exactly what the command prompt program does when it does redirection, and set the file handles in the STARTUPINFO structure.

How to hide Matlab Command Window and command prompt from calling system in C++

I execute the Matlab script file using system() which uses the command prompt and it's working fine. But i wish to hide everything and hope it runs in the background and only showing my GUI from the script file. Any idea?
This is my command in MSVS C++ (Note : i cut short the path name for simplicity purposes) :
system("\"\"C:\\matlab.exe\" -nodisplay -nosplash -nodesktop -r \"run('C:\\main.m');\"\"");
You could try CreateProcess instead of system. A simple example:
#include <windows.h>
#include <stdio.h>
int main() {
PROCESS_INFORMATION pi;
STARTUPINFO si = {
sizeof(si),
NULL, NULL, NULL,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
NULL, NULL, NULL, NULL
};
BOOL res = CreateProcess(
NULL,
"C:\\matlab.exe -nodisplay -nosplash -nodesktop -r \"run('C:\\main.m');\"",
NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL,
NULL, // starting directory (NULL means same dir as parent)
&si, &pi
);
if (res == FALSE) printf("CreateProcess failed\n");
return 0;
}
You might be better off using the MATLAB Engine API.