본문 바로가기
프로그래머의 길/C & C++

윈도우 종료

by 제이콥케이 2010. 1. 6.
반응형
ExitWindowsEx 함수를 사용하여 컴퓨터를 종료, 재시작, 로그아웃 시키는 방법은 매우 간단합니다.
이 함수의 첫번째 인자에 아래 나열된 값중에서 원하는 값을 조합해서 명시만 해주면 되기 때문입니다.
 
1. EWX_LOGOFF        : 사용중인 프로그램을 종료하고 시스템을 LOG OFF 시킨다.
2. EWX_POWEROFF   : 시스템을 종료하고 전원을 끊다.
3. EWX_REBOOT       : 시스템을 종료시킨 후 시스템을 재시작 한다.
4. EWX_SHUTDOWN   : 사용자가 시스템의 전원을 끌 수 있도록 시스템을 종료한다.
5. EWX_FORCE          : 강제로 프로세스를 종료시킨다.
 
이 함수를 사용할때 주의해야할 점은 윈도우즈 NT 계열(Windows NT, Windows 2000, Windows XP..)의
운영체제에서는 종료를 위해서 ExitWindowEx 함수를 사용하는 프로세스가 SE_SHUTDOWN_NAME
이라는 권한을 가지고 있어야 하기 때문에 해당 권한을 얻는 기능을 추가해주여야 한다는 것입니다.
( 윈도우즈 98, Me와 같은 운영체제에서는 권한이 필요 없습니다. )
따라서 ExitWindowsEx 함수를 호출하기 전에 먼저 운영체제의 버전을 체크하는 코드가 있어야 합니다.
 
 
// 현재 응용프로그램이 실행되고 있는 윈도우즈의 버전을 반환하도록 작성된 함수입니다.
// ------------------------------------------------------------------------------
// [ 반환값 : 의미 ]
//   -1 : 버전얻기 실패, 1 : Windows 95,  2 : Windows 98,  3 : Windows ME,  4 : Windows NT,
//    5 : Windows 2000,  6 : Windows XP

char GetOSVersionType()
{
    // 계산된 윈도우즈 버전을 저장할 변수
    char version = -1;
    // 윈도우즈 버전에 관련된 정보를 얻어올 변수
    OSVERSIONINFOEX osvi;
    // OSVERSIONINFOEX 구조체 값을 얻었는지 OSVERSIONINFO 구조체값을 얻었는지를
    // 구분할 변수 ( 0 이면, OSVERSIONINFO 구조체 정보를 얻었다는 뜻입니다. )
    BOOL version_ex_flag = 0;

    // 운영체제의 버전과 관련된 정보를 얻기 위해 구조체 변수를 초기화합니다.
    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
    // 현재 운영체제의 버전을 알수 없기 때문에 OSVERSIONINFOEX 속성으로 버전정보를 얻습니다.
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
 
    // GetVersionEx 함수를 사용하여 현재의 운영체제 정보를 얻습니다.
    // OSVERSIONINFOEX 값을 설정하고 호출했기 대문에 윈도우 NT 4.0 SP6 이상 및 그 이후 버전의
    //  윈도우가 아니라면 이 함수는 실패할 것입니다.
    if(!(version_ex_flag = GetVersionEx((OSVERSIONINFO *)&osvi))){
        // 윈도우즈 버전이 낮아서 OSVERSIONINFOEX 형식으로 값을 얻을수 없는 경우...
        // OSVERSIONINFO 형식으로 재설정하고 값을 얻습니다.
        osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
        if(!GetVersionEx((OSVERSIONINFO *)&osvi)) return -1;
    }
 
    // 얻어온 OSVERSIONINFOEX 구조체 변수의 값을 이용하여 버전을 구별합니다.
    switch(osvi.dwPlatformId){
        // NT 기술 기반의 운영체제인 경우
        case VER_PLATFORM_WIN32_NT:
            if(osvi.dwMajorVersion <= 4) version = 4;
else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) version = 5;
else if(version_ex_flag){
    if(osvi.dwMajorVersion == 5) version = 6;  // XP
    else if(osvi.dwMajorVersion == 6) version = 7;  // 비스타...
}
break;

        // 윈도우즈 9x 기반의 운영체제인 경우
        case VER_PLATFORM_WIN32_WINDOWS:
            if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) version = 1;
            else if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) version = 2;
            else if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) version = 3;
            break;
    }
 
    return version;
}
 
// 현재 운영체제가 NT 계열인 경우, SE_SHUTDOWN_NAME 레벨의 권한 등급을
// 가지고 있어야 하기 때문에 아래의 함수를 이용하여 권한을 얻습니다.
char GetNtPrivilege()
{
    HANDLE h_token;
    TOKEN_PRIVILEGES privilege_info;
 
    // 현재 프로세스의 권한과 관련된 정보를 변경하기 위해 토큰정보를 엽니다.
    if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES |
                                                    TOKEN_QUERY, &h_token)){
        // 권한과 관련된 정보 접근에 실패함..
        return 0;
    }
 
    // 현재 프로세스가 SE_SHUTDOWN_NAME 권한을 사용할수 있도록 설정한다.
    LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privilege_info.Privileges[0].Luid);
    privilege_info.PrivilegeCount = 1;
    privilege_info.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 
    // 지정한 값으로 권한을 조정한다.
    AdjustTokenPrivileges(h_token, FALSE, &privilege_info, 0, (PTOKEN_PRIVILEGES)NULL, 0);
    if(GetLastError() != ERROR_SUCCESS){
        // 권한 조정에 실패한 경우...
        return 0;
    }
 
    return 1;
}
 
// 컴퓨터를 끌때 사용할 함수
void PowerOff()
{
    if(GetOSVersionType()) <= 3{
        // 현재 운영체제가 Windows 95, Windows 98, Windows ME 인 경우...
        ExitWindowsEx(EWX_LOGOFF | EWX_POWEROFF | EWX_SHUTDOWN, 0);
        ExitWindowsEx(EWX_FORCE, 0);
    } else if(GetNtPrivilege()){
        // 현재 운영체제가 Windows NT, Windows 2000, Windows XP 인 경우...
        ExitWindowsEx(EWX_FORCE | EWX_POWEROFF, 0);
    }
}




//////////////////


int CTimerDlg::Window_ShutDown(void)
{
  HANDLE hToken;
     TOKEN_PRIVILEGES tkp;
 
     if( !OpenProcessToken( GetCurrentProcess(),
                            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                           &hToken ) ) return 0;
 
     if( !LookupPrivilegeValue( NULL,
                                SE_SHUTDOWN_NAME,
                               &tkp.Privileges[0].Luid ) ) return 0;
 
     tkp.PrivilegeCount = 1;
     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 
     if( !AdjustTokenPrivileges( hToken,
                                 FALSE,
                                &tkp,
                                 0,
                                 (PTOKEN_PRIVILEGES)NULL,
                                 0 ) ) return 0;
    ExitWindowsEx( EWX_SHUTDOWN | EWX_FORCE, 0 );
 return 0;
}
반응형