プロセスの優先度を強制的に変更
仕事で少し必要になったので得意じゃないVCを。
OpenProcess()でプロセスのハンドラを取得してSetPriorityClass()で優先度を変更するだけと思っていたのですが、一部のプロセスはアクセス拒否で弾かれてしまいました。サービスプロセスやSYSTEMユーザで起動しているプロセスは変更できないのですね。
でもSysinternal社のProcess Explorer*1だとお構いなしに優先度を変更できるので少し調べたところ、こんな感じでいけるのではなかろうかと。(あってるのか?)
- AdjustTokenPrivileges()で特権をつけて
- OpenProcess()でハンドラを取得して
- SetPriorityClass()で優先度変更
- AdjustTokenPrivileges()の特権を無効
とりあえずゴミコード。ここのMicrosoftサポートオンラインをまるパクリ。
#include "stdafx.h" #include <windows.h> #include <stdio.h> #define RTN_OK 0 #define RTN_USAGE 1 #define RTN_ERROR 13 BOOL SetPrivilege( HANDLE hToken, // token handle LPCTSTR Privilege, // Privilege to enable/disable BOOL bEnablePrivilege // TRUE to enable. FALSE to disable ); void DisplayError(LPTSTR szAPI); int _tmain(int argc, char **argv) { DWORD priority_class = BELOW_NORMAL_PRIORITY_CLASS; DWORD pid; DWORD result = true; HANDLE hProcess; HANDLE hToken; if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)) { if (GetLastError() == ERROR_NO_TOKEN) { if (!ImpersonateSelf(SecurityImpersonation)) return RTN_ERROR; if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)){ DisplayError("OpenThreadToken"); return RTN_ERROR; } } else return RTN_ERROR; } // enable SeDebugPrivilege if(!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE)) { DisplayError("SetPrivilege"); CloseHandle(hToken); return RTN_ERROR; } pid = atoi(argv[1]); if ((hProcess = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid)) == NULL) { DisplayError("OpenProcess"); CloseHandle(hToken); return false; } if (!SetPriorityClass(hProcess, priority_class)) { DisplayError("SetPriorityClass"); result = false; } else { fprintf(stdout,"SetPriorityClass() Success: %d\n", priority_class); } // disable SeDebugPrivilege SetPrivilege(hToken, SE_DEBUG_NAME, FALSE); CloseHandle (hProcess); CloseHandle (hToken); return true; } BOOL SetPrivilege( HANDLE hToken, // token handle LPCTSTR Privilege, // Privilege to enable/disable BOOL bEnablePrivilege // TRUE to enable. FALSE to disable ) { TOKEN_PRIVILEGES tp = { 0 }; // Initialize everything to zero LUID luid; DWORD cb=sizeof(TOKEN_PRIVILEGES); if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; if(bEnablePrivilege) { tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; } else { tp.Privileges[0].Attributes = 0; } AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL ); if (GetLastError() != ERROR_SUCCESS) return FALSE; return TRUE; } void DisplayError( LPTSTR szAPI // pointer to failed API name ) { LPTSTR MessageBuffer; DWORD dwBufferLength; fprintf(stderr,"%s() error!\n", szAPI); if(dwBufferLength=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), GetSystemDefaultLangID(), (LPTSTR) &MessageBuffer, 0, NULL )) { DWORD dwBytesWritten; // Output message string on stderr WriteFile(GetStdHandle(STD_ERROR_HANDLE), MessageBuffer, dwBufferLength, &dwBytesWritten, NULL); // free the buffer allocated by the system LocalFree(MessageBuffer); } }
いちおう出来てるっぽいかな。
プロセスの優先順位クラスを備忘録としてメモ。
REALTIME_PRIORITY_CLASS | リアルタイム(R) |
HIGH_PRIORITY_CLASS | 高(H) |
ABOVE_NORMAL_PRIORITY_CLASS | 通常以上(A) |
NORMAL_PRIORITY_CLASS | 通常(N) |
BELOW_NORMAL_PRIORITY_CLASS | 通常以下(B) |
IDLE_PRIORITY_CLASS | 低(L) |
*1:sysinternalのツールさいこー