Check for process on multiple platforms? - c++

I'm using Qt, QProcess to launch a process, but there is presently no way to use QProcess to check existing running processes.
I need a way of achieving this on multiple platforms. I have an application name that I want to look up, if its running I want to get it's PID. If it isn't running I will create an instance of it, this last bit I can do.
I'm working on a Mac and so far I've done the following:
pid_t pid = fork();
if ( pid > 0 ) {
int intStatus;
while ( (pid = waitpid(-1, &intStatus, WNOHANG)) == 0) {
system("ps -A");
qDebug() << "Still waiting!";
sleep(20);
}
qDebug() << "Exit Status %d" << WEXITSTATUS(intStatus);
}
The above executes the command and the output is dumped in the console, I need to capture this so I can process it.
Also looking for a way to achieve this on Windows platforms.

On Posix systems, you could capture the output of ps by using popen and then parse it. The popen part looks like this:
#include <iostream>
#include <cstdio>
int main()
{
FILE *f = popen ("ps -A", "r");
char s [1024];
while (fgets (s, sizeof (s), f))
std::cout << s;
pclose (f);
}
Live demo

I'm not sure how to go about this on linux or unix, but here is an example for windows.
int CheckProc(const wchar_t* procName, PROCESSENTRY32 *procEntry)
{
HANDLE hSnap;
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
{
printf("invalid handle value %s", (char*)hSnap);
return -1;
}
procEntry->dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, procEntry))
{
printf("process32first failed");
CloseHandle(hSnap);
return -1;
}
do
{
if(wcscmp(procEntry->szExeFile, procName) == 0)
{
return 1;
}
} while (Process32Next(hSnap, procEntry));
CloseHandle(hSnap);
return 0;
}
int main()
{
PROCESSENTRY32 procEntry;
const wchar_t* procName = L"process name";
CheckProc(procName, &procEntry);
std::cout << "PID: " << procEntry.th32ProcessID;
}

Related

C++ TlHelp32.h program closes after being written to

I was learning how to interact with processes from a channel called "null". I wrote his program and tried to understand how everything worked. But when i executed it the wpm function did work but then the target program immediately closed after it incremented the same variable I was writing to.
Anyways here's the code.
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
HANDLE hProc = NULL;
DWORD ProcId;
bool attatchProc(const char* ProcName)
{
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(PROCESSENTRY32);
auto hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcSnap == INVALID_HANDLE_VALUE)
return false;
while (Process32Next(hProcSnap, &procEntry)) {
std::cout << procEntry.szExeFile << std::endl;
if (!strcmp(ProcName, procEntry.szExeFile)) {
std::cout << "Process Found!\n Heres the Process ID" << procEntry.th32ProcessID << std::endl;
ProcId = procEntry.th32ProcessID;
hProc = OpenProcess(PROCESS_ALL_ACCESS, false, ProcId);
if (hProc == NULL)
std::cout << "Sike you thought lmao" << std::endl;
CloseHandle(hProcSnap);
return true;
}
}
std::cout << "Process not found or other issue";
}
template <class DataType>
void wpm(DataType VarToWrite, DWORD addressToWrite)
{
WriteProcessMemory(hProc, (PVOID)addressToWrite, &VarToWrite, sizeof(DataType), 0);
}
int main()
{
DWORD memAddr = 0x012FF848;
attatchProc((char*)"Testing.exe");
while (1)
{
wpm<int>(68, memAddr);
}
}
You are not using Process32First to get the first entry in the snapshot. Microsoft Docs has a tutorial on how to do it correctly here
If you use the tutorial you can come up with your own version like mine, which includes exactly what you need and nothing else. I use TCHAR in this example so you can either include tchar.h or you can change it to match your coding style.
#include
DWORD GetProcId(const TCHAR* procName)
{
DWORD procId = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(procEntry);
if (Process32First(hSnap, &procEntry))
{
do
{
if (!_tcsicmp(procEntry.szExeFile, procName))
{
procId = procEntry.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &procEntry));
}
}
CloseHandle(hSnap);
return procId;
}
After calling this function you would check if the return is nonzero and then call OpenProcess() using the process id and the memory access permissions you require. If the process handle is nonzero you may then continue to write to the process memory. If you write to the incorrect memory address you will crash the program, so ensure you have the correct address by using the Visual Studio Debugger and comparing what you see against what you see in the target process using another debugger like Cheat Engine.

c++ Pipe Redirection with CreateProcess() issues

I'm attempting to make a remote administrator tool, so I can control my home computer, and I have the server working. I can send commands across the network fine, but I'm having trouble executing them in the cmd. I have tried to use the CreateProcess() function to start the cmd and then write commands through a pipe, and read the result. I would like to do this multiple times without closing the cmd, so that I can use cd, etc.
It seems like it is at least partially working because it prints out the welcome message for the cmd when the startCmd() function is called. After this however, when I try to write commands to the cmd it never gives me any output. When I check the out pipe, it says that it has read 0 bytes, except when it first starts.
Does this mean that I can only execute 1 command, or do I need to manipulate the pipes in some way after using them once, or something else like that? Also, I apologize if the code is sloppy, I have just been trying a bunch of different solutions and I havent been worrying about the cleanliness of my code.
#define BUFSIZE 4096
#define PATHMAX 400
bool running = false;
HANDLE hChildStdInR = NULL;
HANDLE hChildStdInW = NULL;
HANDLE hChildStdOutR = NULL;
HANDLE hChildStdOutW = NULL;
PROCESS_INFORMATION piProcInfo;
void ErrorExit(const char*);
bool startCmd()
{
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&hChildStdOutR, &hChildStdOutW, &saAttr, 0))
ErrorExit("StdoutRd CreatePipe");
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(hChildStdOutR, HANDLE_FLAG_INHERIT, 0))
ErrorExit("Stdout SetHandleInformation");
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&hChildStdInR, &hChildStdInW, &saAttr, 0))
ErrorExit("Stdin CreatePipe");
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(hChildStdInW, HANDLE_FLAG_INHERIT, 0))
ErrorExit("Stdin SetHandleInformation");
char cmdPath[PATHMAX];
STARTUPINFO siStartInfo;
BOOL bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure. This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hChildStdOutW;
siStartInfo.hStdOutput = hChildStdOutW;
siStartInfo.hStdInput = hChildStdInR;
siStartInfo.wShowWindow = SW_HIDE;
siStartInfo.dwFlags |= STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
GetEnvironmentVariableA("ComSpec", cmdPath, sizeof(cmdPath));
// Create the child process.
bSuccess = CreateProcess(
cmdPath,
NULL, // command line (NULL because application itsself is cmd)
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NEW_CONSOLE, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// Close un-needed pipes
/*CloseHandle(hChildStdOutW);
CloseHandle(hChildStdInR);*/ // Doesn't change anything why I uncomment these lines
// If an error occurs, exit the application.
if (!bSuccess)
ErrorExit("CreateProcess");
else
{
// Close handles to the child process and its primary thread. Some applications might keep these handles to monitor the status of the child process, for example.
/*CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);*/
}
return true;
}
bool writeToCmd(const string& s)
{
DWORD dwWritten;
const char* cmd = s.c_str();
return WriteFile(hChildStdInW, cmd, sizeof(cmd), &dwWritten, NULL);
}
bool exec(const string& command)
{
if (!writeToCmd(command)) {
return false;
}
else {
cout << "Succesfully Wrote" << endl;
}
return true;
}
void checkPipe()
{
while (running) {
while (1) {
Sleep(50);
DWORD bytesAvail = 0;
if (!PeekNamedPipe(hChildStdOutR, NULL, 0, NULL, &bytesAvail, NULL)) {
cout << "Failed to call PeekNamedPipe" << endl;
}
if (bytesAvail) {
CHAR buf[BUFSIZE];
DWORD n;
BOOL success = ReadFile(hChildStdOutR, buf, BUFSIZE, &n, NULL);
if (!success || n == 0) {
cout << "Failed to call ReadFile" << endl;
break;
}
string s = string(buf, buf + n);
cout << s << endl;
break;
}
}
}
}
int main(int argc, char** argv)
{
if (argc != 2) {
cout << "Usage: " << argv[0] << " <ADRESS>" << endl;
return 1;
}
ClientSocket client(argv[1], DEFAULT_PORT);
// Wait for initial response
string w = client.recieveLine();
if (w == "welcome") {
cout << "Connection Successful! " << endl;
}
running = true;
if (startCmd()) cout << "Cmd Started" << endl;
thread checkLoop(&checkPipe);
while (true) {
vector<string> command = split(client.recieveLine());
if (command[0] == "run") {
exec(command[1]);
}
else if (command[0] == "exit") {
running = false;
client.sendLine("exit");
break;
}
}
if (!CloseHandle(hChildStdInW))
ErrorExit("StdInWr CloseHandle");
checkLoop.join();
client.close();
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return 0;
}

Create a forked process from a deamon

I want to create a deamon in Linux that needs to kill off another process. I've created the deamon and it works fine, but my second process is created but it does not run as expected.
Is there something that I'm missing in starting the new process?
This is my code
void StartWSDevice()
{
pid_t pid;
int status;
fflush(NULL);
pid = fork();
switch (pid) {
case -1:
perror("fork");
break;
case 0: {
syslog(LOG_NOTICE, "WSDevice started.");
int res = execl("home/pi/projects/WSDevice/bin/ARM/Debug",
"WSDevice.out", (char *)0);
syslog(LOG_NOTICE, "WSDevice return %d.", res);
break;
}
default:
fflush(NULL);
if (waitpid(pid, &status, 0) != -1) {
syslog(LOG_NOTICE, "Child exited with status %i\n", status);
} else {
perror("waitpid");
}
break;
}
}
int main(void) {
deamonize();
syslog(LOG_NOTICE, "WSDeviceService started.");
while (!stopService) {
// Check if my child process is running
int pid_file = open("/var/run/WSDevice.pid",
O_CREAT | O_RDWR, 0666);
int rc = flock(pid_file, LOCK_EX | LOCK_NB);
if (rc) {
if (EWOULDBLOCK == errno) {
}
} else {
StartWSDevice(); // Its not running, start it
}
sleep(30); /* wait 30 seconds */
}
syslog(LOG_NOTICE, "WSDeviceService terminated.");
exit(EXIT_SUCCESS);
}
You're using execl incorrectly. The first argument to execl() is the process to run. The remaining arguments are the contents of the argv array that is passed to the process. The key here is that argv[0] should be the name of the process being run. So:
int res = execl("/home/pi/projects/WSDevice/bin/ARM/Debug/WSDevice.out",
"/home/pi/projects/WSDevice/bin/ARM/Debug/WSDevice.out",
NULL);
Note that I've also inserted / in front of home. This may be important for you. I've also used NULL instead of (char *)0, which is more of a style thing and doesn't change the functionality.

Getting the PID from popen

I have a program that uses popen() in order to open and read the output from a shell command. The problem is, as far as I can tell, there is no easy way to get the PID of the running process, and hence, you can't kill it if it gets stuck. So the question is, how can you retrieve the PID from a process opened with popen?
The solution I came up with (and the general consensus) is to create a new popen function that allows me to retrieve the PID. Since I was unable to find a simple example of this on SO, I wanted to post my implementation in the hopes that it helps somebody else. Feedback and alternate solutions are welcome.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <string>
#include <sstream>
using namespace std;
#define READ 0
#define WRITE 1
FILE * popen2(string command, string type, int & pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == "r")
{
close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[WRITE], 1); //Redirect stdout to pipe
}
else
{
close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[READ], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL);
exit(0);
}
else
{
if (type == "r")
{
close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only
}
}
pid = child_pid;
if (type == "r")
{
return fdopen(fd[READ], "r");
}
return fdopen(fd[WRITE], "w");
}
int pclose2(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}
int main()
{
int pid;
string command = "ping 8.8.8.8";
FILE * fp = popen2(command, "r", pid);
char command_out[100] = {0};
stringstream output;
//Using read() so that I have the option of using select() if I want non-blocking flow
while (read(fileno(fp), command_out, sizeof(command_out)-1) != 0)
{
output << string(command_out);
kill(-pid, 9);
memset(&command_out, 0, sizeof(command_out));
}
string token;
while (getline(output, token, '\n'))
printf("OUT: %s\n", token.c_str());
pclose2(fp, pid);
return 0;
}
CLARIFICATION
I tried to use the defined functions by #Gillespie's answer but found out that the pid in the C/C++ program was different from the one returned by the terminal command pgrep and looking at the output of ps -aux | grep myNameProc it seemed the process of the C program was forked once more.
I think because execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL); is actually equivalent to /bin/sh cmd string. So basically the child process of your C (or C++) program is creating a new process that does /bin/sh yourRealProcess where yourRealProcess is the one specified in the command string.
I solved doing the following: execl(command.c_str(), command.c_str(), (char*)NULL);. However, as specified by #Gillespie in the previous comments, in this way you will not be able to pass arguments to your process.
C IMPLEMENTATION
According to my needs I readapted #Gillespie's functions to include the above discussed modification and to work in the C programming language:
FILE * custom_popen(char* command, char type, pid_t* pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == 'r')
{
close(fd[0]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[1], 1); //Redirect stdout to pipe
}
else
{
close(fd[1]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[0], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl(command, command, (char*)NULL);
exit(0);
}
else
{
printf("child pid %d\n", child_pid);
if (type == 'r')
{
close(fd[1]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[0]); //Close the READ end of the pipe since parent's fd is write-only
}
}
*pid = child_pid;
if (type == 'r')
{
return fdopen(fd[0], "r");
}
return fdopen(fd[1], "w");
}
int custom_pclose(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}

Some problem with serial programming in vc++ mfc

When I connect my embedded device to my system, I am running my program which will write to the port my embedded is connect and it prints the reply to console.
When I connect my device and run this program it is not giving any output.
But when I connect my device and use PUTTY to send some commands first and then run my program it is working.
Maybe there is a problem in the way I am starting communication?
My source code is:
#include "stdafx.h"
#include <iostream>
//#include <windows.h>
#include <afx.h>
int main()
{
using namespace std;
int i=0;
// cout << "Hello world!" << endl;
HANDLE hSerial;
hSerial = CreateFile("COM5",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(hSerial==INVALID_HANDLE_VALUE)
{
if(GetLastError()==ERROR_FILE_NOT_FOUND)
{
// TRACE("serial port does not exist for reading\n");
//serial port does not exist. Inform user.
}
// TRACE("some other error,serial port does not exist for reading\n");
//some other error occurred. Inform user.
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams))
{
// TRACE("error getting state for reading\n");
//error getting state
}
dcbSerialParams.BaudRate=9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams))
{
//TRACE("error setting state for reading\n");
//error setting serial port state
}
COMMTIMEOUTS timeouts={0};
timeouts.ReadIntervalTimeout=50;
timeouts.ReadTotalTimeoutConstant=50;
timeouts.ReadTotalTimeoutMultiplier=10;
timeouts.WriteTotalTimeoutConstant=50;
timeouts.WriteTotalTimeoutMultiplier=10;
if(!SetCommTimeouts(hSerial, &timeouts))
{
// TRACE("some error occured for reading\n");
//error occureed. Inform user
}
int n=100,n1=100;
char szBuff[100];
DWORD dwBytesRead = 0;
char szBuff1[100];
DWORD dwByteswrote = 0;
memset(szBuff1,0,100);
memcpy(szBuff1,"LIST\r",5);
if(!WriteFile(hSerial, szBuff1,5, &dwByteswrote, NULL))
{
cout << "error writing" ;
}
cout << szBuff1 << endl;
cout << dwByteswrote << endl;
while(1)
{
if(!ReadFile(hSerial, szBuff, n1, &dwBytesRead, NULL))
{
cout << "error reading";
break;
}
else
{
cout << dwBytesRead << endl;
szBuff[dwBytesRead]='\0';
if(dwBytesRead>0)
{
cout << (szBuff);
break;
}
}
}
cin >> i;
}
Try this... you will probably need to do the code for exceptions (ex: if the response is bigger than 2024)
bool SendModemATCommand(const string &strCommand, int iModemPort, string &strRetValue)
{
bool bRetValue = false;
strRetValue = "";
char cBuffer[2024];
HANDLE hCom = NULL;
char cComPort[64];
sprintf_s(cComPort,"\\\\.\\COM%d", iModemPort);
hCom = CreateFile( cComPort,
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // no security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // not overlapped I/O
NULL // hTemplate must be NULL for comm devices
);
if (hCom != INVALID_HANDLE_VALUE)
{
COMMTIMEOUTS comTimeOuts;
comTimeOuts.ReadIntervalTimeout = MAXDWORD;
comTimeOuts.ReadTotalTimeoutMultiplier = MAXDWORD;
comTimeOuts.ReadTotalTimeoutConstant = 0;//MAXDWORD;
comTimeOuts.WriteTotalTimeoutMultiplier = 0;
comTimeOuts.WriteTotalTimeoutConstant = 0;
if(SetCommTimeouts(hCom, &comTimeOuts))
{
DCB dcb;
dcb.DCBlength = sizeof(DCB);
if(GetCommState(hCom, &dcb))
{
DWORD dwBytesWritten = 0;
DWORD dwBytesRead = 0;
DWORD dwBytesTotal = 0;
if( WriteFile(hCom, strCommand.c_str(), (int)strCommand.size(), &dwBytesWritten, NULL) )
{
if(dwBytesWritten == strCommand.size())
{
dwBytesRead = 0;
DWORD tickStart = GetTickCount();
bool bTimeOut = false;
while(true)
{
while(ReadFile(hCom, cBuffer + dwBytesTotal, 1, &dwBytesRead, NULL))
{
if(dwBytesRead == 0 && dwBytesTotal != dwBytesWritten)
break;
dwBytesTotal += dwBytesRead;
}
if ( dwBytesTotal == 0 )
{
// timeout
if ( GetTickCount() - tickStart > 10000) // 10 Seconds
{
bTimeOut = true;
break;
}
}
else
break;
}
cBuffer[dwBytesTotal] = '\0';
strRetValue = cBuffer;
if(bTimeOut)
strRetValue = "Timed out:" + strCommand;
else
bRetValue = true;
}
}
}
}
CloseHandle(hCom);
}
return bRetValue;
}
Most likely the problem is with your initialization.
I recall having this type of trouble before and Com Timeouts structure was particularly troublesome.
I suggest you get a null modem cable from COM5 to another port on the machine (if you have one), or to another computer. Then use a terminal program to open up the other port and see you can see the "List" command coming through when you run the program. If not then it's very likely to be related to the way you are initializing & opening the com port.
This link may prove useful. Just strip out the Afx stuff and look particularly at the initialization.
http://www.codeproject.com/KB/system/chaiyasit_t.aspx
One other suggestion, you only send List once. If the device is not already plugged in and ready, nothing will happen. Maybe it should keep sending the list command until it gets a
Response.
Also, do you need "List\r\n" or just "List\r"? What is the other ends expecting?