***.exe.mui 는 단일 파일로 존재하는 것이 아니라 메인이 되는 exe 가 존재하고 그 하위에 각 언어별로 폴더가 만들어져 있고 해당 폴더마다 해당 언어로 스트링테이블이 저장된 PE 파일, 즉 ***.exe.mui 파일이 존재한다.
간단히 말해 아래와 같은 형태로 존재한다.
SetupICC.exe
│
├─ar-SA
│ setupicc.exe.mui
│
├─cs-CZ
│ setupicc.exe.mui
│
├─da-DK
│ setupicc.exe.mui
│
├─de-DE
│ setupicc.exe.mui
│
├─el-GR
│ setupicc.exe.mui
│
├─en-US
│ setupicc.exe.mui
│
├─es-ES
│ setupicc.exe.mui
│
├─fi-FI
│ setupicc.exe.mui
│
├─fr-FR
│ setupicc.exe.mui
│
├─he-IL
│ setupicc.exe.mui
│
├─hu-HU
│ setupicc.exe.mui
│
├─it-IT
│ setupicc.exe.mui
│
├─ja-JP
│ setupicc.exe.mui
│
├─ko-KR
│ setupicc.exe.mui
│
├─nb-NO
│ setupicc.exe.mui
│
├─nl-NL
│ setupicc.exe.mui
│
├─pl-PL
│ setupicc.exe.mui
│
├─pt-BR
│ setupicc.exe.mui
│
├─pt-PT
│ setupicc.exe.mui
│
├─ru-RU
│ setupicc.exe.mui
│
├─sk-SK
│ setupicc.exe.mui
│
├─sl-SI
│ setupicc.exe.mui
│
├─sv-SE
│ setupicc.exe.mui
│
├─th-TH
│ setupicc.exe.mui
│
├─tr-TR
│ setupicc.exe.mui
│
├─zh-CN
│ setupicc.exe.mui
│
└─zh-TW
setupicc.exe.mui
exe.mui 파일은 결국 PE 파일이긴 하나 직접 다루는 것보다 윈도우에서 제공해주는 API를 이용하여 간편하게 추출할 수 있다.
일단, 레지스트리에 아래와 같은 키, 값이 있다고 가정하자.
DisplayName = Intel(R) Control Center
DisplayName_Localized = @C:\Program Files (x86)\Intel\Intel Control Center\Uninstaller\SetupICC.exe,-100
이럴 경우에는 DisplayName 에 있는 문자열을 그대로 사용해도 상관은 없으나 국제화(Localized)가 되어 있는 값이 있다는 뜻이므로 이왕이면 한글로 표기되어 있는 문자열을 뽑아내는 게 사용자 친화적이다.
이때에 사용할 수 있는 API 가 다음과 같다.
API |
제약조건 |
RegLoadMUIString |
Windows Vista 이상 ( 6.0 ) |
SHLoadIndirectString | Windows XP 이상 ( 5.1 ) |
LoadMUILibrary | Windows NT 이상 ( 3.1 ) |
세가지 API 가 있는데, 클라이언트 윈도우 버전에 따라 선택하여 사용하면 된다.
당연하게, 상위버전의 API 일수록 사용하기 더 편하다.
간단한 예를 보자.
1) RegLoadMUIString : 로컬라이징된 값이 있는 레지스트리 핸들과 해당 키를 던져 주면 결과를 돌려준다.
DWORD size; TCHAR szLocalized[MAX_PATH]; RegLoadMUIString( hKey, _T("DisplayName_Localized"), szLocalized, MAX_PATH, &size, NULL, NULL );
결과 : szLocalized = "인텔® 관리 엔진 구성 요소"
2) SHLoadIndirectString : DisplayName_Localized 값을 일단 추출한 후 해당 값을 넣어 주면된다.
SHLoadIndirectString( _T("@C:\Program Files (x86)\Intel\Intel Control Center\Uninstaller\SetupICC.exe,-100") , szLocalized, MAX_PATH, NULL );
결과 : szLocalized = "인텔® 관리 엔진 구성 요소"
3) LoadMUILibrary : DisplayName_Localized 값을 파싱하고 해당 EXE 혹은 DLL 을 로드해서 직접 스트링테이블의 값을 추출해야 한다.
#include "stdafx.h" #include#include #pragma comment(lib, "muiload.lib") BOOL LoadMUIString( LPCTSTR pszFormString, LPTSTR pszBuffer, int cchBufferMax) { int iResIdx; TCHAR szModule[MAX_PATH]; if ( _stscanf(pszFormString, _T("@%[^,],-%d"), szModule, &iResIdx) == 2 ) { HINSTANCE hInst = LoadMUILibrary( szModule, MUI_LANGUAGE_NAME, NULL ); if ( hInst ) { LoadString(hInst, iResIdx, pszBuffer, cchBufferMax ); FreeMUILibrary(hInst); return TRUE; } } else return FALSE; } void main() { TCHAR szLocalizedString[MAX_PATH]; LPCTSTR DisplayName_Localized = _T("@C:\\Program Files (x86)\\Intel\\Intel Control Center\\Uninstaller\\SetupICC.exe,-100"); LoadMUIString(DisplayName_Localized, szLocalizedString, MAX_PATH); printf("%S", szLocalizedString); }
살펴본 3개의 방법 중에 클라이언트의 상황에 맞는 방법으로 구현하면 된다.