![]() |
Languages »
C / C++ Language »
General
Intermediate
Internationalization and Multiple Language SupportBy Ted FerencChanging the language of a Windows program on the fly using resource only DLLs. |
VC6Win2K, WinXP, MFC, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

This is a simple article showing how one can internationalize a Windows program, changing the menu, accelerators, dialog boxes, and common dialogs (the file open dialog is used in this example) etc. on the fly. I have seen many questions on the newsgroups about this, but have yet to see a good, simple, example.
This code is based on snippets of information found in various newsgroups.
The code is contained primarily in one function, CMainFrame::SetLanguage,
it is partially displayed below. The source code does have more comments and also
has the ability to set the language based on the PC's locale.
If a resource DLL has been loaded we should remove it, this is done in the destructor.
if(m_hInstFrench)
FreeLibrary(m_hInstFrench);
We simply branch on the language we want and load the relevant DLL using LoadLibrary.
The library is kept in memory once it is loaded, because removing it when a new language
was required caused problems with accelerators in NT4, this is described later.
if(!m_hInstFrench) m_hInstFrench = LoadLibrary(_T("LangFRA.dll"));
If a resource DLL was loaded we need to set the MultiLang's resource handle to
the handle of the DLL from which the application�s resources will be loaded. Otherwise
we use m_hInstEnglish, which is initially set to AfxGetInstanceHandle(), to obtain the current instance of the application, and use that
to load the resource from the EXE.
if(hInst) AfxSetResourceHandle(hInst); else AfxSetResourceHandle(m_hInstEnglish);
The menu has to be changed to be the one from our resource DLL.
It should be noted that we need to get the menu from the CMainFrame, this is because we in
effect need to force a change of any elements that are currently displayed. The dialog boxes,
as you will see will be displayed in the correct language automatically, in this example, the About box.
New is used to create the new CMenu so we can then use SetMenu() to set the
current menu to the new menu. This causes the window to be redrawn to
reflect the menu change.
Any other redraws etc. must be done as well, such as updating the status bar with "Ready", using new accelerators, or re-painting any windows that display text.
CMenu *pMenuCurrent = GetMenu();
// Create a new menu instance, we need to use this in SetMenu
m_pMenuNew = new CMenu;
// has the menu changed?
// m_hMenuDefault is the default menu resource for this frame see AFXWIN.H
if(pMenuCurrent->m_hMenu != m_hMenuDefault)
{
// Destroy the "New" menu and delete the resource
// We, after all created it!
pMenuCurrent->DestroyMenu();
delete pMenuCurrent;
}
// Load our new resource, menu and
m_pMenuNew->LoadMenu(IDR_MAINFRAME);
// Displauy the new menu
SetMenu(m_pMenuNew);
Method CMainFrame::GetDate() shows how to use _tsetlocale()
and _tcsftime() to display the current date the langauge we have specified.
These need to be loaded every time the language changes, during testing on NT4 it was found that if the resource only DLL was unloaded when not required the accelerators would not change the next time the language changed. So once loaded they stay in memory until no longer required. Each language uses a different set of accelerators as a test.
// m_hAccelTable is used in Winfrm.cpp as the accelerator handle,
// only one accelerator can be loaded at a time so we MUST clear it
m_hAccelTable = NULL;
bOK = LoadAccelTable(MAKEINTRESOURCE(IDR_MAINFRAME));
MSDN article Q102332 "How to Show a Custom Common Dialog using CFileDialog"
describes how to do this using CFileDialog, this example uses the Win32 function
GetOpenFileName(). Although the code is the same for both methods there appears
to be a bug when using CFileDialog and Visual C++ 6.0, this will be investigated later.
The code for this is CMainFrame::OnFileOpen(). Visual C++ provides some templates, these can be found in one of the Visual C++ directories they have .dlg
suffices, the example uses Fileopen.dlg, to use this do the following:-
Fileopen.dlg.
#include <dlgs.h>,
as a "Read-only symbol directive".
#include <dlgs.h> to the source file in which GetOpenFileName is to be used.
The OFN_ENABLETEMPLATE has to be added to the Flags member of the OPENFILENAME structure, the magic number
1537 is the resource template ID.
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST |
OFN_ENABLETEMPLATE | OFN_NONETWORKBUTTON;
ofn.hInstance = AfxGetResourceHandle();
ofn.lpTemplateName = MAKEINTRESOURCE(1537);
Should there be a mistake in the template, the dialog will not be displayed! There has to be one template per language, so this is not an ideal solution, and every common dialog box, and style of dialog box, that is used would need to be called this way.
This is a "Win32 Dynamic-Link Library", a Resource Only DLL. To create it, do the following:
\NOENTRY in the "Project Settings", "Linker" pane,
"Project Options" section.
| 1.00 |
|
| 1.01 |
|
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 14 Dec 2002 Editor: Nick Parker |
Copyright 2002 by Ted Ferenc Everything else Copyright © CodeProject, 1999-2009 Web19 | Advertise on the Code Project |