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:
I'm trying to make a program that gets a process name, finds it's ID,
and then finds the language with the function GetKeyboardLayout.
Although I'm having difficulties and it seem not to work.
It finds the processID although the language that return is always 00000000.
That is my code :
#include <iostream>
#include <windows.h>
#include <string>
#include <tlhelp32.h>
DWORD FindProcessId(LPCTSTR ProcessName);
int main() {
HKL currentKBLayout;
DWORD processID;
LPCTSTR processName = "chrome.exe";
while (true) {
processID = FindProcessId(processName);
if (processID == 0); // TODO: pause system for 5 seconds
else {
currentKBLayout = GetKeyboardLayout(processID);
std::cout << processID << " | "<< currentKBLayout << std::endl;
}
}
system("pause");
return 0;
}
DWORD FindProcessId(LPCTSTR ProcessName)
{
PROCESSENTRY32 pt;
HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hsnap, &pt)) { // must call this first
do {
if (!lstrcmpi(pt.szExeFile, ProcessName)) {
CloseHandle(hsnap);
return pt.th32ProcessID;
}
} while (Process32Next(hsnap, &pt));
}
CloseHandle(hsnap); // close handle on failure
return 0;
}
I agree with Remys comment about using a simpler way to get the keyboard layout for the processes if that's all you need. If you however are interested in adding more information to your current approach using snapshots, this could be a way to start. It takes a snapshot of all processes and threads. Each Process has a vector of Thread objects. Adding Thread objects to each Process is done via an unordered_map<processId, Process>. To get a unique set of keyboard layouts for each process (since each thread may in theory have its own), an unordered_set<HKL> is used.
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <windows.h>
#include <tlhelp32.h>
struct Thread {
DWORD m_id;
HKL m_keyboard_layout;
Thread(DWORD Id) :
m_id(Id), m_keyboard_layout(GetKeyboardLayout(m_id))
{}
};
struct Process {
std::vector<Thread> m_threads;
DWORD m_id;
std::wstring m_exefile;
Process() = default;
Process(DWORD Id, std::wstring Name) :
m_id(Id), m_exefile(Name)
{}
// get a unique set of HKL:s from all the threads in the process
std::unordered_set<HKL> GetKeyboardLayouts() const {
std::unordered_set<HKL> rv;
for (auto& t : m_threads) {
if(t.m_keyboard_layout) // does it have a keyboard layout?
rv.emplace(t.m_keyboard_layout);
}
return rv;
}
// if you'd like to iterate over the individual threads
std::vector<Thread>::iterator begin() { return m_threads.begin(); }
std::vector<Thread>::iterator end() { return m_threads.end(); }
};
class Snapshot {
HANDLE hSnap;
std::unordered_map<DWORD, Process> m_processes;
void GetProcesses() {
PROCESSENTRY32 pt;
pt.dwSize = sizeof(pt);
if (Process32First(hSnap, &pt)) { // must call this first
do {
m_processes[pt.th32ProcessID] = Process(pt.th32ProcessID, pt.szExeFile);
} while (Process32Next(hSnap, &pt));
}
}
void GetThreads() {
THREADENTRY32 pt;
pt.dwSize = sizeof(pt);
if (Thread32First(hSnap, &pt)) { // must call this first
do {
m_processes[pt.th32OwnerProcessID].m_threads.emplace_back(pt.th32ThreadID);
} while (Thread32Next(hSnap, &pt));
}
}
void Populate() {
GetProcesses();
GetThreads();
}
public:
Snapshot() :
hSnap(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0)),
m_processes()
{
// TODO: make this exception better
if (hSnap == INVALID_HANDLE_VALUE) throw GetLastError();
Populate();
CloseHandle(hSnap);
}
std::unordered_map<DWORD, Process>::iterator begin() { return m_processes.begin(); }
std::unordered_map<DWORD, Process>::iterator end() { return m_processes.end(); }
};
int main() {
Snapshot snap;
// show processes with keyboard layouts
for (const auto& m : snap) { // std::pair m.first = processId, m.second = Process
const Process& p = m.second;
auto layouts = p.GetKeyboardLayouts();
if (layouts.size()) { // only show processes with keyboard layouts
std::wcout << p.m_id << L" " << p.m_exefile << L"\n";
for (const auto& l : layouts) {
std::wcout << L" layout " << l << L"\n";
}
}
}
return 0;
}
My goal is to read write operations from a chosen drive (usually C), using USN journal.
In the next code I've written, I made a small class that processes USN records by using DeviceIoControl
with the FSCTL_QUERY_USN_JOURNAL and FSCTL_ENUM_USN_DATA codes.
#include "stdafx.h"
#include <stdio.h>
#include <assert.h>
#include <vector>
#include <system_error>
#include <Windows.h>
[[noreturn]] void throw_system_error(int error_code) {
throw std::system_error(error_code, std::system_category());
}
class usn_journal {
private:
HANDLE m_drive_handle;
std::vector<uint8_t> m_buffer;
USN_JOURNAL_DATA* m_usn_journal_data;
USN m_next_usn_record_id;
public:
usn_journal(const wchar_t* driver_name) {
m_next_usn_record_id = 0;
m_drive_handle = ::CreateFileW(
driver_name,
GENERIC_READ,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_ALWAYS,
FILE_FLAG_NO_BUFFERING,
nullptr);
if (m_drive_handle == INVALID_HANDLE_VALUE) {
throw_system_error(::GetLastError());
}
m_buffer.resize(1024 * 1024);
}
~usn_journal() {
::CloseHandle(m_drive_handle);
}
void refresh_jounral() {
assert(m_buffer.size() == 1024 * 1024);
DWORD buffer_count = 0;
if (!DeviceIoControl(
m_drive_handle,
FSCTL_QUERY_USN_JOURNAL,
nullptr,
0,
m_buffer.data(),
m_buffer.size(),
&buffer_count,
nullptr)) {
throw_system_error(::GetLastError());
}
m_usn_journal_data =
reinterpret_cast<decltype(m_usn_journal_data)>(m_buffer.data());
}
void process_entries() {
DWORD bytes_read = 0;
MFT_ENUM_DATA_V0 mft_enum_data = {};
mft_enum_data.StartFileReferenceNumber = m_next_usn_record_id;
mft_enum_data.LowUsn = 0;
mft_enum_data.HighUsn = m_usn_journal_data->MaxUsn;
assert(m_buffer.size() == 1024 * 1024);
for (;;){
auto buffer = m_buffer.data();
if (!DeviceIoControl(
m_drive_handle,
FSCTL_ENUM_USN_DATA,
&mft_enum_data,
sizeof(mft_enum_data),
buffer,
m_buffer.size(),
&bytes_read,
nullptr)){
auto error_code = ::GetLastError();
if (error_code == ERROR_HANDLE_EOF) {
return;
}
else {
throw_system_error(::GetLastError());
}
}
m_next_usn_record_id = *reinterpret_cast<USN*>(buffer);
auto buffer_real_begin = buffer + sizeof(USN);
auto usn_cursor = reinterpret_cast<USN_RECORD*>(buffer_real_begin);
int64_t total_usn_buffer_number = bytes_read - sizeof(USN);
while (total_usn_buffer_number >= 0){
total_usn_buffer_number -= usn_cursor->RecordLength;
buffer = reinterpret_cast<uint8_t*>(usn_cursor) + usn_cursor->RecordLength;
usn_cursor = reinterpret_cast<USN_RECORD*>(usn_cursor);
if (usn_cursor->Reason != 0) {
printf("%d\n", (int)usn_cursor->Reason);
}
}
mft_enum_data.StartFileReferenceNumber = m_next_usn_record_id;
}
}
};
int main(int argc, char ** argv){
usn_journal my_journal(L"\\\\?\\c:");
while (true) {
my_journal.refresh_jounral();
my_journal.process_entries();
}
return 0;
}
Here is my problem, after a while, the records are exhausted, and calling DeviceIoControl and FSCTL_ENUM_USN_DATA
DeviceIoControl fails and the error code I get is ERROR_HANDLE_EOF, even if I refresh the journal, I get the same error.
I want to be able to stream any new USN record, and handle write events. I know for sure it's possible as there are
third party tools which present USN records non-stop.
how can reproduce this state of non-stop streaming?
IsProcessRunning returns always false, why? notepad is 100% running! I even tried the built version but still not working... It's strange, I can't find a solution via Google :/
#include <iostream>
#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>
using namespace std;
bool IsProcessRunning(const wchar_t *processName)
{
bool exists = false;
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry))
while (Process32Next(snapshot, &entry))
if (!wcsicmp(entry.szExeFile, processName))
exists = true;
CloseHandle(snapshot);
return exists;
}
int main()
{
if(IsProcessRunning(L"notepad"))
{
cout << "Notepad running!";
}
else
{
cout << "Notepad not running!";
}
cin.get();
return 0;
}
should be "Notepad.exe"
#include <iostream>
#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>
using namespace std;
bool IsProcessRunning(const wchar_t* processName) {
bool exists = false;
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry))
while (Process32Next(snapshot, &entry)) {
wcout << entry.szExeFile << endl;
if (!wcsicmp(entry.szExeFile, processName))
exists = true;
}
CloseHandle(snapshot);
return exists;
}
int main() {
if (IsProcessRunning(L"notepad.exe")) {
cout << "Notepad running!";
} else {
cout << "Notepad not running!";
}
cin.get();
return 0;
}
I'm having a problem when trying to run the following code:
#include "header.h"
int main()
{
id = GetCurrentProcessId();
EnumWindows(hEnumWindows, NULL);
Sleep(5000);
//MoveWindow(hThis, 450, 450, 100, 100, TRUE);
system("pause");
return 0;
}
//header.h
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <Windows.h>
using namespace std;
DWORD id = 0;
HWND hThis = NULL;
BOOL CALLBACK hEnumWindows(HWND hwnd, LPARAM lParam)
{
DWORD pid = 0;
pid = GetWindowThreadProcessId(hwnd, NULL);
if (pid == id)
{
hThis = GetWindow(hwnd, GW_OWNER);
if (!hThis)
{
cout << "Error getting window!" << endl;
}
else
{
char *buffer = nullptr;
int size = GetWindowTextLength(hThis);
buffer = (char*)malloc(size+1);
if (buffer != nullptr)
{
GetWindowText(hThis, buffer, size);
cout << pid << ":" << buffer << endl;
free(buffer);
}
}
}
return TRUE;
}
When I run this code nothing is output to the screen almost as if the program is not attached. I tried running it under a console and windows subsystem in VS2013.
According to the GetCurrentProcessId docs, the API
Retrieves the process identifier of the calling process.
GetWindowThreadProcessId, on the other hand,
Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window.
The return value is the identifier of the thread that created the window.
So looking at your call:
pid = GetWindowThreadProcessId(hwnd, NULL);
You're actually getting back a thread ID, not a process ID. So when you compare pid to id, you're comparing a process ID and a thread ID, and that's just not going to work. Try this instead:
GetWindowThreadProcessId(hwnd, &pid);
(Note: I can't actually test whether this works, since EnumWindows requires a top-level window to enumerate and I ran this as a console app. Let me know if this answer doesn't work for you and I'll delete it.)
(As a second note, you don't need to use NULL anymore, even for WinAPI stuff like HWND. nullptr will work perfectly fine.)
I assume you're trying to find the "Main" window from the ProcessID.. In that case, this MAY help:
#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <Windows.h>
struct WindowHandleStructure
{
unsigned long PID;
HWND WindowHandle;
};
BOOL CALLBACK EnumWindowsProc(HWND WindowHandle, LPARAM lParam)
{
unsigned long PID = 0;
WindowHandleStructure* data = reinterpret_cast<WindowHandleStructure*>(lParam);
GetWindowThreadProcessId(WindowHandle, &PID);
if (data->PID != PID || (GetWindow(WindowHandle, GW_OWNER) && !IsWindowVisible(WindowHandle)))
{
return TRUE;
}
data->WindowHandle = WindowHandle;
return FALSE;
}
HWND FindMainWindow(unsigned long PID)
{
WindowHandleStructure data = { PID, nullptr };
EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&data));
return data.WindowHandle;
}
int main()
{
HWND Window = FindMainWindow(GetCurrentProcessId());
std::wstring Buffer(GetWindowTextLength(Window) + 1, L'\0');
GetWindowText(Window, &Buffer[0], Buffer.size());
std::wcout << Buffer.c_str() << L"\n";
system("pause");
return 0;
}