| |
简单实用资源DLL与语言选择菜单的实现 |
|
时间: 2007-07-24 来自:天极yesky |
 |
|
|
以下是源代码:
以下是引用片段: 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);
} |
|
|
|
|
|
|
|
|