c++ execute system function in thread - c++

When I execute system in a thread, nothing happens. Is there a solution?
#include <iostream>
#include <Windows.h>
using namespace std;
void runffplay()
{
const char* _cmd = "ffplay -fs -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"";
system(_cmd);
}
CloseHandle(CreateThread(0, 0, (PTHREAD_START_ROUTINE)runffplay, 0, 0, 0));

Your runffplay() function has the wrong signature, so you are going to end up corrupting the thread's call stack. Read the CreateThread() and ThreadProc documentations.
Also, you are not doing any error handling.
Try something more like this instead:
#include <iostream>
#include <cstdlib>
#include <Windows.h>
DWORD WINAPI runffplay(LPVOID)
{
// instead of system(), consider using exec..(), or CreateProcess() directly...
const char* _cmd = "ffplay -fs -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"";
int ret = std::system(_cmd);
std::cout << "system() returned " << ret << std::endl;
return 0;
}
HANDLE hThread = CreateThread(NULL, 0, runffplay, NULL, 0, NULL);
if (!hThread) {
DWORD err = GetLastError();
std::cerr << "CreateThread() failed with error " << err << std::endl;
}
else {
...
CloseHandle(hThread);
}
Otherwise, use std::thread instead of CreateThread() directly:
#include <iostream>
#include <thread>
#include <cstdlib>
void runffplay()
{
// instead of system(), consider using exec..(), or CreateProcess() directly...
const char* _cmd = "ffplay -fs -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"";
int ret = std::system(_cmd);
std::cout << "system() returned " << ret << std::endl;
}
std::thread thrd;
try {
thrd = std::thread(runffplay);
}
catch (const std::system_error &e) {
std::cerr << "thread failed with error " << e << std::endl;
}
...
if (thrd.joinable()) {
thrd.join();
}

Use CreateProcess to get the expected result
#include <iostream>
#include <Windows.h>
using namespace std;
HWND ffplayw = 0;
void SetWallpaper()
{
while (ffplayw == 0)
{
ffplayw = FindWindowW(L"SDL_app", 0);
Sleep(10);
}
}
int main()
{
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
if (CreateProcess(L"D:\\my-tools\\ffmpeg\\bin\\ffplay.exe",
(LPWSTR)L" -fs -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"",
0, 0, 0, 0, 0, 0, &info, &processInfo))
{
// WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
Sleep(500);
SetWallpaper();
}
return 0;
}
this is okay too:
CreateProcess(
L"C:\\Windows\\System32\\cmd.exe",
(LPWSTR)L" /c ffplay -loop 0 \"D:\\dynamic wallpaper\\1.mp4\"",
0, 0, 0, 0, 0, 0, &info, &processInfo)

Related

WinApi SpinLock method for two Processes

I have a question regarding Win32 API process treatment.
I have two processes. Process 1, before starting, must run process 2, which waits for the same resource as process 1. It is a .txt file with some integer values. It means that Process1 should be started FIRST and run Process2. The Process1 MUST be completed after Process2.
It should work as followig:
1.Process1 is created.
2.Process 1 is blocked.
3.Process 2 is created and excecuted.
4.Process 1 is unlocked and executed.
5.Process 2 ends.
6.Process 1 ends.
I searched here for a question similar to mine, I've found only the link below, where a SpinLock class is presented:
C++11 Implementation of Spinlock using <atomic>
The issue is to implement it correctly, I've deleted my incorrect implementations of SpinLock methods from main() function.
It was almost impossible to find any example of using this method in practice, hence I am asking this question to have a look on it:
#include <iostream>
#include <Windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <pthread.h>
#include <atomic>
using namespace std;
class SpinLock {
atomic_flag locked = ATOMIC_FLAG_INIT ;
public:
void lock() {
while (locked.test_and_set(memory_order_acquire)) { ; }
}
void unlock() {
locked.clear(memory_order_release);
}
};
int main( int argc, TCHAR *argv[] )
{
//process 1 generates N random values between 1 and 100,then saves it to txt file i argv[1] stores quanity of values, which will be saved to file
STARTUPINFO si = {};
si.cb = sizeof si;
SpinLock SpinLockVar;
PROCESS_INFORMATION pi = {};
const TCHAR* target1 = _T("C:\\USERS\\Admin\\Documents\\File1.exe"); //process 1
const TCHAR* target2 = _T("C:\\USERS\\Admin\\Documents\\File2.exe");
//Process 1 , before starting generating values and saving them to file, runs Process2,which is awaiting for access to txt file (SPINLOCK ).
//Process 1 is terminating after finishing Process 2
if ( !CreateProcess(target1,GetCommandLine(), 0, FALSE, 0, 0, 0, 0, &si, &pi) )
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
WaitForSingleObject(pi.hProcess, INFINITE);
if ( PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0) ) // Good
cout << "Request to terminate process has been sent!";
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
if ( !CreateProcess(target2,0, 0, FALSE, 0, 0, 0, 0, &si, &pi) )
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
WaitForSingleObject(pi.hProcess, INFINITE);
/*
if ( TerminateProcess(pi.hProcess, 0) ) // Evil
cout << "Process terminated!";
*/
if ( PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0) ) // Good
cout << "Request to terminate process has been sent!";
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
cin.sync();
cin.ignore();
return 0;
}
UPDATE
I have used mutex function for now, and it works partially - it has a mutex "spinlock" mechanism, although it sometimes displaying very strange. I have randomly the result which I expect and which is generating randomly after running my program - the first line in cmd is from thread which runs process2, the second line is result of process1
Please check my code :
#include <windows.h>
#include <stdio.h>
#include <pthread.h>
#include <tchar.h>
#include <mutex>
#include <iostream>
HANDLE hMutex;
DWORD ThreadProc1(LPVOID* arg)
{
const TCHAR* target = _T("C:\\USERS\\Admin\\Documents\\File2.exe");
PROCESS_INFORMATION pInfo;
STARTUPINFO sInfo = { sizeof(pInfo) };
BOOL res = CreateProcess(target, 0, 0, FALSE, 0, 0, 0, 0, &sInfo, &pInfo); //process2
if (!res) return 1;
WaitForSingleObject(pInfo.hThread, INFINITE);
CloseHandle(pInfo.hThread);
CloseHandle(pInfo.hProcess);
return TRUE;
}
int main(void)
{
PROCESS_INFORMATION pInfo;
STARTUPINFO sInfo = { sizeof(pInfo) };
const TCHAR* target = _T("C:\\USERS\\Admin\\Documents\\File1.exe");
HANDLE hThreads;
DWORD threadID1;
hMutex=CreateMutex(NULL, FALSE, NULL); //create mutex(resources=1)
WaitForSingleObject(hMutex, INFINITE); //process2 call WaitForSingleObject(hmutex) first to get mutex
hThreads=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, &hMutex, 0, &threadID1);
WaitForSingleObject(hMutex,INFINITE);//process1 call WaitForSingleObject(hmutex) and block
BOOL res = CreateProcess(target, GetCommandLine(), 0, FALSE, 0, 0, 0, 0, &sInfo, &pInfo);//process1
if (!res) return 1;
ReleaseMutex(hMutex);// process2 do file operations, and then release mutex
WaitForSingleObject(hMutex,INFINITE);// process1 WaitForSingleObject(hmutex) unblock(resources -1),
ReleaseMutex(hMutex); // then release mutex(resources +1)
CloseHandle(hMutex);
WaitForSingleObject(hThreads,INFINITE);
CloseHandle(hThreads); //process 1 closing thread after process 2 ends
CloseHandle(pInfo.hProcess);
CloseHandle(pInfo.hThread);
return 0;
}
First, I think you don't need to use mutex or Spinlock. You could create process1 with CREATE_SUSPENDED, create process2, wait for process2 to exit, then call ResumeThread(pi1.hThread) although there may be differences in step 4 and 5.
#include <windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, TCHAR* argv[])
{
STARTUPINFO si1 = { 0 }, si2 = { 0 };
si1.cb = sizeof si1;
si2.cb = sizeof si2;
PROCESS_INFORMATION pi1 = { 0 }, pi2 = { 0 };
const TCHAR* target1 = _T("C:\\Users\\drakew\\source\\repos\\Project4\\Debug\\Project4.exe");
const TCHAR* target2 = _T("C:\\Users\\drakew\\source\\repos\\Project6\\Debug\\Project6.exe");
if (!CreateProcess(target1, 0, 0, FALSE, 0, CREATE_SUSPENDED, 0, 0, &si1, &pi1))
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
printf("Process1 is created ...\n");
printf("Process1 is blocked ...\n");
if (!CreateProcess(target2, 0, 0, FALSE, 0, 0, 0, 0, &si2, &pi2))//Process 2 is created and excecuted ...
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
WaitForSingleObject(pi2.hProcess, INFINITE);
printf("Process 2 ends ...\n");
CloseHandle(pi2.hProcess);
CloseHandle(pi2.hThread);
}
ResumeThread(pi1.hThread); //Process 1 is unlocked and executed ...
WaitForSingleObject(pi1.hProcess, INFINITE);
printf("Process 1 ends ...\n");
CloseHandle(pi1.hProcess);
CloseHandle(pi1.hThread);
}
cin.sync();
cin.ignore();
return 0;
}
Then, If you want to block at the specific location of process1, then you have to modify process1 and process2 to keep synchronization.
I use event to implement lock.
Process1:
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hEvent1 = OpenEvent(EVENT_MODIFY_STATE| SYNCHRONIZE, FALSE, L"Global\\MyEvent1");
HANDLE hEvent2 = OpenEvent(EVENT_MODIFY_STATE| SYNCHRONIZE, FALSE, L"Global\\MyEvent2");
printf("process1: step1 ...\n");
SetEvent(hEvent1);
printf("process1: step2 ...\n");
DWORD dwWaitResult = WaitForSingleObject(hEvent2, INFINITE);
switch (dwWaitResult)
{
case WAIT_OBJECT_0:
printf("process1: step4 ...\n");
break;
default:
return FALSE;
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
}
Process2:
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
HANDLE hEvent1 = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, L"Global\\MyEvent1");
HANDLE hEvent2 = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, L"Global\\MyEvent2");
DWORD dwWaitResult = WaitForSingleObject(hEvent1, INFINITE);
switch (dwWaitResult)
{
case WAIT_OBJECT_0:
printf("process2: step3 ...\n");
SetEvent(hEvent2);
break;
default:
return FALSE;
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
return 1;
}
Main Process:
#include <windows.h>
#include <string>
#include <tchar.h>
#include <cstdlib>
#include <mutex>
#include <iostream>
using namespace std;
int main(int argc, TCHAR* argv[])
{
STARTUPINFO si1 = { 0 }, si2 = { 0 };
si1.cb = sizeof si1;
si2.cb = sizeof si2;
PROCESS_INFORMATION pi1 = { 0 }, pi2 = { 0 };
mutex mtx;
HANDLE hEvent1 = CreateEvent(NULL, FALSE, FALSE, L"Global\\MyEvent1");
HANDLE hEvent2 = CreateEvent(NULL, FALSE, FALSE, L"Global\\MyEvent2");
const TCHAR* target1 = _T("C:\\path\\process1.exe");
const TCHAR* target2 = _T("C:\\path\\process2.exe");
if (!CreateProcess(target1, 0, 0, FALSE, 0, 0, 0, 0, &si1, &pi1))
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
if (!CreateProcess(target2, 0, 0, FALSE, 0, 0, 0, 0, &si2, &pi2))
{
cerr << "CreateProcess failed (" << GetLastError() << ").\n";
}
else
{
WaitForSingleObject(pi2.hProcess, INFINITE);
printf("process2: step5 ...\n");
CloseHandle(pi2.hProcess);
CloseHandle(pi2.hThread);
}
WaitForSingleObject(pi1.hProcess, INFINITE);
printf("process1: step6 ...\n");
CloseHandle(pi1.hProcess);
CloseHandle(pi1.hThread);
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
cin.sync();
cin.ignore();
return 0;
}
Result:

How to get result of a thread in C++

I have written a function which It is doing the Fibonacci calculation. I wanted to start and execute it with CreateThread as a thread. Finally, I want to save the result of the thread (the Fibonacci) and show it in the console. What is the problem with my code? It doesn't work properly. It starts the thread, but I don't know how should I store the result of the thread and show it.
#include <Windows.h>
#include <iostream>
DWORD WINAPI Fibonacci(LPVOID arg_repeat) {
DWORD dwValue = *(int*)arg_repeat;
if (dwValue < 3)
return 1;
return Fibonacci((int*)dwValue - 1) + Fibonacci((int*)dwValue - 2);
}
auto main(int argc, const char* argv[]) -> decltype(0) {
DWORD dwFibonacciValue;
std::cout << "Fibonacci Value: ";
std::cin >> dwFibonacciValue;
DWORD dwThreadId;
HANDLE hThreading = CreateThread(NULL, 0, Fibonacci, &dwFibonacciValue, NULL, &dwThreadId);
WaitForSingleObject(hThreading, INFINITE);
std::cout << "Fibonacci Result: " << dwResult << std::endl;
CloseHandle(hThreading);
return 0;
}
Your code is wrong beause (int*)dwValue - 1 is not a valid pointer.
You should separate the thread function from the fibonacci function. There will be much less dubious and wrong casts and code will be much clearer:
#include <Windows.h>
#include <iostream>
// Clean and easy to read fibonacci function without fancy casts
DWORD Fibonacci(DWORD dwValue) {
if (dwValue < 3)
return 1;
return Fibonacci(dwValue - 1) + Fibonacci(dwValue - 2);
}
// Thread function
DWORD WINAPI Thread(LPVOID arg_repeat) {
return Fibonacci(*(DWORD*)arg_repeat); // the only cast int the whole code
}
int main(int argc, const char* argv[]) -> decltype(0) {
// it's 'int main', not 'auto main'
DWORD dwFibonacciValue;
std::cout << "Fibonacci Value: ";
std::cin >> dwFibonacciValue;
DWORD dwThreadId;
HANDLE hThreading = CreateThread(NULL, 0, Thread, &dwFibonacciValue, 0, &dwThreadId);
WaitForSingleObject(hThreading, INFINITE);
// get return value of the thread (your actual question)
DWORD dwResult;
GetExitCodeThread(hThreading, &dwResult);
std::cout << "Fibonacci Result: " << dwResult << std::endl;
CloseHandle(hThreading);
return 0;
}
There is no error check whatsoever in this code for clarity.
Other detail:
CreateThread(NULL, 0, Thread, &dwFibonacciValue, NULL, &dwThreadId);
// ^ you should provide a DWORD
// here and not a pointer
should be
CreateThread(NULL, 0, Thread, &dwFibonacciValue, 0, &dwThreadId);

Example of using a semaphore and console output

I wrote a simple example of using a semaphore, but sometimes messages from the first thread are not displayed. What the problem?
#include <iostream>
#include <windows.h>
#include <process.h>
HANDLE Semaphore;
void test1(void*) {
WaitForSingleObject(Semaphore, INFINITE);
std::cout << "Thread1: access granted";
_endthread();
}
void test2(void*) {
ReleaseSemaphore(Semaphore, 1, NULL);
_endthread();
}
int main() {
Semaphore = CreateSemaphore(NULL, 0, 1, NULL);
_beginthread(test1, 2048, NULL);
_beginthread(test2, 2048, NULL);
CloseHandle(Semaphore);
}

C++ get child process id from parent process id

In windows 10, if i create a process to open calc.exe first its trigger calc.exe and exit that process after that it opens calculator.exe. How can i get actual process id that shows in task manager.
i am using following code to create the process and display process id
if(!CreateProcess(("C:\\WINDOWS\\system32\\calc.exe"),
NULL,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&startup_info,
&pi) )
{
args.GetReturnValue().Set(Nan::New(response).ToLocalChecked());
}
else
{
int dwPid = GetProcessId(pi.hProcess);
int v = dwPid->Int32Value();
args.GetReturnValue().Set(dwPid);
}
#include <iostream>
#include <vector>
#include <cstring>
#include <windows.h>
#include <tlhelp32.h>
using std::vector;
using std::cout;
using std::endl;
vector<DWORD> pids_from_ppid(DWORD ppid) {
vector<DWORD> pids;
HANDLE hp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hp, &pe)) {
do {
if (pe.th32ParentProcessID == ppid) {
pids.push_back(pe.th32ProcessID);
}
} while (Process32Next(hp, &pe));
}
CloseHandle(hp);
return pids;
}
int main(int argc,char *argv[]) {
if (arc >= 2) {
DWORD ppid = (DWORD)strtoul(argv[1], nullptr, 10);
vector<DWORD> pidVec = pids_from_ppid(ppid);
for (int i = 0; i < pidVec.size(); i++) {
cout << pidVec[i] << endl;
}
}
return 0;
}

How to add a path with spaces as an arguments to CreateProcess batch file?

I am trying to pass an argument with a space in i to a batch file I run via CreateProcess(). How do I specify that the entire object is an argument?
std::wstring args = TEXT("/C \"C:\\setup.bat\" C:\\TEST TEST");
In the example above, my batch file reads the first argument as C:\TEST.
And, this does not work (batch file exits immediately and does not run):
std::wstring args = TEXT("/C \"C:\\setup.bat\" \"C:\\TEST TEST\"");
Here is the entire code:
#include <iostream>
#define WINDOWS_LEAN_AND_MEAN
#include <Windows.h>
#include <strsafe.h>
#include <string>
#include <UserEnv.h>
#include <vector>
#define BUFSIZE 4096
#pragma comment(lib, "userenv.lib")
std::wstring GetEnvString()
{
wchar_t* env = GetEnvironmentStrings();
if (!env)
{
abort();
}
const wchar_t* var = env;
size_t total_len = 0;
size_t len;
while ((len = wcslen(var)) > 0)
{
total_len += len + 1;
var += len + 1;
}
std::wstring result(env, total_len);
FreeEnvironmentStrings(env);
return result;
}
int main()
{
LPVOID env;
if (!CreateEnvironmentBlock(&env, NULL, FALSE))
{
std::cout << "FAILURE" << std::endl;
system("PAUSE");
abort();
}
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(pi));
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
std::wstring program = TEXT("C:\\Windows\\System32\\cmd.exe");
std::wstring args = TEXT("/C");
args.append(TEXT(" \"C:\\setup.bat\""));
args.append(TEXT(" C:\TEST TEST"));
std::vector<wchar_t> buf(args.begin(), args.end());
buf.push_back(0);
if (!CreateProcess(program.c_str(), buf.data(), NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, env, NULL, &si, &pi))
{
std::cout << "FAILURE" << std::endl;
system("pause");
abort();
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
DestroyEnvironmentBlock(env);
if (!CreateEnvironmentBlock(&env, NULL, FALSE))
{
std::cout << "FAILURE" << std::endl;
abort();
}
return 0;
}
the problem is that the /C parameter needs its entire parameter enclosed by quotes (if it contain spaces).
so, instead of cmd /c "c:\setup.bat" "c:\test test", you need cmd /c ""c:\setup.bat" "c:\test test"" (or at least cmd /c "c:\setup.bat "c:\test test"")
Figured it out:
std::wstring args = TEXT("/C");
args.append(TEXT(" \"\"C:\\setup.bat\""));
args.append(TEXT(" \"C:\\TEST TEST\""));
I figure this ends up doing something like: cmd.exe "C:\setup.bat "C:\Test Test""
How about this:
std::wstring args = TEXT("/C \"C:\\setup.bat\" \"C:\\TEST\ TEST\"");