일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 해외주식
- Espressif
- 애플
- 현대통신
- matter
- 나스닥
- Bestin
- 빅데이터분석기사
- 매터
- 주식
- 홈네트워크
- Home Assistant
- 월패드
- 미국주식
- homebridge
- 국내주식
- esp32
- 라즈베리파이
- Python
- MQTT
- Apple
- raspberry pi
- SK텔레콤
- RS-485
- 힐스테이트 광교산
- 공모주
- ConnectedHomeIP
- cluster
- 배당
- 파이썬
- Today
- Total
YOGYUI
MFC::프로그램으로 PC 전원 끄기 (Windows OS) 본문
Turn Off / Restart PC Power by Programming Code
MS Windows 환경에서 프로그래밍 코드(Visual C++, MFC)를 통해 PC의 전원을 끄는 방법을 알아보자
용도) Windows OS에 접근하지 못하게 프로그램을 구성한 뒤, PC의 전원을 끄거나 재시작하고자 할 경우
※ Windows 10, Visual Studio 2019에서 구현 및 테스트함
1. API 사용 - ExitWindowsEx
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-exitwindowsex
<WinUser.h>에 선언되어 있는 ExitWindowsEx 함수를 호출하면 된다
함수 원형은 다음과 같다
BOOL ExitWindowsEx(
[in] UINT uFlags,
[in] DWORD dwReason
);
uFlags의 인자로 다음 값들 중 하나를 사용할 수 있다 (각 인자에 대한 자세한 설명은 위 문서 참고)
- EWX_HYBRID_SHUTDOWN (0x00400000)
- EWX_LOGOFF (0x00000000)
- EWX_POWEROFF (0x00000008)
- EWX_REBOOT (0x00000002)
- EWX_RESTARTAPPS (0x00000040)
- EWX_SHUTDOWN (0x00000001)
이름을 보면 알겠지만, PC 파워 종료뿐만 아니라 재시작, 로그오프 등의 기능도 동일 함수로 수행할 수 있다
또한, uFlags 인자에 다음 두 값중 하나를 or 연산으로 조합할 수 있다
- EWX_FORCE (0x00000004)
실행중인 다른 프로세스들에 WM_QUERYENDSESSION 메시지를 보내지 않음 - EWX_FORCEIFHUNG (0x00000010)
실행중인 다른 프로세스들이 WM_ENDSESSION 메시지 혹은 WM_QUERYENDSESSION 메시지에 응답하는 것을 기다림
즉, EWX_FORCE를 조합하면 다른 프로세스(ex: 워드프로세서 문서 등)가 저장되지 않은 내역이 있음에도 불구하고 사용자 확인 메시지 없이 강제로 셧다운시켜버리게 되니, 호출 시 주의해야 한다
또한, 함수가 호출되는 이유로 dwReason 인자를 입력할 수 있는데, Major-Minor를 or 연산으로 조합하여 다양한 셧다운 원인을 조합할 수 있다 (자세한 내용은 링크 참고)
예를 들어
SHTDN_REASON_MAJOR_APPLICATION |
SHTDN_REASON_MINOR_UPGRADE |
SHTDN_REASON_FLAG_PLANNED
와 같이 조합하면 '어플리케이션(SW)이 계획에 의해 업그레이드됨에 따라' 이 함수를 호출하게 된다는 것을 의미한다 (특정 프로그램 업그레이드 후 재시작이 필요하다고 나오는 메시지를 봤다면 익숙한 개념)
[구현]
단순히 위 함수만 호출한다고 해서 전원이 종료되거나 재시작되는 것은 아니고, 이 함수를 호출하는 프로세스에 Shutdown에 대한 권한(Privilege)을 부여받아야 한다 (마이크로소프트 제공 예시)
https://docs.microsoft.com/en-us/windows/win32/shutdown/how-to-shut-down-the-system
현재 프로세스에 권한을 부여하는 코드는 다음과 같이 구성할 수 있다
(Visual Studio 설치 시 자동으로 설치되는 라이브러리들을 활용하기 때문에, 추가적으로 설치할 건 없다)
#include <windows.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "advapi32.lib")
BOOL GetShutdownPrivilege() {
HANDLE hCurrentProcess, hToken;
TOKEN_PRIVILEGES* tkp = NULL;
// 현재 프로세스 핸들 얻기
hCurrentProcess = GetCurrentProcess();
// 현재 프로세스에 대해 'Adjust Privelege' 토큰 발급
if (!OpenProcessToken(hCurrentProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
// 토큰 구조체 할당
tkp = new TOKEN_PRIVILEGES;
if (!tkp)
return FALSE;
// Shutdown 권한에 대한 LUID 구조체 쿼리
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp->Privileges[0].Luid);
tkp->PrivilegeCount = 1;
tkp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Adjust Privelege 토큰 적용
AdjustTokenPrivileges(hToken, FALSE, tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
delete tkp;
if (GetLastError() != ERROR_SUCCESS)
return FALSE;
return TRUE;
}
이 함수는 어플리케이션 초기화 시 한번만 호출해도 되고, 혹은 ExitWindowsEx 함수 호출 시 다음과 같이 구현해도 된다
void PowerOffByAPI()
{
if (GetShutdownPrivilege())
ExitWindowsEx(
EWX_POWEROFF | EWX_FORCE,
SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_OTHER
);
}
※ Visual Studio에서 작업 시 C28159 경고 메시지를 확인할 수 있다
(Legacy API. Rearchitect to avoid Reboot)
어차피 시스템 종료를 원해서 구현한 것이니 경고를 무시해도 좋고, 아니면 InitiateSystemShutdownEx 함수로 구현해도 좋다 (사용법이 조금 더 복잡하니 이 글에서는 무시)
2. shutdown 실행파일 호출
Windows 설치 경로에 있는 /system32 디렉터리 내에는 shutdown 이라는 이름의 실행파일이 존재한다
(사용자가 PC 종료나 재시작, 로그오프 등의 명령을 내릴 때 실제로 호출되는 실행파일)
이 실행파일을 코드상에서 다음과 같이 호출하면 된다
#include <stdlib.h>
void PowerOffByExec() {
system("shutdown /f /s");
}
system 함수는 <stdlib.h>에 선언되어 있다
_DCRTIMP int __cdecl system(
_In_opt_z_ char const* _Command
);
※ 환경변수 PATH에 "{윈도우 설치 경로}/system32"가 추가되어 있어야 한다
만약 환경변수에 없는데 추가하는게 귀찮다면, shutdown.exe의 전체 경로를 함께 기입해주면 된다
system("C:\\Windows\\System32\\shutdown /f /s");
system 명령어에 대한 자세한 내용 (인자 입력 등)은 다음 문서 참고
https://docs.microsoft.com/ko-kr/windows-server/administration/windows-commands/shutdown
[참고]
https://stackoverflow.com/questions/846576/is-there-a-c-function-to-turn-off-the-computer
https://docs.microsoft.com/en-us/windows/win32/secauthz/enabling-and-disabling-privileges-in-c--
'Software > C, C++' 카테고리의 다른 글
C++::디렉터리 존재 여부 확인하기 (g++) (0) | 2022.07.25 |
---|---|
C++::chrono - 현재 날짜/시간 가져오기 (밀리초 포함) (0) | 2022.07.24 |
C/C++::CRC8, CRC16, CRC32 계산 라이브러리 깃허브 등록 (DLL) (0) | 2021.10.22 |
C++::CRC-16 계산 알고리즘 구현 (소스코드) (2) | 2021.10.13 |
std::vector 내부 요소에서 시퀀스 찾기 (find sub-sequence) (0) | 2021.10.12 |