XP 호환성 모드 조작하기

@codemaru · January 15, 2007 · 4 min read

XP에서 프로그램의 등록정보를 보면 호환성 탭이 있습니다. 거기서 과거 특정 운영체제 호환모드로 프로그램을 실행시킬 수 있도록 하고 있습니다. 호환성 탭을 열면 아래와 같은 화면이 나옵니다. "다음에 대해 호환성 모드로 이 프로그램을 실행"에 체크 하고 운영체제를 선택하면 됩니다.

XP             md 0

XP에서 호환성 모드를 체크할 경우 드라이버와 관련된 프로그램은 오동작할 가능성이 많이 있습니다. 이러한 경우에 사용할 수 있는 코드입니다. 특정 애플리케이션의 호환성 체크 유무와 함께, 호환성을 다른 값으로 설정할 수 있는 함수입니다.
오동작 원인
일반적으로 드라이버는 NT와 9x계열을 나누어 프로그램 합니다. 드라이버를 연동하는 프로그램에서 운영체제 버전을 구해서 알맞은 버전을 로딩하도록 하죠. 그런데 버전을 구하는데 많이 사용되는 GetVersionEx의 값이 위의 호환성 체크를 해두면 바뀝니다. 실제 O/S는 XP인데, 9x 호환성 체크를 해두면 9x라고 버전이 나오는 것이죠. 그래서 잘못된 드라이버를 로딩할 수 있습니다. 물론 VerifyVersionInfo라는 함수를 쓰면 호환성을 무시하고 진짜 버전을 구할수 있긴 합니다.

typedef enum \_APPCOMPATFLAG
{  
    apcfNone = -1, // 호환성 없는 경우
  
    apcfWin95,   // 95 호환성
  
    apcfWin98, // 98/me 호환성
  
    apcfWinNT4SP5, // nt4sp5 호환성
  
    apcfWin2000 // 2k 호환성
  
}   
  
APPCOMPATFLAG, \*PAPPCOMPATFLAG;

  
APPCOMPATFLAG WINAPI GetAppCompatFlag(LPCTSTR szFileName);

호환성 모드를 조사하는 함수입니다. 리턴값은 호환성 모드 입니다.

첫번째 인자는 파일 경로입니다.

BOOL   
WINAPI SetAppCompatFlag(LPCTSTR szFileName, APPCOMPATFLAG apcfNewType);

호환성 모드를 설정하는 함수입니다. apcfNewType에 적당한 호환성 값을 넣어 주시면 됩니다.

#include <windows.h>  
  
typedef enum \_APPCOMPATFLAG   
{   
    apcfNone = -1  
    , apcfWin95  
    , apcfWin98  
    , apcfWinNT4SP5  
    , apcfWin2000   
} APPCOMPATFLAG, \*PAPPCOMPATFLAG;  
  
APPCOMPATFLAG WINAPI GetAppCompatFlag(LPCTSTR szFileName);   
BOOL WINAPI SetAppCompatFlag(LPCTSTR szFileName, APPCOMPATFLAG actNewType);  
  
APPCOMPATFLAG WINAPI GetAppCompatFlag(LPCTSTR szFileName)   
{   
    HKEY   hKey;   
    LPCTSTR szRegAppCompatLayerKey = "Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers";   
    APPCOMPATFLAG apcfRet = apcfNone;   
    LPCTSTR szActName[5] = {"Win95", "Win98", "WinNT4SP5", "Win2000", NULL};   
      
    if(IsWinXP() && RegOpenKey(HKEY\_CURRENT\_USER, szRegAppCompatLayerKey, &hKey) == ERROR\_SUCCESS)   
    {  
        TCHAR szCompatType[MAX\_PATH] = {0};   
        DWORD dwType;   
        DWORD dwSize = sizeof szCompatType;   
        if(RegQueryValueEx(hKey, szFileName, NULL, &dwType, (LPBYTE) szCompatType, &dwSize) == ERROR\_SUCCESS)   
        {     
            for(int i=0; szActName[i] != NULL; ++i)     
            {      
                if(stricmp(szCompatType, szActName[i]) == 0)      
                {       
                    apcfRet = (APPCOMPATFLAG) i;       
                    break;      
                }     
            }   
        }   
          
        RegCloseKey(hKey);   
    }   
      
    return apcfRet;   
}  
  
BOOL WINAPI SetAppCompatFlag(LPCTSTR szFileName, APPCOMPATFLAG apcfNewType)   
{   
    HKEY hKey;   
    LPCTSTR szRegAppCompatLayerKey = "Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers";   
    BOOL bRet = FALSE;   
    LPCTSTR szActName[6] = {"", "Win95", "Win98", "WinNT4SP5", "Win2000", NULL};   
      
    if(IsWinXP() && RegOpenKey(HKEY\_CURRENT\_USER, szRegAppCompatLayerKey, &hKey) == ERROR\_SUCCESS)   
    {   
        TCHAR szNewType[MAX\_PATH] = {0};   
        strcpy(szNewType, szActName[apcfNewType+1]);   
          
        if(strcmp(szNewType, "") == 0)   
        {     
            if(RegDeleteValue(hKey, szFileName) == ERROR\_SUCCESS)      
                bRet = TRUE;   
        }   
        else   
        {     
            if(RegSetValueEx(hKey, szFileName, 0, REG\_SZ, (LPBYTE) szNewType, strlen(szNewType)+1) == ERROR\_SUCCESS)      
                bRet = TRUE;     
        }   
          
        RegCloseKey(hKey);   
    }   
      
    return bRet;   
}
@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중