Windows 앱 호환이 동작하는 방식 ── 호환성 모드, 심(Shim), Compatibility Administrator로 오래된 앱의 수명을 연장하는 방법
· 업데이트: · Go Komura · Windows, 호환성 모드, 심(Shim), 애플리케이션 호환성, Compatibility Administrator, 레거시 자산, Windows 개발, 기존 시스템
수정 이력(1건, 최종 수정 2026년 09월 03일)
이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.
- 한국어 전면 재작성에 맞춰 본문 표현을 바로잡았습니다. 기술적인 주장은 일본어판과 같습니다.
- 최초 공개
이 글을 인용하기(DOI(등록된 아카이브): 10.5281/zenodo.22176310)
아래 DOI는 이전에 등록된 아카이브를 가리키며 현재 본문과 다를 수 있습니다. 현재 본문을 참조할 때는 이 페이지의 URL을 사용하세요.
Go Komura (2026). 「Windows 앱 호환이 동작하는 방식 ── 호환성 모드, 심(Shim), Compatibility Administrator로 오래된 앱의 수명을 연장하는 방법」. 합동회사 코무라소프트. https://comcomponent.com/ko/blog/windows-appcompat-shims-compatibility-mode/
- DOI(등록된 아카이브)
- 10.5281/zenodo.22176310
- DOI(마지막 등록 버전)
- 10.5281/zenodo.22176311
「소스 코드가 남아 있지 않은 10년 된 업무 앱이, 새 Windows 11 PC에서 시작되지 않습니다. 속성의 호환성 탭에서 『Windows XP』에 체크했더니 쉽게 동작했습니다. ── 이것은 도대체 무엇을 하는 건가요. 이 상태에 기대어 계속 써도 되나요」. 고객에게서 자주 받는 상담입니다.
체크 하나로 동작해 버리면, 오히려 불안해지는 법입니다. 마법처럼 보이는 호환성 모드의 정체는 심(Shim)이라고 부르는, 앱과 Windows API 사이에 끼어들어 「거짓말」을 돌려주는 작은 코드 묶음입니다. Windows는 몇 세대 전의 앱을 계속 동작시키기 위해 이 응급처치를 OS 자신이 대규모로 쓰고 있으며, 사용자와 관리자에게도 그 일부가 열려 있습니다.
구조를 모른 채 쓰면, 「왜 동작하는지 모르니 건드리지 못한다」는 불안정한 수명 연장이 됩니다. 반대로 구조를 이해하면, 어디까지 안심하고 기댈 수 있는지, 무엇이 일어나면 깨지는지, 언제 다시 만들어야 하는지를 근거를 가지고 판단할 수 있게 됩니다.
flowchart TB
accTitle: 구조를 이해하면 수명 연장의 질이 달라진다
accDescr: 구조를 모른 채 호환성 모드를 쓰면 건드리지 못하는 불안정한 수명 연장이 되지만, 구조를 이해하면 어디까지 기댈 수 있는지, 무엇이 일어나면 깨지는지, 언제 다시 만들어야 하는지를 근거를 가지고 판단할 수 있다
unknown["구조를 모른 채 사용"] --> fear["건드리지 못하는 불안정한 수명 연장"]
known["구조를 이해하고 사용"] --> judge["근거를 가진 판단"]
judge -.-> j1["어디까지 기댈 수 있는가"]
judge -.-> j2["무엇이 일어나면 깨지는가"]
judge -.-> j3["언제 다시 만들어야 하는가"]
그림 1: 같은 수명 연장이라도, 구조를 몰라서 생기는 불안과 이해에 근거한 판단은 질이 다릅니다.
이 글에서는 중소기업 IT 담당자와, 오래된 업무 앱을 맡은 Windows 앱 개발자를 대상으로, 호환성 모드의 정체인 심의 구조, 대표 심으로 할 수 있는 일, Compatibility Administrator를 이용한 조직적 적용, 그리고 심으로는 구할 수 없는 한계와 「수명 연장인가 이전인가」의 판단까지를 Microsoft Learn 1차 자료를 바탕으로 정리합니다.
1. 먼저 결론
- 호환성 모드의 정체는 심(호환 레이어)입니다. 호환성 탭 설정은
HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers에 기록되고, 시작할 때 그 프로세스에 심 묶음이 적용됩니다.12 - 심은 가져오기 주소 테이블(IAT) 교체에 의한 사용자 모드 API 훅입니다. 앱이 Windows API를 호출하는 경로에 끼어들어, 옛 Windows와 같은 답을 돌려줍니다. OS 본체를 바꾸는 것이 아닙니다.3
- 심으로 할 수 있는 일은 앱 코드를 수정해서 할 수 있는 일과 같은 범위입니다. 보안 기능을 우회하지 못하며, 커널 모드(장치 드라이버) 문제도 고치지 못합니다.3
- 버전 위장, 파일 경로 바꿔 지정, 레지스트리 위장, 관리자 검사 위장 등 Microsoft가 준비한 기성 심이 다수 있습니다. Compatibility Administrator에서 개별 EXE에 적용할 수 있습니다.4
- Windows 자신도 기본적으로 심을 사용합니다. 시작할 때마다 OS 표준 호환 데이터베이스(.sdb)가 대조되는 것 외에, PCA(Program Compatibility Assistant)가 문제를 감지해 호환 설정을 자동으로 적용하기도 합니다.15
- 「옛 Windows라고 답하는」 동작은 이제 기본입니다. Windows 8.1 이후
GetVersionEx는 매니페스트에서 선언하지 않은 OS 버전을 돌려주지 않습니다. 호환성 모드는 이 구조의 연장입니다.67 - 16비트 앱, 커널 드라이버 의존, 하드웨어 직접 접근에는 심이 통하지 않습니다. 특히 64비트 Windows에서는 16비트 앱을 애초에 실행할 수 없습니다.8
- 「관리자를 요구하지만 실제로는 필요 없는」 앱에는 RunAsInvoker가 정석입니다.
__COMPAT_LAYER=RunAsInvoker로 권한 상승 요청을 억제하고 일반 권한으로 실행할 수 있습니다.9 - 심으로 동작한다 = 당장은 수명을 연장할 수 있다, 이지만 본래 길은 「심 없이 동작하는 형태로 고치는 것」입니다. 수명 연장을 정했다면, 어떤 심으로 동작하는지를 기록하고 재작성 판단 재료로 관리합니다.
그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 16건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle
2. 애플리케이션 호환성의 전체 그림 ── Windows가 가진 하위 호환의 층
심 이야기에 들어가기 전에, Windows가 오래된 앱을 위해 가진 방식을 한눈에 정리합니다. 「호환성 모드에서 동작했다」고 한 마디로 말해도, 실제로 앱을 구하는 것은 이 가운데 하나, 혹은 여러 층의 조합입니다.
| 층 | 하는 일 | 주된 대상 |
|---|---|---|
| 심(호환성 모드) | API 호출에 끼어들어, 옛 Windows와 같은 응답을 위장한다 | 옛 OS를 전제로 작성된 앱 전반 |
| UAC 가상화(파일/레지스트리) | 권한이 없는 HKLM\Software나 Program Files에 대한 쓰기를 사용자별 VirtualStore로 넘긴다 |
관리자 권한을 전제로 작성된 32비트 앱 |
| WOW64 | 32비트 앱을 64비트 Windows에서 그대로 실행한다(레지스트리·파일의 32비트 뷰를 제공) | 32비트 앱 전반 |
| DPI 가상화 | DPI 비대응 앱을 96 DPI로 그리게 하고, 비트맵 확대로 표시한다 | 고 DPI 디스플레이 위의 오래된 앱 |
UAC 가상화는 매니페스트가 없는 32비트 대화형 프로세스에 대해 동작하는 과도기 조치이며, Microsoft 자신이 「향후 Windows에서 삭제할 의향의 임시 기술」이라고 분명히 말합니다.10 Wow6432Node로의 리디렉션과 VirtualStore의 실제 피해와 대처는 「레지스트리의 32bit/64bit 리디렉션과 가상화의 함정」에서 자세히 다루므로, 이 글은 심을 중심에 두고 다른 층은 필요한 범위에서만 언급합니다.
flowchart TB
accTitle: UAC 가상화의 위치
accDescr: UAC 가상화는 매니페스트가 없는 32비트 대화형 프로세스에 대해 동작하는 과도기 조치로, 쓰기를 사용자별 VirtualStore로 넘기지만, Microsoft 자신이 향후 Windows에서 삭제할 의향의 임시 기술이라고 분명히 말한다
proc["매니페스트 없는 32비트 대화형 프로세스"] --> uacv["UAC 가상화가 동작"]
uacv --> vs["사용자별 VirtualStore로 전달"]
uacv -.-> tmp["향후 삭제를 전제로 한 임시 기술"]
그림 2: UAC 가상화는 매니페스트가 없는 32비트 프로세스용 과도기 조치이며, 영구적으로는 기댈 수 없습니다.
DPI 가상화도 덧붙이면, DPI 대응을 선언하지 않은 앱은 96 DPI(100%)로 그리고 있는 것으로 취급되고, Windows가 비트맵을 늘려 표시합니다. 고 DPI 모니터에서 오래된 앱이 「흐릿해 보이는」 것은 이 때문이며, 호환성 탭의 「높은 DPI 설정 재정의」는 이 가상화 동작을 바꾸는 스위치입니다.11
flowchart TB
accTitle: DPI 가상화의 구조
accDescr: DPI 대응을 선언하지 않은 앱은 96 DPI로 그리고 있는 것으로 취급되고, Windows가 비트맵을 늘려 표시하므로 흐릿하게 보이며, 호환성 탭의 높은 DPI 설정 재정의는 이 가상화 동작을 전환한다
app["DPI 대응을 선언하지 않은 앱"] --> treat["96 DPI로 그리는 것으로 취급"]
treat --> stretch["비트맵을 늘려 표시"]
stretch --> blur["고 DPI 모니터에서 흐릿해 보임"]
tab["높은 DPI 설정 재정의"] -.->|가상화 동작을 전환| treat
그림 3: DPI 비대응 앱은 96 DPI로 취급되어 늘어나고, 호환성 탭의 재정의는 이 가상화의 스위치가 됩니다.
3. 심(Shim)의 정체 ── IAT 교체로 API 사이에 끼어들기
3.1. 앱과 OS 사이에 서는 「통역」
Windows 실행 파일(PE 형식)은 외부 DLL의 API를 가져오기 주소 테이블(IAT) 경유로 호출합니다. 앱이 GetVersionEx를 호출할 때, 실제로는 IAT에 적힌 주소로 점프할 뿐입니다. 심의 구조는 여기를 노립니다. 앱 로드 때 대상 API의 IAT 항목을 심 코드 주소로 바꿔 쓰고, 앱과 Windows 사이에 끼어드는 것입니다. 동적으로 GetProcAddress로 얻는 API도, GetProcAddress 자체를 훅해서 대응합니다.3
끼어든 심은, 예를 들어 「지금 OS 버전은?」이라는 조회에 옛 버전 번호를 돌려주거나, 쓸 수 없는 위치로의 파일 접근을 다른 곳으로 바꿔 지정한 뒤, 필요하면 진짜 API를 호출합니다. 앱에서 보면 「옛 Windows에서 동작하는」 것처럼 보이고, OS에서 보면 「규칙을 지키는 앱이 동작하는」 것처럼 보입니다. ── 심은 둘 사이의 통역입니다.
flowchart TB
accTitle: 심이 API 호출에 끼어드는 경로
accDescr: 앱의 API 호출은 IAT를 지나며, 로드 때 IAT 항목을 심 쪽으로 바꿔 쓰면 심이 끼어들어 옛 Windows와 같은 응답을 위장한 뒤 필요하면 진짜 API를 호출한다
app["앱"] -->|API 호출| iat["IAT 항목"]
iat -->|로드 때 심 쪽으로 바꿔 씀| shim["심(통역)"]
shim -->|필요하면| api["진짜 Windows API"]
shim -.-> lie["옛 Windows와 같은 응답을 위장"]
gpa["GetProcAddress 경유 호출"] -.->|훅으로 대응| shim
그림 4: 앱과 Windows API 사이에 심이 끼어듭니다. 바뀌는 것은 앱 쪽 IAT이며, OS 본체는 바뀌지 않습니다.
이 설계에서 중요한 성질이 세 가지 나옵니다.3
- 심은 앱 쪽 코드로 동작합니다. OS의 일부가 아니므로, 앱과 같은 보안 제약을 받습니다. 심으로 OS의 보안 기능을 우회할 수 없으며, 심을 쓰기 위해 보안 설정을 느슨하게 할 필요도 없습니다.
- 심으로 고칠 수 있는 것은, 앱 코드를 수정해서도 고칠 수 있습니다. 심은 「소스가 없다·고칠 수 없다」는 경우의 대체 수단이지, 코드 수정보다 강력한 것은 아닙니다.
- 사용자 모드로 한정됩니다. 커널 모드에서 동작하는 장치 드라이버의 호환 문제는 심으로 고칠 수 없습니다.
3.2. 심 데이터베이스(.sdb)와 대조
「어느 EXE에 어느 심을 적용할지」의 대응표가 심 데이터베이스이며, 확장자 .sdb의 바이너리 파일입니다. 데이터베이스에는 대상 앱의 실행 파일이 파일 이름·크기·체크섬·버전 같은 속성(대조 속성)으로 등록되어 있으며, 프로세스 시작 때 대조됩니다. 해결책에는 API 훅을 주입하는 Appfix(심) 외에, 「이 앱에는 호환성 문제가 있습니다」라는 메시지를 표시하는 Apphelp도 있습니다. 여러 심과 플래그를 묶은 것이 호환 레이어(호환성 모드)입니다.1
놓치기 쉽지만, 이 대조는 호환성 모드를 설정한 앱뿐 아니라 모든 프로세스 시작에서 이루어집니다. Windows에는 수천 개의 알려진 앱 수정이 담긴 OS 표준 데이터베이스(실체는 %WINDIR%\AppPatch 아래)가 포함되어 있으며, 그 PC에서도 오늘, 어디선가 오래된 앱이 모르는 사이에 심이 붙은 채 시작되고 있을 것입니다. Microsoft가 제공하는 호환 수정은 Windows의 일부로 출하되며, Windows Update로 갱신됩니다.3
flowchart TB
accTitle: 프로세스 시작 때의 심 데이터베이스 대조
accDescr: 모든 프로세스 시작에서 심 데이터베이스와 대조되며, 대조 속성에 일치하는 등록이 있으면 Appfix에 의한 심 주입이나 Apphelp 메시지 표시가 이루어지고, 없으면 그대로 시작된다
start["프로세스 시작"] --> db["심 데이터베이스(.sdb)와 대조"]
db -.-> attr["파일 이름·크기 등으로 대조"]
db --> hit{"등록이 있는가?"}
hit -->|예| appfix["Appfix(심을 주입)"]
hit -->|예| apphelp["Apphelp(메시지 표시)"]
hit -->|아니요| plain["그대로 시작"]
layer["호환 레이어(호환성 모드)"] -.->|여러 심과 플래그의 묶음| appfix
그림 5: 대조는 호환성 모드를 설정한 앱뿐 아니라, 모든 프로세스 시작에서 이루어집니다.
3.3. PCA ── 자동으로 심을 적용하는 경로
하나 더, 관리자가 의도하지 않아도 심이 적용되는 경로가 PCA(Program Compatibility Assistant)입니다. PCA는 앱 실행을 감시하고, 알려진 호환성 문제의 징후를 감지하면 수정 적용을 사용자에게 제안하거나, 일부 경우에는 자동으로 호환 설정을 적용합니다. 예를 들어, 이미 해제된 DLL 안의 코드를 호출해 크래시하는 앱에는 PINDLL, 보호된 Windows 파일에 대한 쓰기에 실패하는 앱에는 WRPMITIGATION 같은 호환성 모드가 할당됩니다.5
flowchart TB
accTitle: PCA가 자동으로 호환 설정을 적용하는 흐름
accDescr: PCA는 앱 실행을 감시하고, 알려진 호환성 문제의 징후를 감지하면 수정 적용을 사용자에게 제안하거나, 일부 경우에는 자동으로 호환 설정을 적용한다
run["앱 실행"] --> pca["PCA가 감시"]
pca --> sign{"알려진 문제의 징후?"}
sign -->|있음| resp{"어떤 경우인가?"}
resp -->|제안으로 대응| suggest["수정 적용을 제안"]
resp -->|일부 경우| auto["자동으로 호환 설정을 적용"]
sign -->|없음| none["그대로 실행"]
auto -.-> ex["예:PINDLL이나 WRPMITIGATION"]
그림 6: PCA는 앱 실행을 감시하고, 알려진 문제의 징후를 감지하면 수정 제안 또는 자동 적용을 합니다.
「아무것도 설정하지 않았는데, 어느새 호환성 모드 체크가 들어가 있었다」의 정체는 많은 경우 이것입니다. 고장도 오조작도 아니며, Windows 설계대로의 동작입니다.
4. 대표 심으로 무엇을 할 수 있는가
Microsoft가 공개한 기성 심 가운데, 업무 앱 수명 연장에서 실제로 자주 쓰는 것을 발췌합니다.4
| 심 | 할 수 있는 일(요약) |
|---|---|
| WinXPSP3VersionLie 등 VersionLie 계열 | OS 버전 조회에 지정한 옛 버전을 돌려준다(버전 위장) |
| CorrectFilePaths | 쓸 수 없거나 존재하지 않는 파일 경로로의 접근을 다른 곳으로 바꿔 지정한다 |
| VirtualRegistry | 레지스트리 읽기·쓰기를 리디렉션·위장한다(버전 위장이나 존재하지 않는 키의 흉내를 포함) |
| ForceAdminAccess | 「관리자 그룹에 속해 있는가」 검사에 일시적으로 True를 돌려준다 |
| RunAsAdmin / RunAsHighest / RunAsInvoker | 매니페스트의 requireAdministrator / highestAvailable / asInvoker 지정과 같은 실행 수준을 바깥에서 부여한다 |
| WRPMitigation | 보호된 OS 파일·레지스트리에 대한 쓰기에 성공을 위장해, 앱을 다음으로 진행시킨다 |
| EmulateGetDiskFreeSpace | 빈 디스크 용량을 최대 2GB로 돌려준다(대용량 디스크에서 자리 넘침이 나는 앱 대책) |
| GlobalMemoryStatusLie | 메모리 상태 보고 값을 위장한다(시작 시 메모리 검사에서 실패하는 앱 대책) |
| LoadLibraryRedirect | 앱에 동봉된 옛 시스템 DLL이 아니라, Windows 쪽의 최신 DLL을 읽게 한다 |
들여다보면 알 수 있듯이, 심의 대부분은 「오래된 앱이 기대하는 답을 돌려주는 거짓말」입니다. 디스크는 2GB까지, OS는 XP, 당신은 관리자 ── 앱이 태어난 시대의 세계관을, 그 프로세스 안에만 재현하고 있습니다.
버전 위장은 「공식의 기본 동작」이 되었다
버전 위장은 특별한 편법이 아닙니다. Windows 8.1 이후 GetVersionEx가 돌려주는 값은 앱 매니페스트에 따라 달라졌습니다. 매니페스트의 <compatibility> 섹션에 <supportedOS> 선언이 없는 앱에는, 실제 OS가 무엇이든 Windows 8 상당(6.2)이 돌아갑니다. 선언이 있으면, 선언한 것 중 가장 높은 OS까지의 값이 돌아갑니다(예: Windows 8.1 GUID까지 선언했다면, Windows 11 위에서도 6.3).67
즉 「앱이 보는 Windows 버전」은 다음의 여러 단계로 정해집니다.
- 매니페스트에서 선언한 OS까지의 값이 돌아간다(선언이 없으면 6.2)
- 호환성 모드(VersionLie 계열 심)가 적용되어 있으면, 선택한 OS의 버전이 돌아간다6
flowchart TB
accTitle: 앱이 보는 OS 버전이 정해지는 방식
accDescr: GetVersionEx가 돌려주는 값은 매니페스트의 supportedOS 선언 유무로 정해지고, 선언이 없으면 Windows 8 상당의 6.2, 선언이 있으면 선언한 가장 높은 OS까지의 값이 돌아가며, VersionLie 계열 심이 적용되어 있으면 선택한 OS 버전으로 덮어쓴다
q["GetVersionEx 조회"] --> m{"supportedOS 선언이 있는가?"}
m -->|아니요| v62["Windows 8 상당(6.2)이 돌아감"]
m -->|예| decl["선언한 가장 높은 OS까지의 값"]
v62 --> lie{"VersionLie 계열 심 적용?"}
decl --> lie
lie -->|예| fake["호환성 모드에서 고른 OS의 값"]
lie -->|아니요| asis["그대로의 값이 돌아감"]
그림 7: 앱이 보는 Windows 버전은 매니페스트와 심의 여러 단계로 정해집니다.
자사 개발 앱에서 「OS 버전을 보고 분기하는데, Windows 11인데 8로 판정된다」고 혼란스럽다면, 먼저 매니페스트의 supportedOS 선언을 의심하십시오. 반대로 말하면, 버전 검사로 시작을 거부하는 오래된 앱은 심의 VersionLie로 높은 확률로 돌파할 수 있습니다. 버전 번호만 보고 있을 뿐, 실제 동작은 새 OS에서도 문제 없는 경우가 많기 때문입니다.
flowchart TB
accTitle: 버전에서 비롯된 두 증상과 대처
accDescr: 자사 앱이 Windows 11인데 8로 판정되면 매니페스트의 supportedOS 선언을 의심하고, 버전 검사로 시작을 거부하는 오래된 앱은 VersionLie 심으로 높은 확률로 돌파할 수 있다
sym1["Windows 11인데 8로 판정"] --> fix1["supportedOS 선언을 의심한다"]
sym2["버전 검사로 시작 거부"] --> fix2["VersionLie로 돌파를 시도한다"]
fix2 -.-> why["동작 자체는 새 OS에서도 문제 없는 경우가 많다"]
그림 8: 판정이 옛것이 되는 증상은 매니페스트를, 시작 거부는 VersionLie를 각각 의심합니다.
5. 호환성 모드 체크박스는 무엇을 하는가
속성 → 호환성 탭 설정은 레지스트리의 AppCompatFlags\Layers 키에 저장됩니다. DXGI의 앱 호환 설정 등도 같은 키를 쓰는, 호환 레이어 지정의 위치입니다.2 실제로 확인해 봅니다.
reg query "HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
호환성 탭에서 「Windows XP (Service Pack 3)」, 「관리자 권한으로 이 프로그램 실행」, 「높은 DPI 설정 재정의」를 설정한 EXE라면, 예를 들어 다음과 같은 값이 보입니다.
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
C:\LegacyApp\Gyomu.exe REG_SZ ~ WINXPSP3 RUNASADMIN HIGHDPIAWARE
체크 항목과 값의 대응 대표 예입니다(Windows 11에서 확인한 예이며, OS 버전에 따라 항목 이름·값은 달라질 수 있습니다).
| 호환성 탭 항목 | 기록되는 값(예) | 실체 |
|---|---|---|
| 호환성 모드: Windows XP (Service Pack 3) | WINXPSP3 | 버전 위장 외 여러 심을 묶은 호환 레이어 |
| 256색(8비트 색) 사용 | 256COLOR | 옛 색 모드 완화 |
| 640×480 해상도로 실행 | 640X480 | 저해상도에서 실행 |
| 전체 화면 최적화 사용 안 함 | DISABLEDXMAXIMIZEDWINDOWEDMODE | 전체 화면 때 그리기 최적화를 끔 |
| 높은 DPI 설정 재정의(애플리케이션) | HIGHDPIAWARE | DPI 가상화(비트맵 늘리기)를 그만두게 한다11 |
| 관리자 권한으로 이 프로그램 실행 | RUNASADMIN | 시작 때 권한 상승을 요구한다 |
잡아 둘 포인트는 세 가지입니다.
- 「관리자 권한으로 이 프로그램 실행」도 같은 위치에 기록됩니다. 호환성 모드와 권한 상승 지정은 같은 Layers 키에 함께 있으며, 「호환성 모드를 설정했더니 권한 상승까지 따라왔다/사라졌다」는 혼란은 여기서 생깁니다. 값을 직접 보면 원인을 가를 수 있습니다.
- HKCU에 기록되는 것은 「그 사용자의 설정」입니다. 탭의 「모든 사용자의 설정 변경」에서 설정한 경우에는 HKLM 쪽 같은 이름 키에 기록되어 모든 사용자에게 적용됩니다. 초기 배포로 나눠 줄 때는 어느 쪽에 쓰고 있는지를 의식하십시오.
- 체크박스는 기성 레이어의 입구일 뿐입니다. 탭에서 고를 수 있는 것은 대표적인 레이어뿐이며, 개별 심을 골라 조합할 수는 없습니다. 그것을 하는 것이 다음 장의 Compatibility Administrator입니다.
flowchart TB
accTitle: 호환성 탭 설정이 적용되기까지의 흐름
accDescr: 호환성 탭 설정은 AppCompatFlags의 Layers 키에 EXE 경로와 값으로 저장되고, 다음에 그 EXE를 시작할 때 로더가 값을 읽어 대응하는 호환 레이어를 프로세스에 적용한다
tab["호환성 탭에서 설정"] --> reg["Layers 키에 EXE 경로와 값을 저장"]
reg --> boot["다음 EXE 시작"]
boot --> loader["로더가 값을 읽음"]
loader --> apply["호환 레이어를 프로세스에 적용"]
reg -.-> hkcu["HKCU는 그 사용자만"]
reg -.-> hklm["HKLM은 모든 사용자에게 적용"]
그림 9: 체크박스의 실체는 Layers 키에 대한 기록이며, 적용은 다음 시작 때 이루어집니다.
6. Compatibility Administrator의 실무 ── 사용자 지정 .sdb를 만들어 배포하기
6.1. 입수와 주의점
Compatibility Administrator는 Windows ADK(Windows Assessment and Deployment Kit)에 포함된 도구입니다.12 설치하면 32비트 판과 64비트 판이 모두 들어가며, 32비트 앱 수정에는 32비트 판을, 64비트 앱에는 64비트 판을 써야 합니다.13
주의할 점이 하나 더 있습니다. Compatibility Administrator를 관리자 권한(상승된 상태)으로 시작해 테스트하면, UAC 가상화나 리디렉션이 본래처럼 동작하지 않아 「고쳐졌다」고 잘못 판정하는 경우가 있습니다. 수정의 효과는 반드시 실제 이용자와 같은 계정·권한으로 확인하십시오.4
flowchart TB
accTitle: Compatibility Administrator 이용 때의 두 가지 주의
accDescr: 32비트 앱 수정에는 32비트 판을, 64비트 앱에는 64비트 판을 쓰고, 수정의 효과는 상승된 상태가 아니라 실제 이용자와 같은 계정과 권한으로 확인한다
app32["32비트 앱"] --> tool32["32비트 판으로 수정"]
app64["64비트 앱"] --> tool64["64비트 판으로 수정"]
elev["상승된 상태에서 테스트"] -.-> wrong["고쳐졌다고 잘못 판정할 우려"]
user["실제 이용자와 같은 권한으로 테스트"] --> ok["효과를 올바르게 확인"]
그림 10: 32비트 판과 64비트 판의 구분, 그리고 실제 이용자와 같은 권한으로의 확인이 입구의 주의점입니다.
6.2. 사용자 지정 호환 데이터베이스를 만드는 절차
대략의 흐름은 다음과 같습니다.14
- Compatibility Administrator 왼쪽 창의 「Custom Databases」에서 새 데이터베이스를 만들고, 「Create New」→「Application Fix」를 고른다
- 앱 이름·벤더 이름을 입력하고, 대상 EXE 파일을 지정한다
- 적용할 호환성 모드(레이어)를 고른다 ── 먼저 「Windows XP 호환」 같은 묶음으로 시험하는 것이 지름길입니다
- 필요하면 개별 호환 수정(심)을 추가로 고른다 ── VersionLie만, CorrectFilePaths만, 처럼 최소 구성으로 좁힐 수 있습니다
- 대조 조건(파일 크기·체크섬·버전 등)을 확인하고 저장한다
대조 조건은 「이 EXE에만 적용하기」 위한 열쇠입니다. 기본 조건만으로도 보통은 충분하지만, 앱 버전을 특정할 수 있는 조건을 남기는 것을 권합니다. 나중에 벤더가 수정판을 냈을 때, 새 버전에까지 옛 거짓말이 계속 적용되는 사고를 막을 수 있기 때문입니다.1415
flowchart TB
accTitle: 사용자 지정 호환 데이터베이스를 만드는 절차
accDescr: 새 데이터베이스에 Application Fix를 만들고, 앱 이름과 대상 EXE를 지정하고, 호환성 모드 묶음으로 시험한 뒤 필요하면 개별 심으로 좁히고, 대조 조건을 확인해 저장한다
new["새 데이터베이스를 만든다"] --> fix["Application Fix를 고른다"]
fix --> info["앱 이름과 대상 EXE를 지정"]
info --> layer["호환성 모드 묶음으로 시험"]
layer --> single["필요하면 개별 심으로 좁힘"]
single --> match["대조 조건을 확인하고 저장"]
match -.-> ver["버전을 특정하는 조건을 남김"]
그림 11: Application Fix는 먼저 호환성 모드 묶음으로 시험하고, 최소 구성으로 좁히며, 대조 조건으로 대상을 한정합니다.
만든 .sdb는 먼저 검증 기기에서 테스트합니다. 의도대로 동작하면 조직 배포입니다.
6.3. sdbinst로 배포하기
사용자 지정 .sdb를 각 PC에 적용하는 명령이 sdbinst.exe입니다(관리자 권한 필요).15
:: 설치(-q 는 확인 없는 자동)
sdbinst -q "C:\Deploy\MyCorpFixes.sdb"
:: 제거(파일 지정)
sdbinst -q -u "C:\Deploy\MyCorpFixes.sdb"
:: 제거(데이터베이스 GUID 지정)
sdbinst -q -u -g {데이터베이스의 GUID}
조직 배포 전략으로 Microsoft는, 앱 설치 프로그램에 개별 .sdb를 넣는 방식보다 회사로서 하나(또는 부서마다)의 사용자 지정 데이터베이스로 모아 집중 관리하는 방식을 권장합니다. 수정이 늘수록, 한 줄짜리 데이터베이스를 여러 개 배포하는 것보다 하나의 데이터베이스를 갱신해 다시 배포하는 쪽이 관리하기 쉽기 때문입니다. 사용자 지정 데이터베이스는 고유 GUID를 가지며, 같은 GUID의 새 버전을 설치하면 이전 버전은 자동으로 교체되므로 갱신 운용도 단순합니다. 배포 자체는 MSI 패키지화나 시작 스크립트 등, 관리자 권한으로 실행할 수 있는 기존의 배포 경로에 올립니다.15
flowchart TB
accTitle: 사용자 지정 .sdb의 작성부터 배포까지의 흐름
accDescr: Compatibility Administrator로 사용자 지정 호환 데이터베이스를 만들어 검증 기기에서 테스트하고, sdbinst로 각 PC에 적용하며, 갱신 때는 같은 GUID의 새 버전을 설치하면 이전 버전이 자동으로 교체된다
make["Compatibility Administrator로 작성"] --> test["검증 기기에서 테스트"]
test --> deploy["sdbinst로 각 PC에 적용"]
deploy --> update["같은 GUID의 새 판을 설치"]
update -.-> replace["이전 버전은 자동으로 교체"]
deploy -.-> inv["프로그램 및 기능에 등록된다"]
그림 12: 사용자 지정 .sdb는 작성·검증·sdbinst 배포의 흐름으로 전개하고, 갱신은 GUID로 관리합니다.
설치된 사용자 지정 데이터베이스는 「프로그램 및 기능(설치된 앱)」에 항목으로 등록되므로, 재고 파악이나 삭제는 그곳에서도 확인할 수 있습니다. 어느 PC에 어떤 .sdb가 들어 있는지는 자산 관리 대장에 올려 두어야 할 정보입니다.
7. 통하지 않는 경우와 한계
심은 만능이 아닙니다. 구조상 다음 경우에는 통하지 않습니다.
- 커널 모드 문제. 심은 사용자 모드 프로세스 안에서 동작하므로, 장치 드라이버의 비호환은 고칠 수 없습니다. 오래된 계측 기기·USB 동글·프린터 드라이버가 Windows 11에 대응하지 않는 경우, 앱 쪽에 무엇을 적용해도 해결되지 않습니다. 바이러스 백신의 일부처럼 커널에서 동작하는 코드도 마찬가지입니다.3
- 16비트 앱. 64비트 Windows는 16비트 앱 실행을 지원하지 않습니다. 핸들이 64비트 Windows에서는 32비트의 유효 비트를 가져, 16비트 앱에 잘라 넘길 수 없기 때문이며, 시작은
ERROR_BAD_EXE_FORMAT로 실패합니다.8 앱 본체는 32비트여도 설치 프로그램의 시작 부분(스텁)이 16비트인 시대의 패키지가 있으며, 이 경우 「앱은 동작하는데 설치할 수 없다」는 형태로 나타납니다. - 하드웨어에 대한 직접 접근. I/O 포트나 물리 메모리를 직접 만지는 전제의 산업용 앱은, 애초에 현대 Windows에서는 사용자 모드에서 허용되지 않으며, 심으로 위장할 수 있는 범위를 넘습니다.
- 보안 기능 우회. 심은 앱과 같은 보안 제약 아래에서 동작하므로, 「권한이 없어 할 수 없는 일」을 가능하게 하지는 못합니다. ForceAdminAccess나 WRPMitigation은 검사나 쓰기의 성공을 위장해 앱을 다음으로 진행시킬 뿐이며, 실제로 보호된 자원을 다시 쓰고 있는 것은 아닙니다.34
- 자기 무결성 검사를 하는 앱. 오래된 복사 방지나 변조 탐지를 가진 앱은, API 훅 자체를 이상으로 보고 동작하지 않게 되는 경우가 있습니다.
flowchart TB
accTitle: 심이 통하지 않는 경우
accDescr: 심은 사용자 모드 프로세스 안에서 동작하므로, 커널 모드 드라이버 문제, 16비트 앱, 하드웨어에 대한 직접 접근, 보안 기능 우회에는 통하지 않는다
shim["심(사용자 모드에서 동작)"] -->|통하지 않음| drv["커널 드라이버"]
shim -->|통하지 않음| b16["16비트 앱"]
shim -->|통하지 않음| hw["하드웨어 직접 접근"]
shim -->|통하지 않음| sec["보안 기능 우회"]
b16 -.-> fmt["64비트에서는 시작 자체가 실패"]
sec -.-> fake["성공 위장으로 다음으로 진행시킬 뿐"]
그림 13: 심은 사용자 모드로 한정되며, 커널·16비트·하드웨어 직접 접근·보안 우회에는 닿지 않습니다.
그리고 심에 공통된 본질적 한계가 「응급처치라는 점」입니다. 심은 특정 API의 특정 쓰임새에 맞춘 거짓말이며, OS 쪽 구현이 바뀌면 전제가 무너집니다. Microsoft가 제공하는 심은 Windows의 일부로서 Windows Update로 유지되지만3, 사용자 지정 데이터베이스로 적용한 거짓말을 돌보는 것은 자사 조직입니다. 기능 업데이트마다 「심으로 수명 연장 중인 앱 목록」을 검증하는 운용을, 수명 연장의 비용으로 잡아 두십시오.
flowchart TB
accTitle: 응급처치로서의 심과 유지 책임
accDescr: 심은 특정 API 쓰임새에 맞춘 거짓말이라 OS 쪽 구현이 바뀌면 전제가 무너지고, Microsoft 제공 심은 Windows Update로 유지되지만, 사용자 지정 데이터베이스로 적용한 거짓말을 돌보는 것은 자사 조직이며, 기능 업데이트마다의 검증이 수명 연장의 비용이 된다
shim["심은 응급처치의 거짓말"] --> break["OS 구현이 바뀌면 전제가 무너진다"]
ms["Microsoft 제공 심"] --> wu["Windows Update로 유지"]
own["사용자 지정 데이터베이스의 거짓말"] --> self["돌보는 것은 자사 조직"]
self --> cost["기능 업데이트마다의 검증이 수명 연장 비용"]
그림 14: 심이라는 거짓말의 유지 책임은, Microsoft 제공분과 자사 조직의 사용자 지정분으로 갈립니다.
8. RunAsInvoker의 실무 가치 ── 권한 상승 요청만 잠재우기
심 가운데에서도, IT 담당자의 일상 업무에서 가장 자주 나오는 것이 RunAsInvoker입니다.
오래된 업무 앱에는 매니페스트에서 requireAdministrator를 선언했거나, EXE 이름이나 내용에서 설치 프로그램으로 잘못 탐지되어, 시작할 때마다 UAC 권한 상승을 요구하는 것이 있습니다. 그런데 그 상당수는 XP 시대의 관성으로 관리자를 요구할 뿐, 실제로는 관리자 권한을 쓰지 않습니다. RunAsInvoker 심을 적용하면, 설치 프로그램 탐지도 매니페스트도 덮어써서 부모 프로세스에서 상속한 토큰(=일반 사용자 권한) 그대로 앱이 시작됩니다.9
flowchart TB
accTitle: RunAsInvoker가 권한 상승 요청을 억누르는 구조
accDescr: 매니페스트의 requireAdministrator 선언이나 설치 프로그램 오탐지가 시작 때 UAC 권한 상승 요청의 원인이 되지만, RunAsInvoker를 적용하면 둘 다 덮어써지고, 부모 프로세스에서 상속한 토큰 그대로 시작된다
manifest["requireAdministrator 선언"] --> shim{"RunAsInvoker 적용?"}
detect["설치 프로그램으로 오탐지"] --> shim
shim -->|아니요| uac["시작할 때마다 UAC 권한 상승 요청"]
shim -->|예| token["부모 토큰 그대로 시작"]
token -.-> limit["관리자가 필수인 처리는 앱 안에서 실패"]
그림 15: RunAsInvoker는 권한 상승 요청의 원인을 덮어쓸 뿐이며, 권한이 늘어나지는 않습니다.
Compatibility Administrator로 .sdb를 만들지 않아도, 환경 변수 __COMPAT_LAYER로 같은 레이어를 일시적으로 적용할 수 있습니다.
:: 이 명령 프롬프트에서 시작하는 자식 프로세스에 RunAsInvoker를 적용
set __COMPAT_LAYER=RunAsInvoker
start "" "C:\LegacyApp\Gyomu.exe"
# PowerShell의 경우
$env:__COMPAT_LAYER = 'RunAsInvoker'
Start-Process 'C:\LegacyApp\Gyomu.exe'
이 두 줄을 배치 파일로 만들어 바로 가기 대신 배포하면, 일반 사용자에게 로컬 관리자 권한을 나눠 주지 않아도 되고, UAC 암호 입력으로 매번 IT 담당자가 호출되는 일도 없어집니다. 최소 권한 원칙에도 맞는, 방어를 굳히는 방향의 호환 기법입니다.
flowchart TB
accTitle: RunAsInvoker 배치 배포의 효과
accDescr: RunAsInvoker를 설정하는 두 줄의 배치 파일을 바로 가기 대신 배포하면, 일반 사용자에게 로컬 관리자 권한을 나눠 주지 않아도 되고, UAC 암호 입력으로 IT 담당자가 호출되는 일도 없어져, 최소 권한 원칙에 맞는 운용이 된다
bat["두 줄의 배치를 배포"] --> noadmin["관리자 권한을 나눠 주지 않아도 됨"]
bat --> nocall["UAC로 IT 담당자가 호출되지 않음"]
noadmin --> lp["최소 권한 원칙에 맞는 운용"]
nocall --> lp
그림 16: 배치 배포만으로, 관리자 권한 배포와 UAC 대응 호출을 둘 다 줄일 수 있습니다.
주의점도 분명히 해 둡니다.
- 권한이 늘어나지는 않습니다. 정말로 관리자 권한이 필요한 처리(HKLM에 대한 쓰기, Program Files 아래의 갱신 등)는 앱 안에서 오류가 되거나, 조건을 충족하면 UAC 가상화로 VirtualStore로 넘어갑니다.10 설정 저장이 「통하지 않게 된」 것처럼 보이면 가상화를 의심하십시오.
- 환경 변수 방식은 자식 프로세스에만 적용됩니다. 영구 적용하려면 호환성 탭(RUNASINVOKER는 탭에 항목이 없으므로 Layers 키에 직접 설정)이나 .sdb 배포가 확실합니다.
- 쓰기 위치를 바로잡는 것이 본래의 길입니다. 앱을 고칠 수 있다면, 설정 파일을
%APPDATA%아래로 옮기고, 매니페스트에서asInvoker를 선언하는 것이 올바른 모습입니다.9
flowchart TB
accTitle: RunAsInvoker의 일시 적용과 영구 적용
accDescr: 환경 변수 COMPAT_LAYER에 의한 적용은 거기에서 시작한 자식 프로세스에만 적용되고, 영구적으로 적용하려면 Layers 키에 직접 설정하거나 .sdb로 배포한다
env["환경 변수로 설정"] --> child["자식 프로세스에만 적용"]
child -.-> tmp["일시적 적용"]
layers["Layers 키에 직접 설정"] --> always["영구 적용"]
sdb["sdb로 배포"] --> always
그림 17: 환경 변수 방식은 자식 프로세스로 한정된 일시 적용이며, 영구화는 Layers 키나 .sdb로 합니다.
9. 수명 연장인가 이전인가의 판단 ── 심으로 동작한 뒤에 생각할 것
심으로 동작한 순간은 안도하지만, 거기서 생각을 멈추지 않는 것이 중요합니다. 심으로 동작했다 = Windows가 마련한 받침대에 우연히 들어맞았다는 것에 지나지 않습니다. 판단 축을 표로 정리합니다.
| 판단 축 | 수명 연장(심) 쪽 조건 | 이전·재작성 쪽 조건 |
|---|---|---|
| 남은 이용 기간 | 1〜2년 안에 업무 단위로 폐지 예정 | 5년 이상 계속 쓴다는 전제 |
| 소스 코드 | 없다(벤더 소멸·분실) | 있다, 또는 자산을 회수할 수 있다 |
| 의존의 깊이 | 사용자 모드 API 호환만의 문제 | 드라이버·16비트·전용 하드웨어에 의존 |
| 대체 수단 | 패키지 제품이나 새 버전이 존재하지 않는다 | 이전 대상 제품·기술이 명확하다 |
| 장애 시 영향 | 멈춰도 대체 절차로 업무가 돌아간다 | 기간 업무가 직접 타격을 받는다 |
| 검증 체제 | 기능 업데이트마다 동작을 확인할 수 있다 | 검증 자원이 없어 방치되기 쉽다 |
수명 연장을 정했다면, 다음 세 가지를 세트로 운용에 올리십시오.
- 기록한다. 어느 EXE에, 어느 심/레이어를, 왜 적용했는지. Layers 키 값과 .sdb의 GUID를 대장에 남깁니다. 「왜 동작하는지 아무도 모른다」는 상태가, 다음 담당자에게 가장 큰 부채입니다. 이 사고방식은 「소스 코드도 명세서도 없는 시스템을 인수인계받았다면」에서 다룬 보전의 발상과 같습니다.
- 검증한다. Windows 기능 업데이트의 검증 항목에, 심으로 수명 연장 중인 앱의 시작·주요 조작을 넣습니다. OS 교체 계획(Windows 10 지원 종료 이후의 현실적 선택)과도 연동시킵니다.
- 기한을 정한다. 「다음 기간 시스템 개편까지」「2028년 3월까지」처럼 수명 연장의 끝을 정하고, 이전 검토를 병행합니다.
flowchart TB
accTitle: 수명 연장을 정한 경우의 운용 3점 세트
accDescr: 어느 심으로 동작하는지를 대장에 기록하고, 기능 업데이트마다 심으로 수명 연장 중인 앱의 동작을 검증하고, 수명 연장의 기한을 정해 이전 검토를 병행한다
decide["수명 연장을 정한다"] --> rec["기록:어떤 심으로 동작하는지 대장에"]
rec --> verify["검증:기능 업데이트마다 동작 확인"]
verify --> deadline["기한:수명 연장의 끝을 정한다"]
deadline --> mig["이전 검토를 병행한다"]
그림 18: 수명 연장은 기록·검증·기한의 3점 세트에 이전 검토의 병행까지 넣어 운용합니다.
이전 쪽의 선택지는 앱 기술에 따라 정석이 달라집니다. VB6로 만든 앱이라면 「VB6 앱은 언제까지 동작하는가」에서 정리한 전면 재작성·자동 변환·단계 이전의 세 가지, ActiveX/OCX에 의존한다면 「ActiveX / OCX를 지금 어떻게 다룰 것인가」의 남기기·감싸기·바꾸기의 판단표를 쓸 수 있습니다. 심은 이런 이전 프로젝트의 검토·준비 기간을 안전하게 버는 시간 벌기, 로 자리매김하는 것이 건전합니다.
flowchart TB
accTitle: 이전 쪽 선택지와 심의 위치
accDescr: 이전의 정석은 앱 기술에 따라 달라지고, VB6로 만든 앱이라면 전면 재작성·자동 변환·단계 이전의 세 가지, ActiveX 의존이라면 남기기·감싸기·바꾸기의 판단표를 쓸 수 있으며, 심은 이전 프로젝트의 검토와 준비 기간을 안전하게 버는 시간 벌기로 자리매김한다
tech{"앱의 기술은?"} -->|VB6로 만든 앱| vb["재작성·자동 변환·단계 이전"]
tech -->|ActiveX 의존| ax["남기기·감싸기·바꾸기"]
shim["심으로의 수명 연장"] -.->|검토와 준비의 시간을 번다| tech
그림 19: 이전의 정석은 앱 기술로 정해지고, 심은 그 검토 기간을 버는 시간 벌기로 자리매김합니다.
10. 정리
- 호환성 모드의 정체는 심입니다. 호환성 탭 설정은 AppCompatFlags\Layers 키에 기록되고, 시작 때 IAT 교체에 의한 API 훅으로서 프로세스에 주입됩니다.
- 심은 「오래된 앱이 기대하는 답을 돌려주는 거짓말」의 모임입니다. 버전 위장, 경로 바꿔 지정, 레지스트리 위장, 관리자 검사 위장 등의 기성 심이 마련되어 있습니다.
- Windows 자신이 기본적으로 대량의 심을 쓰고 있으며, PCA가 자동 적용하는 경우도 있습니다. 호환성 모드에 기대는 것 자체는, OS의 정식 방식에 오른 타당한 선택입니다.
- 사용자 모드 한정·보안 우회 불가라는 원리적인 한계가 있으며, 커널 드라이버·16비트 앱·하드웨어 직접 접근은 구할 수 없습니다.
- 조직 배포는 Compatibility Administrator(Windows ADK)로 사용자 지정 .sdb를 만들고, sdbinst로 배포합니다. 32비트/64비트 판의 구분, 실제 이용 계정에서의 테스트, GUID에 의한 갱신 관리가 실무의 핵심입니다.
- 「관리자를 요구하지만 실제로는 필요 없는」 앱은
__COMPAT_LAYER=RunAsInvoker로 일반 권한화할 수 있습니다. 권한을 나눠 주는 것이 아니라 권한 상승 요청을 잠재우는, 방어 쪽 기법입니다. - 심으로 동작하는 것은 수명 연장이지 해결이 아닙니다. 무엇으로 동작하는지를 기록하고, 기능 업데이트마다 검증하고, 기한을 정해 이전을 병행한다 ── 이 3점 세트까지 포함해 「호환성 모드에 기대는」 판단입니다.
다음에 호환성 모드 체크로 오래된 앱이 동작하면, 이렇게 다시 물으십시오. 「이 앱은 어느 거짓말 덕분에 동작하는가. 그 거짓말은 언제까지 통할 것인가」. 답할 수 있다면, 수명 연장은 제대로 된 전략입니다.
관련 기사
- 레지스트리의 32bit/64bit 리디렉션과 가상화의 함정 ── Wow6432Node와 「썼는데 값이 없다」 문제
- VB6 앱은 언제까지 동작하는가 ── 런타임 지원 현황과 현실적인 .NET 이전 진행 방법
- ActiveX / OCX를 지금 어떻게 다룰 것인가 - 남길지·감쌀지·교체할지 판단표
- Windows 10 지원 종료 이후의 현실적 선택 ── ESU·LTSC·교체 판단표
- 소스 코드도 명세서도 없는 시스템을 인수인계받았다면 ── 멈추지 않고 운영·유지보수하기 위한 실무 절차
- Windows 셸 통합의 현재 ── 컨텍스트 메뉴, 파일 연결, Windows 11의 변화
관련 상담 영역
합동회사 코무라소프트에서는, 소스 코드가 없는 오래된 업무 앱의 동작 조사와 수명 연장 설계(심·호환성 모드 선정, 사용자 지정 .sdb 작성과 전개), Windows 11 이전에 따른 기존 앱의 호환성 검증, 그리고 수명 연장과 병행하는 재작성·이전의 계획 수립을 다룹니다. 「호환성 모드에서 동작해 버렸는데, 이대로 괜찮은가」라는 단계부터의 상담이어도 괜찮습니다.
참고 링크
-
Microsoft Learn, Application Compatibility Database. 호환성 기반이 .sdb 형식 데이터베이스로 문제와 해결책을 관리한다는 점, 실행 파일 속성에 의한 대조, Apphelp(메시지 표시)와 Appfix(심에 의한 API 훅), 여러 심과 플래그를 묶은 호환 레이어(모드)에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, DXGI overview. 애플리케이션 호환 설정이 레지스트리의 HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers 키에 저장된다는 점에 대해(DXGI의 호환 설정을 예로). ↩ ↩2
-
Microsoft Learn, Understanding and Using Compatibility Fixes. 호환 수정(심)이 IAT(가져오기 주소 테이블)를 다시 써서 API 호출을 리디렉션한다는 점, 동적 링크는 GetProcAddress 훅으로 대응한다는 점, 심이 앱과 같은 보안 제약을 받아 OS 보안 기능을 우회하지 못한다는 점, 사용자 모드로 한정되어 드라이버 문제를 고치지 못한다는 점, 심으로 가능한 수정은 코드 수정으로도 가능하다는 점, 벤더 지원이 끝난 앱 등에서의 이용 시나리오, Microsoft 제공 호환 수정이 Windows의 일부로 출하되고 Windows Update로 갱신된다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, Compatibility Fixes for Windows 10, Windows 8, Windows 7, and Windows Vista. CorrectFilePaths, VirtualRegistry, ForceAdminAccess, RunAsAdmin/RunAsHighest/RunAsInvoker, WRPMitigation, EmulateGetDiskFreeSpace, GlobalMemoryStatusLie, LoadLibraryRedirect, VersionLie 계열 등 알려진 호환 수정의 목록과 설명, Compatibility Administrator의 32비트/64비트 판 구분, 상승된 상태에서 테스트하면 가상화나 리디렉션이 기대대로 동작하지 않으므로 실제 이용 계정으로 검증해야 한다는 점에 대해. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Program Compatibility Assistant scenarios for Windows 8. PCA가 앱 실행을 감시해 알려진 호환성 문제의 징후를 감지하고, 권장 수정의 적용을 제안하거나 자동 적용한다는 점(PINDLL, DISABLEUSERCALLBACKEXCEPTION, VIRTUALIZEDELETE, WRPMITIGATION 등), 호환성 탭과 호환성 문제 해결사에서의 수정 적용에 대해. ↩ ↩2
-
Microsoft Learn, GetVersionExW function. Windows 8.1 이후 GetVersionEx가 돌려주는 값이 매니페스트에 의존하게 되어, Windows 8.1/10용으로 매니페스트되지 않은 앱에는 Windows 8의 버전 값(6.2)이 돌아간다는 점, 호환성 모드가 유효한 경우에는 선택한 OS의 버전을 보고한다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Targeting your application for Windows. 앱 매니페스트의 compatibility 섹션에 supportedOS 요소로 지원 OS의 GUID를 선언하는 방법, 선언이 없을 때의 동작, trustInfo를 포함하지 않는 32비트 x86 앱이 UAC 파일 가상화(VirtualStore로의 쓰기 리디렉션) 대상이 된다는 점에 대해. ↩ ↩2
-
Microsoft Learn, Running 32-bit Applications. WOW64가 64비트 Windows에서 32비트 앱을 실행하는 에뮬레이션 층이며 파일·레지스트리 충돌을 격리한다는 점, 64비트 Windows가 16비트 앱 실행을 지원하지 않으며 핸들의 유효 비트 수 문제로 시작이 ERROR_BAD_EXE_FORMAT로 실패한다는 점에 대해. ↩ ↩2
-
Microsoft Learn, Using the RunAsInvoker Fix. RunAsInvoker 호환 수정이 부모 프로세스에서 상속한 토큰으로 앱을 시작시킨다는 점, 설치 프로그램 탐지와 매니페스트 처리를 둘 다 덮어쓴다는 점, API를 가로채지 않고 로더 플래그로 적용된다는 점, 코드를 고칠 수 있으면 매니페스트에서 asInvoker를 선언하는 것이 본래의 수정이라는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Registry Virtualization. 레지스트리 가상화가 HKLM\Software에 대한 전역 쓰기를 사용자별 VirtualStore로 투명하게 리디렉션하는 호환 기술이라는 점, 32비트 대화형 프로세스만 대상이며 매니페스트에 requestedExecutionLevel을 지정한 프로세스나 64비트 프로세스에서는 무효라는 점, 향후 Windows에서 삭제할 의향의 임시 기술로 자리매김된다는 점에 대해. ↩ ↩2
-
Microsoft Learn, High DPI Desktop Application Development on Windows. DPI 비대응 앱이 96 DPI 고정으로 그리고 있는 것으로 취급되어, 고 DPI 디스플레이에서는 Windows가 비트맵을 늘려 표시하므로 흐릿하게 보인다는 점, DPI 인식 모드(Unaware/System/Per-Monitor)의 차이에 대해. ↩ ↩2
-
Microsoft Learn, Download and install the Windows ADK. Windows ADK에 Compatibility Administrator와 Standard User Analyzer가 포함된다는 점, ADK 버전 선택의 생각과 내려받기·설치 방법에 대해. ↩
-
Microsoft Learn, Compatibility Administrator User’s Guide. Compatibility Administrator가 호환 수정·호환성 모드·AppHelp 메시지 적용과 사용자 지정 데이터베이스 작성 기능을 제공한다는 점, 32비트 판과 64비트 판이 설치되며 32비트 앱에는 32비트 판을, 64비트 앱에는 64비트 판을 써야 한다는 점에 대해. ↩
-
Microsoft Learn, Creating a Custom Compatibility Fix in Compatibility Administrator. 호환 수정(구칭 심)이 API 호출에 끼어드는 작은 코드라는 점, 사용자 지정 데이터베이스에 Application Fix를 만드는 절차(앱 이름·벤더·대상 EXE 지정, 호환성 모드 선택, 추가 심 선택, 대조 조건 설정), 대조 정보를 좁히면서도 앱을 올바르게 식별할 수 있는 조건을 남겨야 한다는 점에 대해. ↩ ↩2
-
Microsoft Learn, Compatibility Fix Database Management Strategies and Deployment. 사용자 지정 호환 데이터베이스의 관리 전략으로 집중 관리형 데이터베이스가 권장된다는 점, 호환 수정에 버전 검사(대조 조건)를 넣어 새 버전에 적용되지 않게 해야 한다는 점, Sdbinst.exe에 의한 로컬 설치(-q, -u, -g 옵션), 데이터베이스 GUID가 같은 새 버전을 설치하면 이전 버전이 자동 제거된다는 점, MSI나 스크립트에 의한 배포 방법에 대해. ↩ ↩2 ↩3
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
OLE 개체란 무엇인가 - 포함과 연결의 구조, 그리고 업무 문서의 함정
Word에 Excel 표를 넣는 기능의 정체가 바로 OLE 개체입니다. 포함과 연결의 차이, 복합 파일과 구조화 스토리지, In-Place Activation의 구조부터 링크 깨짐, 파일 비대화, 보안 대책까지 실무 관점에서 설명합니다.
빠른 시작의 정체 ── Windows의 「종료」가 다시 시작과 다른 이유
Windows의 「종료」는 기본적으로 하이브리드 종료가 되어 커널과 드라이버가 최대 절전 모드 파일에 저장되고 다음 부팅에서 복원됩니다. 다시 시작해야만 해결되는 이유, 가동 시간·업데이트·Wake on LAN에 미치는 영향, 확인 방법과 비활성...
Time Travel Debugging ── 장기 가동에서 재현되지 않는 결함을 「녹화」해서 되감기
한 달에 한 번만 나오는 결함은 크래시 덤프로는 결과밖에 찍히지 않습니다. WinDbg의 Time Travel Debugging(TTD)으로 실행을 녹화해 되감는 방법을 TTD.exe의 녹화 설계, 링 버퍼, TTD.Calls 쿼리, 덤프와의 역...
인수는 왜 깨지는가 ── Windows 명령줄 인수의 규칙
Windows에는 인수의 배열이 존재하지 않으며, CreateProcess에 전달되는 것은 한 줄의 문자열이고 분할은 받는 쪽이 합니다. CommandLineToArgvW·CRT·.NET의 분할 규칙과 .NET의 ArgumentList, C++에...
Windows 프린터 드라이버 제공 종료 ── 업무 앱의 장표·라벨 인쇄는 어떻게 대비할 것인가
Microsoft는 v3/v4 프린터 드라이버의 제공 종료를 단계적으로 진행하고 있으며, 2026년 7월부터는 IPP 클래스 드라이버가 우선됩니다. Windows protected print mode에서 무엇이 사라지는지, 업무 앱의 장표·라벨 ...
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- 호환성 모드에 체크했더니 앱이 동작했습니다. 그대로 계속 써도 되나요?
- 당장의 업무 연속이라는 의미에서는 그대로 써도 됩니다. 호환성 모드의 실체는 심이라고 부르는 사용자 모드 API 훅이며, OS 설정으로 정식 제공되는 방식입니다. 다만 심은 앱을 고치지 않고 동작시키기 위한 응급처치일 뿐이며, OS 업데이트로 전제가 바뀌면 다시 동작하지 않을 수 있습니다. 호환성 모드로 동작한다는 사실을 대장에 기록하고, 그 앱을 다시 만들 것인지 계획적으로 수명을 연장할 것인지의 판단과 함께 운용하십시오.
- 호환성 모드 체크박스는 구체적으로 무엇을 하나요?
- 속성의 호환성 탭에서 설정을 저장하면, HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers 키에 대상 EXE 경로와 "WINXPSP3", "HIGHDPIAWARE" 같은 값이 기록됩니다. 다음에 그 EXE를 시작할 때 Windows 로더가 이 값을 읽고, 대응하는 호환 레이어(심 묶음)를 프로세스에 적용합니다. 예를 들어 Windows XP 호환성 모드라면, OS 버전을 조회하는 API에 옛 값을 돌려주는 버전 위장 등이 동작합니다. OS 본체의 동작을 바꾸는 것이 아니라, 그 프로세스에만 「옛 Windows인 척」 보여주는 방식입니다.
- 16비트 시대의 오래된 앱은 64비트 Windows의 호환성 모드로 동작시킬 수 있나요?
- 동작시킬 수 없습니다. 64비트 Windows는 WOW64로 32비트 앱을 실행하지만, 16비트 앱 실행은 지원하지 않으며 시작을 시도하면 ERROR_BAD_EXE_FORMAT로 실패합니다. 심으로는 피할 수 없는 아키텍처상의 제한입니다. 설치 프로그램의 시작 부분만 16비트인 옛 패키지도 같은 이유로 실패합니다. 반드시 필요하다면, 32비트 Windows를 포함한 가상 머신 등 호환성 모드 밖의 수단을 검토하게 됩니다.
- 「관리자로 실행하지 않으면 시작되지 않는」 앱을 일반 사용자 권한 그대로 동작시킬 수 있나요?
- 시도할 가치가 있는 것이 RunAsInvoker입니다. 명령 프롬프트에서 set __COMPAT_LAYER=RunAsInvoker를 실행한 뒤 앱을 시작하면, 매니페스트의 requireAdministrator 지정이나 설치 프로그램 탐지에 의한 권한 상승 요청이 억제되고, 호출 측과 같은(일반 사용자) 권한으로 시작됩니다. 관리자 권한을 「요구만 하고 실제로는 쓰지 않는」 앱이라면, 이것만으로 일상 운용에서 권한 상승을 빼낼 수 있습니다. 권한이 늘어나지는 않으므로, 정말로 관리자 권한이 필요한 처리는 그 앱 안에서 실패합니다. 동작을 확인한 뒤에 채택하십시오.
- Compatibility Administrator는 어디서 받을 수 있나요?
- Windows ADK(Windows Assessment and Deployment Kit)에 포함되어 있습니다. Microsoft 사이트에서 ADK를 내려받고, 설치 때 Application Compatibility Tools 계열 기능을 선택하면 사용할 수 있습니다. 32비트 판과 64비트 판이 모두 설치되며, 32비트 앱 수정에는 32비트 판을, 64비트 앱에는 64비트 판을 써야 한다는 점에 주의하십시오. 만든 사용자 지정 호환 데이터베이스(.sdb)는 각 PC에서 sdbinst 명령을 실행해 적용합니다.