After improving the previous post, I came up with the following program:
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <string>
using std::wcout;
using std::wcerr;
using std::wstring;
using std::wstringstream;
static const DWORD BAD_PRIORITY_CLASS_SELECTION = 0xffff0000;
static void MyPrintHelp();
static bool MyAttemptToChangeProcessPriorityClass(DWORD pid,
DWORD priorityClassFlag);
static bool MyCheckPriorityClassSelection(DWORD priorityClassSelection);
static DWORD MyConvertPriorityClassSelectionToFlag(DWORD priorityClassSelection);
static wstring MyConvertProcessClassFlagToString(DWORD priorityClassFlag);
int wmain(int argc, const wchar_t** args) {
if (argc != 3) {
::MyPrintHelp();
return 0;
}
DWORD pid;
DWORD priorityClassFlag;
DWORD priorityClassSelection;
// Read the PID and the process priority class selection:
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;
}
// Once here, reading and parsing the PID and the priority class succeeded:
if (!::MyCheckPriorityClassSelection(priorityClassSelection)) {
// Here, the priority class selection is out of bounds:
wcerr << L"Error: bad priority class selection: "
<< priorityClassSelection
<< L". Must be between 0 and 5, inclusively.\n";
return EXIT_FAILURE;
}
// Get the WinAPI flag for the selected priority class:
priorityClassFlag =
::MyConvertPriorityClassSelectionToFlag(priorityClassSelection);
if (priorityClassFlag == BAD_PRIORITY_CLASS_SELECTION) {
wcerr << L"Error: unknown priority class selection: "
<< priorityClassSelection
<< L"\n";
return EXIT_FAILURE;
}
return ::MyAttemptToChangeProcessPriorityClass(pid, priorityClassFlag) ?
EXIT_SUCCESS :
EXIT_FAILURE;
}
static void MyPrintHelp() {
wcout << L"prioset.exe PID PRIORITY_CLASS\n"
<< L"Where PRIORITY_CLASS is one of:\n"
<< L" 0 - IDLE_PRIORITY_CLASS\n"
<< L" 1 - BELOW_NORMAL_PRIORITY_CLASS\n"
<< L" 2 - NORMAL_PRIORITY_CLASS\n"
<< L" 3 - ABOVE_NORMAL_PRIORITY_CLASS\n"
<< L" 4 - HIGH_PRIORITY_CLASS\n"
<< L" 5 - REALTIME_PRIORITY_CLASS\n"
<< L" REALTIME_PRIORITY_CLASS requires administrator "
<< L"privileges.\n";
}
static 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::wstring:
wstring message(messageBuffer, size);
// Free the Win32's string's buffer:
::LocalFree(messageBuffer);
return message;
}
static bool MyAttemptToChangeProcessPriorityClass(DWORD pid, DWORD priorityClassFlag) {
HANDLE processHandle =
::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION,
false,
pid);
if (processHandle == NULL) {
wcout << L"Error: could not open a process with PID " << pid << "\n";
return false;
}
DWORD oldPriorityClass = ::GetPriorityClass(processHandle);
if (oldPriorityClass == 0) {
DWORD errorCode = ::GetLastError();
wcerr << L"Error: "
<< ::GetLastErrorAsString(errorCode)
<< L"Error code: "
<< errorCode
<< L"\n";
::CloseHandle(processHandle);
return false;
}
if (!::SetPriorityClass(processHandle, priorityClassFlag)) {
DWORD errorCode = ::GetLastError();
wcerr << L"Error: "
<< ::GetLastErrorAsString(errorCode)
<< L"Error code: "
<< errorCode
<< L"\n";
::CloseHandle(processHandle);
return false;
}
DWORD newPriorityClass = ::GetPriorityClass(processHandle);
if (newPriorityClass == 0) {
DWORD errorCode = ::GetLastError();
wcerr << L"Error: "
<< ::GetLastErrorAsString(errorCode)
<< L"Error code: "
<< errorCode
<< L"\n";
::CloseHandle(processHandle);
return false;
}
::CloseHandle(processHandle);
if (newPriorityClass == oldPriorityClass) {
wcout << L"The requested priority class is the same "
<< L"as the current priority class ("
<< ::MyConvertProcessClassFlagToString(newPriorityClass)
<< L").\n";
return true;
}
if (newPriorityClass == priorityClassFlag) {
wcout << L"Successfully changed the priority class from "
<< ::MyConvertProcessClassFlagToString(oldPriorityClass)
<< L" ("
<< oldPriorityClass
<< L") to "
<< ::MyConvertProcessClassFlagToString(newPriorityClass)
<< L" ("
<< newPriorityClass
<< L")\n";
} else {
wcout << L"Warning: Could not change the priority class from "
<< ::MyConvertProcessClassFlagToString(oldPriorityClass)
<< L" ("
<< oldPriorityClass
<< L") to "
<< ::MyConvertProcessClassFlagToString(priorityClassFlag)
<< L" ("
<< priorityClassFlag
<< L"). Instead, "
<< ::MyConvertProcessClassFlagToString(newPriorityClass)
<< L" ("
<< newPriorityClass
<< L") is used as a new priority class.\n";
}
return true;
}
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:
return BAD_PRIORITY_CLASS_SELECTION;
}
}
static wstring MyConvertProcessClassFlagToString(DWORD priorityClassFlag) {
switch (priorityClassFlag) {
case IDLE_PRIORITY_CLASS:
return L"IDLE_PRIORITY_CLASS";
case BELOW_NORMAL_PRIORITY_CLASS:
return L"BELOW_NORMAL_PRIORITY_CLASS";
case NORMAL_PRIORITY_CLASS:
return L"NORMAL_PRIORITY_CLASS";
case ABOVE_NORMAL_PRIORITY_CLASS:
return L"ABOVE_NORMAL_PRIORITY_CLASS";
case HIGH_PRIORITY_CLASS:
return L"HIGH_PRIORITY_CLASS";
case REALTIME_PRIORITY_CLASS:
return L"REALTIME_PRIORITY_CLASS";
default:
return L"BAD_PRIORITY_CLASS";
}
}
Critique request
Please tell me anything that comes to mind.