以下是引用片段: LanguageSupport.h #pragma once #include #define ID_LANGUAGE_FIRST 0x6F00 #define ID_LANGUAGE_LAST 0x6FFF class CLanguageSupport { public: CLanguageSupport(); ~CLanguageSupport(); void CreateMenu(CCmdUI *pCmdUI, UINT nFirstItemId= ID_LANGUAGE_FIRST); void OnSwitchLanguage(UINT nId, bool bLoadNewLanguageImmediately= false); void LoadBestLanguage(); protected: CWordArray m_aLanguages; LANGID m_nExeLanguage; LANGID m_nCurrentLanguage; HINSTANCE m_hDll; static const TCHAR szLanguageId[]; static LANGID GetLangIdFromFile(LPCTSTR pszFilename); static CString GetLanguageName(LANGID wLangId); static LANGID GetUserUILanguage(); static LANGID GetSystemUILanguage(); void GetAvailableLanguages(); bool LoadLanguage(); bool LoadLanguageDll(); void LookupExeLanguage(); void UnloadResourceDll(); static void SetResourceHandle(HINSTANCE hDll); }; LanguageSupport.cpp #include "stdafx.h" #include "resource.h" #include "LanguageSupport.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "version.lib") const TCHAR CLanguageSupport::szLanguageId[]=_T("LanguageId"); #ifndef countof #define countof(x) (sizeof(x)/sizeof((x)[0])) #endif void CLanguageSupport::LoadBestLanguage() { ASSERT(AfxGetApp()->m_pszRegistryKey!=NULL && AfxGetApp()->m_pszRegistryKey[0]!=0); m_nCurrentLanguage=(LANGID)AfxGetApp()->GetProfileInt(_T(""),szLanguageId,0); if (LoadLanguage()) return; m_nCurrentLanguage= GetUserUILanguage(); if (LoadLanguage()) return; m_nCurrentLanguage= GetSystemUILanguage(); if (LoadLanguage()) return; m_nCurrentLanguage= GetUserDefaultLangID(); if (LoadLanguage()) return; m_nCurrentLanguage= GetSystemDefaultLangID(); if (LoadLanguage()) return; m_nCurrentLanguage= m_nExeLanguage; VERIFY(LoadLanguage()); } bool CLanguageSupport::LoadLanguage() { if (m_nCurrentLanguage==0) return false; if (LoadLanguageDll()) return true; WORD wSubLanguage= SUBLANGID(m_nCurrentLanguage); if (wSubLanguage!=SUBLANG_NEUTRAL) { m_nCurrentLanguage= MAKELANGID( PRIMARYLANGID(m_nCurrentLanguage), SUBLANG_NEUTRAL ); if (LoadLanguageDll()) return true; } if (wSubLanguage!=SUBLANG_DEFAULT) { m_nCurrentLanguage= MAKELANGID( PRIMARYLANGID(m_nCurrentLanguage), SUBLANG_DEFAULT ); if (LoadLanguageDll()) return true; } return false; } typedef LANGID (WINAPI*PFNGETUSERDEFAULTUILANGUAGE)(); typedef LANGID (WINAPI*PFNGETSYSTEMDEFAULTUILANGUAGE)(); #if _MFC_VER<0x0700 // for VC6 users. Depending on your version of the platform SDK, you may need these lines or not. typedef LPARAM LONG_PTR; #endif static BOOL CALLBACK _EnumResLangProc(HMODULE /*hModule*/, LPCTSTR /*pszType*/, LPCTSTR /*pszName*/, WORD langid, LONG_PTR lParam) { // Helper used to identify the language in NTDLL.DLL (used for NT4) if(lParam == NULL) // lParam = ptr to var that receives the LangId return FALSE; LANGID* plangid = reinterpret_cast< LANGID* >( lParam ); *plangid = langid; return TRUE; } LANGID CLanguageSupport::GetUserUILanguage() { HINSTANCE hKernel32= ::GetModuleHandle(_T("kernel32.dll")); ASSERT(hKernel32 != NULL); PFNGETUSERDEFAULTUILANGUAGE pfnGetUserDefaultUILanguage = (PFNGETUSERDEFAULTUILANGUAGE)::GetProcAddress(hKernel32, "GetUserDefaultUILanguage"); // NB: GetProcAddress() takes an ANSI string if(pfnGetUserDefaultUILanguage != NULL) { return pfnGetUserDefaultUILanguage(); } else { return 0; } } LANGID CLanguageSupport::GetSystemUILanguage() { HINSTANCE hKernel32= ::GetModuleHandle(_T("kernel32.dll")); ASSERT(hKernel32 != NULL); PFNGETSYSTEMDEFAULTUILANGUAGE pfnGetSystemDefaultUILanguage = (PFNGETSYSTEMDEFAULTUILANGUAGE)::GetProcAddress(hKernel32, "GetSystemDefaultUILanguage"); // NB: GetProcAddress() takes an ANSI string if(pfnGetSystemDefaultUILanguage != NULL) { return pfnGetSystemDefaultUILanguage(); } else { if (::GetVersion()&0x80000000) { DWORD dwLangID= 0; // Assume error HKEY hKey = NULL; LONG nResult = ::RegOpenKeyEx(HKEY_CURRENT_USER, _T( "Control Panel\\Desktop\\ResourceLocale" ), 0, KEY_READ, &hKey); if (nResult == ERROR_SUCCESS) { DWORD dwType; TCHAR szValue[16]; ULONG nBytes = sizeof( szValue ); nResult = ::RegQueryValueEx(hKey, NULL, NULL, &dwType, LPBYTE( szValue ), &nBytes ); if (nResult==ERROR_SUCCESS && dwType==REG_SZ) _stscanf( szValue, _T( "%x" ), &dwLangID ); ::RegCloseKey(hKey); } return (LANGID)dwLangID; } else { LANGID LangId = 0; HMODULE hNTDLL = ::GetModuleHandle( _T( "ntdll.dll" ) ); if (hNTDLL != NULL) { ::EnumResourceLanguages( hNTDLL, RT_VERSION, MAKEINTRESOURCE( 1 ), _EnumResLangProc, reinterpret_cast< LONG_PTR >( &LangId ) ); } return LangId; } } } bool CLanguageSupport::LoadLanguageDll() { if (m_nCurrentLanguage==m_nExeLanguage) { TRACE0("Resource DLL is... the EXE.\n"); UnloadResourceDll(); return true; } TCHAR szAbbrevName[4]; if (GetLocaleInfo(MAKELCID(m_nCurrentLanguage, SORT_DEFAULT), LOCALE_SABBREVLANGNAME, szAbbrevName, 4)==0) { TRACE1("Attempt to load DLL for unsupported language. Language = %u\n", m_nCurrentLanguage); return false; } TCHAR szFilename[MAX_PATH]; DWORD cch= GetModuleFileName( NULL, szFilename, MAX_PATH); ASSERT(cch!=0); LPTSTR pszExtension= PathFindExtension(szFilename); lstrcpy(pszExtension, szAbbrevName); lstrcat(pszExtension, _T(".dll")); HINSTANCE hDll = LoadLibrary(szFilename); if (hDll != NULL) { TRACE1("Resource DLL %s loaded successfully\n",szFilename); UnloadResourceDll(); m_hDll= hDll; SetResourceHandle(m_hDll); return true; } else return false; } CLanguageSupport::CLanguageSupport() { m_hDll= NULL; m_nCurrentLanguage= 0; LookupExeLanguage(); } CLanguageSupport::~CLanguageSupport() { UnloadResourceDll(); } void CLanguageSupport::UnloadResourceDll() { if (m_hDll!=NULL) { SetResourceHandle(AfxGetApp()->m_hInstance); FreeLibrary(m_hDll); m_hDll= NULL; } } void CLanguageSupport::SetResourceHandle(HINSTANCE hDll) { AfxSetResourceHandle(hDll); #if _MFC_VER>=0x0700 _AtlBaseModule.SetResourceInstance(hDll); #endif } LANGID CLanguageSupport::GetLangIdFromFile(LPCTSTR pszFilename) { DWORD dwHandle; DWORD dwLength=GetFileVersionInfoSize((LPTSTR)pszFilename,&dwHandle); if (dwLength==0) { TRACE(_T("Failed to read file's version info. Error= %1!u!\n"), GetLastError()); return 0; } LANGID nLangId=0; CByteArray abData; abData.SetSize(dwLength); if (GetFileVersionInfo((LPTSTR)pszFilename,dwHandle,dwLength,(LPVOID)abData.GetData())) { LANGID *pLanguageId; // NB: LANGID = WORD if (VerQueryValue(abData.GetData(),_T("\\VarFileInfo\\Translation"),(void**)&pLanguageId,(PUINT)&dwLength)) nLangId=*pLanguageId; } return nLangId; } void CLanguageSupport::OnSwitchLanguage(UINT nId, bool bLoadNewLanguageImmediately) { int nLanguageIndex= nId-ID_LANGUAGE_FIRST; if (nLanguageIndex<0 || nLanguageIndex>=m_aLanguages.GetSize()) return; LANGID LangId= m_aLanguages[nLanguageIndex]; AfxGetApp()->WriteProfileInt(_T(""),szLanguageId,(int)LangId); if (bLoadNewLanguageImmediately) { LoadBestLanguage(); } else { LANGID nCurrentLanguage= m_nCurrentLanguage; m_nCurrentLanguage= LangId; VERIFY(LoadLanguage()); CString csFormat(MAKEINTRESOURCE(IDS_RESTART)); // Don't forget to add a string in the String Table : m_nCurrentLanguage= nCurrentLanguage; VERIFY(LoadLanguage()); CString csMessage; csMessage.FormatMessage(csFormat, LPCTSTR(AfxGetAppName())); // IDS_RESTART : Please restart %1. AfxMessageBox(csMessage,MB_ICONINFORMATION); // Please restart MyApp. } } void CLanguageSupport::GetAvailableLanguages() { m_aLanguages.SetSize(0); if (m_nExeLanguage!=0) m_aLanguages.Add(m_nExeLanguage); TCHAR szFileMask[MAX_PATH+10]; DWORD cch= GetModuleFileName( NULL, szFileMask, MAX_PATH); ASSERT(cch!=0); LPTSTR pszExtension= PathFindExtension(szFileMask); lstrcpy(pszExtension, _T("???.dll")); CFileFind finder; BOOL bWorking = finder.FindFile(szFileMask); while (bWorking) { bWorking = finder.FindNextFile(); LANGID nLanguageID=GetLangIdFromFile(finder.GetFilePath()); if (nLanguageID!=0) m_aLanguages.Add(nLanguageID); } } void CLanguageSupport::CreateMenu(CCmdUI *pCmdUI, UINT nFirstItemId) { GetAvailableLanguages(); UINT nCurrentItem= 0; CMenu SubMenu; SubMenu.CreatePopupMenu(); for (int i=0; i { SubMenu.AppendMenu(MF_STRING, ID_LANGUAGE_FIRST+i, GetLanguageName(m_aLanguages[i]) ); if (m_nCurrentLanguage==m_aLanguages[i]) nCurrentItem= ID_LANGUAGE_FIRST+i; } if (nCurrentItem!=0) SubMenu.CheckMenuRadioItem(ID_LANGUAGE_FIRST, ID_LANGUAGE_FIRST+(int)m_aLanguages.GetSize()-1, nCurrentItem, MF_BYCOMMAND); MENUITEMINFO mii= { sizeof(mii) }; mii.fMask= MIIM_SUBMENU; mii.hSubMenu= SubMenu.m_hMenu; ::SetMenuItemInfo(pCmdUI->m_pMenu->m_hMenu, pCmdUI->m_nID, FALSE, &mii); pCmdUI->Enable(); SubMenu.Detach(); } CString CLanguageSupport::GetLanguageName(LANGID wLangId) { TCHAR szLanguage[200], szCP[10]; GetLocaleInfo( MAKELCID(wLangId, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, szCP, 10); int nAnsiCodePage= _ttoi(szCP); int cch= GetLocaleInfo( MAKELCID(wLangId, SORT_DEFAULT), LOCALE_SNATIVELANGNAME, szLanguage, countof(szLanguage)); if (cch!=0) { #ifndef UNICODE wchar_t szLanguageW[200]; cch= MultiByteToWideChar(nAnsiCodePage, MB_ERR_INVALID_CHARS, szLanguage, -1, szLanguageW, countof(szLanguageW)); BOOL bUsed= FALSE; cch= WideCharToMultiByte(CP_ACP, 0, szLanguageW, -1, szLanguage, countof(szLanguage), "X", &bUsed); if (bUsed || nAnsiCodePage==0) { cch= 0; } #endif } if (cch==0) { cch= GetLocaleInfo( MAKELCID(wLangId, SORT_DEFAULT), LOCALE_SLANGUAGE, szLanguage, countof(szLanguage)); if (cch==0) _stprintf(szLanguage, _T("%u - ???"), wLangId); // Ouch ! We can't even display the name in the current language ! } return szLanguage; } void CLanguageSupport::LookupExeLanguage() { TCHAR szFilename[MAX_PATH]={0}; DWORD cch= GetModuleFileName( NULL, szFilename, MAX_PATH); ASSERT(cch!=0); m_nExeLanguage= GetLangIdFromFile(szFilename); } |