资源DLL与语言选择菜单的实现

 
资源DLL 与语言选择菜单的实现
 
 
         简介
         在当今这个发展越来越快的世界中,软件的本地化及翻译工作越来越重要,极大地关系到软件的销量及普及率;就拿常见的Win32/MFC程序来说,一个比较方便的办法就是附加单独的资源DLL文件。
         本文介绍了一种易于应用的方法,可在C++/MFC程序中支持多种语言,并演示了怎样用少量的代码添加对资源DLL的支持,这包含了两个方面:根据用户偏好在程序开始时自动选择最合适的语言;提供一个语言选择子菜单(以供用户自行选择)。如图所示:
 
 
 
         关于资源DLL
         有关在程序中支持多语言最灵活的方法,也许就是使用所谓的“资源DLL”了,其主要思想是为每种语言创建一个单独的DLL文件,而这个DLL中包含了已翻译为某种特定语言的程序资源;因此,如果你的程序最初版本是中文,且又翻译成了法文、德文、日文,这样你就有了三个资源DLL。中文资源在.exe文件中,而其他三种语言各自对应一个DLL文件。
         如果程序中又需要支持某种新的语言,只须简单地添加一个DLL到安装文件中就行了。在程序运行时,会根据用户偏好,相应地加载资源DLL。
         资源DLL可由一个专门的Visual Studio工程来创建,也可由某些专用的工具来创建,本文以Visual Studio 2003来创建,Visual Studio 2005也差不多。顺便提一下,把所有的语言资源都打包进EXE文件,在理论上是可行的,但在实际中却行不通;因为,大多数加载资源的高层API——如LoadString()、DialogBox()等等——不会让你指定想要的语言,而SetThreadLocale()也不会如预期那样工作(此API在Win9X中不存在)。
 
 
         一步一步支持资源DLL
         以下是在主程序中,添加支持资源DLL(语言选择菜单)的步骤:
 
1、 把LanguageSupport.h及LanguageSupport.cpp添加到你的工程。
在MyApp.h及MyApp.cpp(假定CMyApp是工程类)中,加入以下黑体行:
 
#include "LanguageSupport.h"
 
class CMyApp : public CWinApp
{
public:
   CLanguageSupport m_LanguageSupport;
   ...
};
BOOL CMyApp::InitInstance()
{
   //把以下这行注释掉,防止MFC进行自己的资源DLL处理。
   // CWinApp::InitInstance();
   ...
   SetRegistryKey(_T("MyCompany"));
 
   //根据用户偏好,加载相应的资源DLL。
   m_LanguageSupport.LoadBestLanguage();
   ...
}
 
         在主菜单中,添加一个名为“语言(Language)”的菜单项。接下来,在CMainFrame类中,为“语言(Language)”菜单项添加一个菜单更新处理程序,假定名为OnUpdateToolsLanguage(),如下所示:
 
void CMainFrame::OnUpdateToolsLanguage(CCmdUI *pCmdUI)
{
 
   //创建语言子菜单(只在菜单第一次打开时)。
   theApp.m_LanguageSupport.CreateMenu(pCmdUI);
}
 
 
2、 为语言选择菜单项添加菜单处理程序。
在MainFrm.h中,把处理程序afx_msg void OnLanguage(UINT nID)添加在CMainFrame的protected部分中某处;在MainFrm.cpp中,添加定义及消息映射入口:
 
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
...
ON_COMMAND_RANGE(ID_LANGUAGE_FIRST,ID_LANGUAGE_LAST, OnLanguage)
//这些ID声明在LanguageSupport.h中
END_MESSAGE_MAP()
 
void CMainFrame::OnLanguage(UINT nID)
{ //用户选择了菜单中的某种语言
 theApp.m_LanguageSupport.OnSwitchLanguage(nID);
}
 
         注意,这个处理程序不能用向导来添加,因为它是一个COMMAND_RANGE菜单处理程序——用于处理“语言(Language)”菜单中所有语言项。
 
 
3、 也是最后一步,在字符资源表中,添加一个名为IDS_RESTART的字符串,值为“请重新运行%1”,%1可为程序名。
 
 
怎样创建资源DLL
         首先,CLanguageSupport类假定所有的DLL都名为MyAppXXX.dll,这里MyApp.exe是可执行文件名,XXX是所支持语言的三个字母缩写(CHN代表中文、FRA代表法文、DEU代表德文、JPN代表日文)。同时,exe文件与dll文件都应有一个Version版本信息资源,其语言匹配文件名中的三个缩写字母。接着,我们创建一个Win32 DLL工程:
 
1、 打开Visual Studio 2003,选择文件-新建-工程,输入工程名如MyAppDEU创建一个德文版本,单击确定;在程序设置页,选择DLL及空项目。
2、 把它转换为一个资源DLL:打开项目属性,在“配置”下拉框中选择“所有配置”;打开链接器-高级,将“纯资源DLL”设为“是”。另外,如果你使用Visual C++ 6.0,则需要手工在链接设置的编辑框中添加 /NOENTRY作为命令行选项;而Visual C++ 2005,与Visual C++ 2003类似,在链接器-高级里,选择“无入口点”为“是”。
3、 创建一份EXE资源文件的副本,并把它添加到DLL工程中:建议将MyApp.rc文件改名成所需的语言版本,如MyAppDEU.rc。
4、 修改路径:在资源视图中,鼠标右键单击MyAppDEU.rc,打开“资源包含”,修改所有包含资源文件的路径。每种语言都有会一个子目录l.xxx,例如,修改#include "afxres.rc"为#include "l.deu/afxres.rc"。
5、 设置语言属性:在资源视图中,打开“版本信息version info”(如果没有就创建一个),设置语言属性为正确的语言,如German(Germany),确保语言匹配DLL名中的三个字母。
 
         现在可以编译DLL了,之后便可得到一个资源DLL,当然,它还没有经过翻译,但这已是翻译者的任务了。按照上述步骤就可创建出一系统语言的DLL,你唯一要做的事情,就是把它们复制到应用程序的目录了。另外,从程序中加载资源DLL也非常简单,LoadLibrary()与AfxSetResourceHandle(hDll)就可以胜任了。
 
 
以下是源代码:
 
LanguageSupport.h
 
#pragma once
 
#include <afxcoll.h>
 
#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 <shlwapi.h>
 
#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<m_aLanguages.GetSize(); 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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MFC(Microsoft Foundation Class)是一种开发Windows桌面应用程序的框架,可以使用动态链接库(DLL)来实现中英文切换。 首先,我们需要创建一个DLL项目,并在其中添加资源文件,包括不同语言的字符串和对应的ID。比如,可以创建两个资源文件,一个是英文字符串,另一个是中文字符串,分别命名为en-US.res和zh-CN.res。 然后,在MFC应用程序中使用LoadLibrary函数加载DLL,并调用FindResource和LoadResource函数加载对应语言资源。可以通过设置不同的语言标识符参数来选择加载不同的资源。例如,对于英文资源,可以使用以下代码: HMODULE hModule = LoadLibrary(_T("dll路径")); HRSRC hResource = FindResource(hModule, MAKEINTRESOURCE(IDR_ENGLISH), RT_RCDATA); HGLOBAL hMemory = LoadResource(hModule, hResource); LPVOID lpResource = LockResource(hMemory); CString strEnglish((const char*)lpResource); FreeLibrary(hModule); 对于中文资源,只需将IDR_ENGLISH更改为IDR_CHINESE即可。 最后,使用CString或其他方法将获取的字符串显示在MFC应用程序的界面上,即可实现中英文切换。 需要注意的是,为了方便切换语言,在MFC应用程序中还需提供切换语言的选项或设置,通过相应的逻辑代码来实现切换时重新加载DLL并更新界面显示的字符串。 总结起来,借助MFC的特性和DLL的加载能力,我们可以在应用程序中通过加载不同的资源文件来实现中英文切换。 ### 回答2: 在MFC中使用DLL实现中英文切换,可以通过以下步骤进行: 第一步,创建一个DLL项目,用于存储中英文的字符串资源。可以在资源文件中添加对应的中英文字符串,并在代码中定义一个函数来获取这些字符串。 第二步,创建一个MFC应用程序项目。在应用程序的初始化过程中,加载DLL文件并获取所需要的字符串资源。可以使用LoadLibrary函数加载DLL文件,并使用GetProcAddress函数获取相应函数的地址。 第三步,创建一个语言选择界面,用于让用户选择要使用的语言。可以使用对话框或者菜单添加语言选项。用户选择语言后,将相应的语言标识保存在配置文件或注册表中。 第四步,根据用户选择的语言标识,动态修改应用程序中的字符串显示。可以通过调用DLL中的函数来获取对应的中英文字符串,然后将其显示在对应的界面控件上。 第五步,在应用程序的所有界面中添加语言切换的功能。可以在每个界面的菜单栏或功能栏上添加一个语言切换的按钮或选项,用户点击按钮或选择选项后,重新加载相应语言的字符串资源,并刷新界面中的所有文本。 通过以上步骤,就可以实现MFC应用程序的中英文切换功能。用户可以根据自己的需要选择合适的语言,并在应用程序中动态更改界面文字的显示。这样可以提供更好的用户体验,同时方便应对不同语言环境下的需求。 ### 回答3: 在MFC中实现中英文切换可以通过使用动态链接库(DLL)的方式来实现。首先,我们可以在资源文件中创建多语言版本的字符串资源,分别对应中文和英文。然后,将这些字符串资源保存到一个DLL文件中。 在MFC应用程序中,我们需要在主窗口初始化时加载这个DLL文件,以便在运行时可以动态切换语言。可以在InitInstance函数中使用LoadLibrary函数加载DLL文件,并使用AfxSetResourceHandle函数将资源句柄设置为DLL文件的句柄。 当需要切换语言时,我们可以通过调用AfxSetResourceHandle函数来重新设置资源句柄为DLL文件的句柄,然后强制重绘界面。这样就可以实现界面上的文本、标签等显示为不同的语言了。 另外,为了方便管理和切换语言,可以根据需求在应用程序中添加一个菜单或者工具栏,通过点击菜单项或者工具栏按钮在运行时切换语言。当用户通过菜单或者工具栏切换语言时,可以根据用户选择的语言,重新设置资源句柄为相应DLL文件的句柄,并强制重绘界面。 需要注意的是,在切换语言的过程中,我们需要注意重新加载语言资源,例如重新加载菜单资源、工具栏资源等,以便将其显示为对应的语言。 总的来说,通过使用DLL实现中英文切换可以让我们的应用程序更加灵活多语言化,提供更好的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值