title: MFC uses dll for multi language switching based on dialog box
categories:[MFC]
tags: [audio and video programming]
date: 2021/12/15
Author: hackett
WeChat official account: overtime ape
1, Foreword
Qt uses qm file switching. There are two loading methods, which are easier
Load in the resource file (this is better):
advantage:
- When the program is released, you don't have to put the latest qm files are copied to the loading path, which reduces the risk of no translation or inaccurate translation on the interface when modifying translation;
- The translated information will not be exposed to users;
Disadvantages:
- The resource file will compile the executable program, so it will lead to the larger volume of the executable program (but the. qm file is generally small, and this disadvantage can be ignored);
- When only the translation is modified and the source code is not modified, the executable must also be recompiled.
Load outside the program:
advantage:
- When you only modify the translation without modifying the source code, you don't need to recompile the executable, just replace the modified one qm documents;
- It will not affect the size of the executable program;
Disadvantages:
- When the program is released, it is necessary to update it qm file is copied to the corresponding loading path (this step is often forgotten in actual development), resulting in no translation or inaccurate translation;
- If the translation information is exposed to the user, it may be modified by the user (irresistible factors, which can be ignored).
There is a demand that the MFC interface needs to be switched between multiple languages. Baidu has made a lot of efforts. There are many ways to realize multiple languages in MFC:
- VS provides the "insert copy" method of the dialog box;
- Make the interface text to be displayed as an ini file. When loading the interface, each control uses SetWindowText to display different language contents;
- Make Dll resource files and call different DLLs in different languages;
Overall, the dll method is more suitable for your own needs, so use this to do it
2, Preparatory work
Create a new MFC project in visual studio
[file] - [new] - [PROJECT], select "MFC application", project name: test, and put it in the workspace folder
Select dialog based and cancel use Unicode library
[finish] complete the creation of MFC project based on dialog box.
There are two buttons in the interface, text and Edit Control
Right click Add Resource - menu - new to create a menu for language selection and add language switching options
Open test RC attribute, find the Menu in misc, and select IDR_MENU1 just now. After doing these, you can prepare for the production of dll
3, Make dll
Create English dll
In visual studio
Solution: right click [add] - [new project], select MFC DLL, enter the project name in English, and click OK
The MFC DLL wizard does not modify, but adopts the default shared MFC DLL rule settings and click finish.
Delete unwanted files from the DLL
Remove English under "resource file" of the project rc,English. RC2 file, resource under "header file" H file and delete it in the corresponding directory
Import related files:
Copy "test.rc" and "resource.h" under workspace\test to the folder test\English of the English DLL project.
Then copy all the files in the workspace\test\res folder of test to the folder corresponding to the English DLL project.
Then add the above files to the English project.
Right click the English item, and click Add - existing item, as shown in the figure
Modify the relevant resource attributes of the English project to English, and translate the corresponding button and text into English
Modify English project properties. [configuration attribute] - [linker] - [advanced], "no entry point" is changed to "Yes (/ NOENTRY)".
Next, you can right-click generate to generate English.dll
Chinese, Japanese and other language versions can be created according to the method of English project.
The display content in the text box can also be read from the configuration file in the same way as the language configuration
test.h
// test.h : PROJECT_NAME application's main header file // #pragma once #ifndef __AFXWIN_H__ #error "include" stdafx.h "before including this file to generate PCH file" #endif #include "resource.h" / / main symbol // CtestApp: // For the implementation of this class, see test cpp // class CtestApp : public CWinApp { public: CtestApp(); // rewrite public: virtual BOOL InitInstance(); // Add new code private: CString pExePath; char m_strLanguage[MAX_PATH]; HINSTANCE m_hLangDLL; // realization DECLARE_MESSAGE_MAP() }; extern CtestApp theApp;
test.cpp
// test.cpp: defines the class behavior of the application. // #include "stdafx.h" #include "test.h" #include "testDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CtestApp BEGIN_MESSAGE_MAP(CtestApp, CWinApp) ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() // CtestApp construction CtestApp::CtestApp() { // Support Restart Manager m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; // TODO: add construction code here, // Place all important initializations in InitInstance // New code // initialize variable memset(m_strLanguage,0,sizeof(m_strLanguage)); m_hLangDLL=NULL; } // The only CtestApp object CtestApp theApp; BOOL CtestApp::InitInstance() { // If an application manifest running on Windows XP specifies to // Use comctl32 DLL version 6 or later to enable visualization, //InitCommonControlsEx() is required. Otherwise, the window cannot be created. INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); // Set it to include all that you want to use in your application // Public control class. InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); CWinApp::InitInstance(); AfxEnableControlContainer(); // Create a shell manager in case the dialog box contains // Any shell tree view control or shell list view control. CShellManager *pShellManager = new CShellManager; // Standard initialization // If you do not use these functions and want to reduce // The size of the final executable, the following should be removed // Specific initialization routines not required // Change the registry key used to store settings // TODO: the string should be modified appropriately, // For example, change to company or organization name SetRegistryKey(_T("Local application generated by application wizard")); // ***********New code. Language selection********** // Read settings from INI file pExePath = CtestDlg::GetExePath(); pExePath += _T("\\ip.ini"); ::GetPrivateProfileString(_T("Language"), _T("currentlanguage"), _T(""),m_strLanguage, MAX_PATH, pExePath); // Load the corresponding DLL file switch (atoi(m_strLanguage)) { case LANG_CHINESE: m_hLangDLL=::LoadLibrary("Chinese.dll"); break; case LANG_ENGLISH: m_hLangDLL=::LoadLibrary("English.dll"); break; default: m_hLangDLL=::LoadLibrary("Chinese.dll"); break; } if (m_hLangDLL!=NULL) { AfxSetResourceHandle(m_hLangDLL); } else { AfxMessageBox("language DLL File loading failed!"); exit(1); // Abnormal termination procedure } // *************************************** CtestDlg dlg; m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: when to place processing here // Click OK to close the code of the dialog box } else if (nResponse == IDCANCEL) { // TODO: when to place processing here // "Cancel" to close the code of the dialog box } else if (nResponse == -1) { TRACE(traceAppMsg, 0, "warning: Dialog creation failed,The application will terminate unexpectedly if you use it on the dialog box MFC Control, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS. \n"); } // Delete the shell manager created above. if (pShellManager != NULL) { delete pShellManager; } // Since the dialog box is closed, FALSE will be returned to exit the application, // Instead of starting the application's message pump. return FALSE; }
testDlg.cpp
// testDlg.cpp: implementation file // #include "stdafx.h" #include "test.h" #include "testDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CAboutDlg dialog box for application about menu item class CAboutDlg : public CDialogEx { public: CAboutDlg(); // Dialog data enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // realization protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CtestDlg dialog box CtestDlg::CtestDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CtestDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // initialize variable m_hLangDLL=NULL; } void CtestDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CtestDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CtestDlg::OnBnClickedButton1) ON_COMMAND(ID_MENU_CHINESE, &CtestDlg::OnChinese) ON_COMMAND(ID_MENU_ENGLISH, &CtestDlg::OnEnglish) END_MESSAGE_MAP() // CtestDlg message handler BOOL CtestDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // "About..." Add menu items to the system menu. // IDM_ABOUTBOX must be within the scope of the system command. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Sets the icon for this dialog box. When the main window of the application is not a dialog box, the frame will automatically // Do this SetIcon(m_hIcon, TRUE); // Set large icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: add additional initialization code here m_menu.LoadMenu(IDR_MENU1); // Note that you need to load the menu here SetMenu(&m_menu); return TRUE; // Returns TRUE unless the focus is set to the control } void CtestDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // If you add the minimize button to the dialog box, you need the following code // To draw the icon. For MFC applications that use the document / view model, // This will be done automatically by the framework. void CtestDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // Device context for drawing SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // Centers the icon in the workspace rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // draw icon dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //When the user drags the minimized window, the system calls this function to obtain the cursor //Display. HCURSOR CtestDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } CString CtestDlg::GetExePath() { char szExePath[MAX_PATH] = {0}; GetModuleFileName(AfxGetApp()->m_hInstance, szExePath, 256); int i = (int)strlen(szExePath) - 1; for (; i >= 0 && szExePath[i] != '\\'; i--) ; szExePath[i + 1] = 0; return szExePath; } void CtestDlg::OnBnClickedButton1() { } BOOL CtestDlg::ResetDialog() { //TODO: processing additional resources that may have been added AfxOleTerm(FALSE); if(m_hLangDLL) { FreeLibrary(m_hLangDLL); } STARTUPINFO StartupInfo={0}; PROCESS_INFORMATION ProcessInfo; StartupInfo.cb=sizeof(STARTUPINFO); char Path[256]; GetModuleFileName(NULL,(LPSTR)(LPCTSTR)Path,250); CreateProcess(NULL,(LPSTR)(LPCTSTR)Path,NULL,NULL,FALSE,0,NULL,NULL,&StartupInfo,&ProcessInfo); return TRUE; } void CtestDlg::OnChinese() { // TODO: add command handler code here pExePath = GetExePath(); pExePath += _T("\\ip.ini"); int iRet = MessageBox(_T("Make sure to switch to the Chinese version?"),_T("Tips"),MB_YESNO); if (iRet == IDYES) { WritePrivateProfileString(_T("Language"), _T("currentlanguage"), "0", pExePath); m_hLangDLL=::LoadLibrary("Chinese.dll"); if (m_hLangDLL!=NULL) { ResetDialog(); AfxSetResourceHandle(m_hLangDLL); exit(1); } else { AfxMessageBox("language Chinese.dll File loading failed!"); exit(1); // Abnormal termination procedure } } } void CtestDlg::OnEnglish() { // TODO: add command handler code here pExePath = GetExePath(); pExePath += _T("\\Config.ini"); int iRet = MessageBox(_T("OK to switch to English version?"),_T("Tips"),MB_YESNO); if (iRet == IDYES) { WritePrivateProfileString(_T("Language"), _T("currentlanguage"), "1", pExePath); m_hLangDLL=::LoadLibrary("English.dll"); if (m_hLangDLL!=NULL) { ResetDialog(); AfxSetResourceHandle(m_hLangDLL); exit(1); } else { AfxMessageBox("language English.dll File loading failed!"); exit(1); //Abnormal termination procedure } } }
testDlg.h
// testDlg.h: header file // #pragma once // Add macro definition #define LANG_CHINESE 0 #define LANG_ENGLISH 1 #define LANG_JAPNESE 2 // CtestDlg dialog box class CtestDlg : public CDialogEx { // structure public: CtestDlg(CWnd* pParent = NULL); // Standard Constructors // Dialog data enum { IDD = IDD_TEST_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // realization protected: HICON m_hIcon; // Generated message mapping function virtual BOOL OnInitDialog(); virtual BOOL ResetDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedButton1(); afx_msg void OnChinese(); afx_msg void OnEnglish(); static CString GetExePath(); CString pExePath; HINSTANCE m_hLangDLL; CMenu m_menu; };
ip.ini
[Language] currentlanguage=0
4, Pit encountered
1. When using dll for multi language switching, do not use MFC Button Control type buttons, but ordinary buttons (otherwise the program will flash)
Finally, a rendering:
If you think the article is good, you can give a "three links", and the article is synchronized to the personal WeChat official account.
I'm hackett. I'll see you next time