(See the next iteration .)
I have this program (call it, for example, prioset.exe
), that asks for two command line arguments: (1) the target process PID, (2) a priority class selector in the range 0...5
(as specified in the WinAPI docs, where 0 stands for idle priority class, and 5 for real-time priority class.
My main concern is whether we can pass to dwDesiredAccess
of OpenProcess
more restricted flags than PROCESS_ALL_ACCESS
.
Here's the code:
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <string>
using std::wcout;
using std::wcerr;
using std::wstringstream;
static void MyPrintHelp();
static void MyAttemptToChangeProcessPriorityClass(DWORD pid,
DWORD priorityClass);
static bool MyCheckPriorityClassSelection(DWORD priorityClassSelection);
static DWORD MyConvertPriorityClassSelectionToFlag(DWORD priorityClassSelection);
int wmain(int argc, const wchar_t** args) {
if (argc != 3) {
MyPrintHelp();
return 0;
}
DWORD pid;
DWORD priorityClassSelection;
wstringstream wss;
wss << args[1] << L" " << args[2];
wss >> pid;
if (wss.fail() || wss.eof()) {
wcerr << L"Error: bad PID (" << args[1] << L"\n";
return EXIT_FAILURE;
}
wss >> priorityClassSelection;
if (wss.fail()) {
wcerr << L"Error: bad priority class selector (" << args[2] << L")\n";
return EXIT_FAILURE;
}
if (!MyCheckPriorityClassSelection(priorityClassSelection)) {
wcerr << L"Error: bad priority class selection: "
<< priorityClassSelection
<< L". Must be between 0 and 5, inclusively.\n";
return EXIT_FAILURE;
}
MyAttemptToChangeProcessPriorityClass(
pid,
MyConvertPriorityClassSelectionToFlag(
priorityClassSelection));
}
static void MyPrintHelp() {
wcout << L"prioset.exe PID PRIORITY\n";
}
static std::wstring GetLastErrorAsString(DWORD errorMessageId)
{
LPWSTR messageBuffer = nullptr;
size_t size = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errorMessageId,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR) &messageBuffer, 0, NULL);
//Copy the error message into a std::string.
std::wstring message(messageBuffer, size);
//Free the Win32's string's buffer.
LocalFree(messageBuffer);
return message;
}
static void MyAttemptToChangeProcessPriorityClass(DWORD pid, DWORD priorityClass) {
HANDLE processHandle =
::OpenProcess(PROCESS_ALL_ACCESS,
false,
pid);
if (processHandle == NULL) {
wcout << L"Error: could not open a process with PID " << pid << "\n";
return;
}
DWORD oldPriorityClass = GetPriorityClass(processHandle);
if (oldPriorityClass == 0) {
DWORD errorCode = ::GetLastError();
wcerr << L"Error: "
<< GetLastErrorAsString(errorCode)
<< L"Error code: "
<< errorCode
<< L"\n";
::CloseHandle(processHandle);
return;
}
if (!::SetPriorityClass(processHandle, priorityClass)) {
DWORD errorCode = GetLastError();
wcerr << L"Error: "
<< GetLastErrorAsString(errorCode)
<< L"Error code: "
<< errorCode
<< L"\n";
::CloseHandle(processHandle);
return;
}
DWORD newPriorityClass = GetPriorityClass(processHandle);
if (newPriorityClass == 0) {
DWORD errorCode = ::GetLastError();
wcerr << L"Error: "
<< GetLastErrorAsString(errorCode)
<< L"Error code: "
<< errorCode
<< L"\n";
::CloseHandle(processHandle);
return;
}
::CloseHandle(processHandle);
if (newPriorityClass == priorityClass) {
wcout << L"Successfully changed the priority class from "
<< oldPriorityClass
<< L" to "
<< newPriorityClass
<< L"\n";
} else {
wcout << L"Could not change the priority class from "
<< oldPriorityClass
<< L" to "
<< priorityClass
<< L" Instead, "
<< newPriorityClass
<< L" is used as a new priority class.\n";
}
}
static bool MyCheckPriorityClassSelection(DWORD priorityClassSelection) {
return priorityClassSelection >= 0 || priorityClassSelection < 6;
}
static DWORD MyConvertPriorityClassSelectionToFlag(
DWORD priorityClassSelection) {
switch (priorityClassSelection) {
case 0:
return IDLE_PRIORITY_CLASS;
case 1:
return BELOW_NORMAL_PRIORITY_CLASS;
case 2:
return NORMAL_PRIORITY_CLASS;
case 3:
return ABOVE_NORMAL_PRIORITY_CLASS;
case 4:
return HIGH_PRIORITY_CLASS;
case 5:
return REALTIME_PRIORITY_CLASS;
default:
throw L"Bad priority class selection.";
}
}
```