Prev: I love MFC!
Next: Using CMFCToolBar and CMFCMenuBar?
From: mfc on 18 Jun 2010 13:30 Hi, I`ve a sdi application where I want to add multiple language support. If the user press the button btn1, the language should be changed. After the OnButtonClick-Function I`m using SendMessage to send a msg to one function in the mainframe-class (class CMainFrame : public CFrameWnd) This is the function in the CMainFrame() - only a small demo: HINSTANCE hInst = NULL; if(!m_hInstGerman) m_hInstGerman = LoadLibrary(_T("LangDeu.dll")); hInst = m_hInstGerman; if(hInst) AfxSetResourceHandle(hInst); //CTestDialog dlg(this); //dlg.DoModal(); //dlg.ShowWindow(SW_SHOW); Which commands will be missing here to start the new language-dialog? At the moment - nothing happens; the code will be executed without any errors and the dll is loaded. Within the vs-project-map: I`ve one main-project (with doc/view sdi app) with the resources (first shown dialog) and I`ve installed two further projects which only includes the resource-files (one for German and one for English). Both have the same resources (dialogs) as the main-project. main-project: resource: IDD_MAIN_DIALOG german-dll-project: resourec: IDD_MAIN_DIALOG (with German strings - the same for the English one) Thanks for your hints! best regards Hans
From: Joseph M. Newcomer on 18 Jun 2010 14:41 Why is there *any* button called "btn1". The FIRST thing you do when creating controls is change all those stupid default IDs (e.g., IDC_BUTTON1) to something meaningful (e.g. IDC_ASK_USER_FOR_NAME). Only then do you start to create variables (which will have meaningful names, like c_AskUserForName) and handlers (e.g., OnBnClickedAsUserForName). So already you are digging yourself into a pit of unmaintainability. On Fri, 18 Jun 2010 10:30:36 -0700 (PDT), mfc <mfcprog(a)googlemail.com> wrote: >Hi, > >I`ve a sdi application where I want to add multiple language support. >If the user press the button btn1, the language should be changed. > >After the OnButtonClick-Function I`m using SendMessage to send a msg >to one function in the mainframe-class >(class CMainFrame : public CFrameWnd) > >This is the function in the CMainFrame() - only a small demo: > >HINSTANCE hInst = NULL; > >if(!m_hInstGerman) > m_hInstGerman = LoadLibrary(_T("LangDeu.dll")); **** There are so many things wrong with the above code I cannot hope to list all of them. Why is there an m_hInstGerman? Do you plan to add a variable for each of the several hundred languages supported? Will there be an hInstItalian_Italy, hinstItalian_Swiss, an hInstSpanish_Mexican, an hInstFrench_Canadian? Of course not. One local instance variable will suffice for all possible languages and that's all you should ever need. In the worst case, using a simple std::map to map language abbreviations to DLL handles might be used, if you want to support the user dynamically switching languages. Or, you can compute the DLL name (GetModuleFileName) and only load the DLL if the name you get is different from the one you have (don't forget to FreeLibrary the one you are about to replace!) Why are you not forming the name from the user's current selected active language? Why did you hardwire it to "LangDeu.dll"? Do you plan to add code like the above for each of the hundreds of languages supported by Windows? Play with my Locale Explorer (see my MVP Tips site). It will even generate the code for you! From the Locale Explorer: // LOCALE_SABBREVLANGNAME CString sabbrevlangname_data; LCID lcid = LOCALE_SYSTEM_DEFAULT; { /* get LOCALE_SABBREVLANGNAME */ LPTSTR p = sabbrevlangname_data.GetBuffer(4); VERIFY(::GetLocaleInfo(lcid, LOCALE_SABBREVLANGNAME, p, 4)); sabbrevlangname_data.ReleaseBuffer(); } /* get LOCALE_SABBREVLANGNAME */ // ... use sabbrevlangname_data here **** > >hInst = m_hInstGerman; **** I have no idea why you need m_hInstGerman at all! It doesn't make any sense to have a variable for every possible language, because you simply don't know at the time you compile this how many languages are going to be supported by Windows! Note that your plan to deliver, say, only a German and English DLL is irrelevant. If I speak English and Esperanto, I can trivially create an Esperanto DLL. If Esperanto were a language supported by MIcrosoft (who knows if they won't support it in the future?) then I would want to use it. Since you don;t know what DLLs are going to be available, you are making a serious error assuming that it is the "other one" of yours. ***** > >if(hInst) > AfxSetResourceHandle(hInst); ***** if(hInst != NULL) It is a horrible artifact of poor C instruction that makes people think that testing a non-boolean value like you did could possibly make sense. Bad C manuals encourage this. **** > >//CTestDialog dlg(this); >//dlg.DoModal(); >//dlg.ShowWindow(SW_SHOW); > >Which commands will be missing here to start the new language-dialog? **** The ones you commented out. Note that the ShowWindow is a complete nonsense line and will, in fact, generate an assertion error at runtime because after the DoModal returns, the dlg window DOES NOT EXIST so trying to show it at that point makes no sense! **** >At the moment - nothing happens; the code will be executed without any >errors and the dll is loaded. **** Well, since you commented out the DoModal, do not expect much to happen! **** > > >Within the vs-project-map: I`ve one main-project (with doc/view sdi >app) with the resources (first shown dialog) and I`ve installed two >further projects which only includes the resource-files (one for >German and one for English). Both have the same resources (dialogs) as >the main-project. **** The fact that resources of the same ID exist in the main project is kind of scary. I would never do that. **** > >main-project: >resource: IDD_MAIN_DIALOG > > >german-dll-project: >resourec: IDD_MAIN_DIALOG (with German strings - the same for the >English one) > > >Thanks for your hints! > >best regards >Hans Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: mfc on 18 Jun 2010 15:55 On 18 Jun., 20:41, Joseph M. Newcomer <newco...(a)flounder.com> wrote: > Why is there *any* button called "btn1". The FIRST thing you do when creating controls is > change all those stupid default IDs (e.g., IDC_BUTTON1) to something meaningful (e.g. > IDC_ASK_USER_FOR_NAME). Only then do you start to create variables (which will have > meaningful names, like c_AskUserForName) and handlers (e.g., OnBnClickedAsUserForName). > > So already you are digging yourself into a pit of unmaintainability. > > > > > > On Fri, 18 Jun 2010 10:30:36 -0700 (PDT), mfc <mfcp...(a)googlemail.com> wrote: > >Hi, > > >I`ve a sdi application where I want to add multiple language support. > >If the user press the button btn1, the language should be changed. > > >After the OnButtonClick-Function I`m using SendMessage to send a msg > >to one function in the mainframe-class > >(class CMainFrame : public CFrameWnd) > > >This is the function in the CMainFrame() - only a small demo: > > >HINSTANCE hInst = NULL; > > >if(!m_hInstGerman) > > m_hInstGerman = LoadLibrary(_T("LangDeu.dll")); > > **** > There are so many things wrong with the above code I cannot hope to list all of them. > > Why is there an m_hInstGerman? Do you plan to add a variable for each of the several > hundred languages supported? Will there be an hInstItalian_Italy, hinstItalian_Swiss, an > hInstSpanish_Mexican, an hInstFrench_Canadian? Of course not. One local instance > variable will suffice for all possible languages and that's all you should ever need. In > the worst case, using a simple std::map to map language abbreviations to DLL handles might > be used, if you want to support the user dynamically switching languages. Or, you can > compute the DLL name (GetModuleFileName) and only load the DLL if the name you get is > different from the one you have (don't forget to FreeLibrary the one you are about to > replace!) > > Why are you not forming the name from the user's current selected active language? Why > did you hardwire it to "LangDeu.dll"? > > Do you plan to add code like the above for each of the hundreds of languages supported by > Windows? > > Play with my Locale Explorer (see my MVP Tips site). It will even generate the code for > you! > > From the Locale Explorer: > > // LOCALE_SABBREVLANGNAME > CString sabbrevlangname_data; > LCID lcid = LOCALE_SYSTEM_DEFAULT; > { /* get LOCALE_SABBREVLANGNAME */ > LPTSTR p = sabbrevlangname_data.GetBuffer(4); > VERIFY(::GetLocaleInfo(lcid, LOCALE_SABBREVLANGNAME, p, 4)); > sabbrevlangname_data.ReleaseBuffer();} /* get LOCALE_SABBREVLANGNAME */ > > // ... use sabbrevlangname_data here thanks for all these information. Do you know which steps I`ve to do to start a new dll (during running the programm)? Or is it only possible to restart the programm to start a new dll??? All the steps which are necessary after loading the new dll file with LoadLibrary()...
From: mfc on 18 Jun 2010 16:57 On 18 Jun., 21:55, mfc <mfcp...(a)googlemail.com> wrote: > On 18 Jun., 20:41, Joseph M. Newcomer <newco...(a)flounder.com> wrote: > > > > > > > Why is there *any* button called "btn1". The FIRST thing you do when creating controls is > > change all those stupid default IDs (e.g., IDC_BUTTON1) to something meaningful (e.g. > > IDC_ASK_USER_FOR_NAME). Only then do you start to create variables (which will have > > meaningful names, like c_AskUserForName) and handlers (e.g., OnBnClickedAsUserForName). > > > So already you are digging yourself into a pit of unmaintainability. > > > On Fri, 18 Jun 2010 10:30:36 -0700 (PDT), mfc <mfcp...(a)googlemail.com> wrote: > > >Hi, > > > >I`ve a sdi application where I want to add multiple language support. > > >If the user press the button btn1, the language should be changed. > > > >After the OnButtonClick-Function I`m using SendMessage to send a msg > > >to one function in the mainframe-class > > >(class CMainFrame : public CFrameWnd) > > > >This is the function in the CMainFrame() - only a small demo: > > > >HINSTANCE hInst = NULL; > > > >if(!m_hInstGerman) > > > m_hInstGerman = LoadLibrary(_T("LangDeu.dll")); > > > **** > > There are so many things wrong with the above code I cannot hope to list all of them. > > > Why is there an m_hInstGerman? Do you plan to add a variable for each of the several > > hundred languages supported? Will there be an hInstItalian_Italy, hinstItalian_Swiss, an > > hInstSpanish_Mexican, an hInstFrench_Canadian? Of course not. One local instance > > variable will suffice for all possible languages and that's all you should ever need. In > > the worst case, using a simple std::map to map language abbreviations to DLL handles might > > be used, if you want to support the user dynamically switching languages. Or, you can > > compute the DLL name (GetModuleFileName) and only load the DLL if the name you get is > > different from the one you have (don't forget to FreeLibrary the one you are about to > > replace!) > > > Why are you not forming the name from the user's current selected active language? Why > > did you hardwire it to "LangDeu.dll"? > > > Do you plan to add code like the above for each of the hundreds of languages supported by > > Windows? > > > Play with my Locale Explorer (see my MVP Tips site). It will even generate the code for > > you! > > > From the Locale Explorer: > > > // LOCALE_SABBREVLANGNAME > > CString sabbrevlangname_data; > > LCID lcid = LOCALE_SYSTEM_DEFAULT; > > { /* get LOCALE_SABBREVLANGNAME */ > > LPTSTR p = sabbrevlangname_data.GetBuffer(4); > > VERIFY(::GetLocaleInfo(lcid, LOCALE_SABBREVLANGNAME, p, 4)); > > sabbrevlangname_data.ReleaseBuffer();} /* get LOCALE_SABBREVLANGNAME */ > > > // ... use sabbrevlangname_data here > > thanks for all these information. Do you know which steps I`ve to do > to start a new dll (during running the programm)? Or is it only > possible to restart the programm to start a new dll??? > > All the steps which are necessary after loading the new dll file with > LoadLibrary()...- Zitierten Text ausblenden - > > - Zitierten Text anzeigen - I`ve found a good working example besides the effect that the language didn`t change the dll on-the-fly http://read.pudn.com/downloads83/sourcecode/chinese/319271/LanguageSupport.cpp__.htm void CLanguageSupport::OnSwitchLanguage(UINT nId, bool bLoadNewLanguageImmediately) with bLoadNewLanguageImmediately = TRUE; Everything seems to be ok, but it doesn`t work... maybe you know where the problem would be? best regards Hans
From: Joseph M. Newcomer on 18 Jun 2010 17:00
See below... On Fri, 18 Jun 2010 12:55:24 -0700 (PDT), mfc <mfcprog(a)googlemail.com> wrote: >On 18 Jun., 20:41, Joseph M. Newcomer <newco...(a)flounder.com> wrote: >> Why is there *any* button called "btn1". �The FIRST thing you do when creating controls is >> change all those stupid default IDs (e.g., IDC_BUTTON1) to something meaningful (e.g. >> IDC_ASK_USER_FOR_NAME). �Only then do you start to create variables (which will have >> meaningful names, like c_AskUserForName) and handlers (e.g., OnBnClickedAsUserForName). >> >> So already you are digging yourself into a pit of unmaintainability. >> >> >> >> >> >> On Fri, 18 Jun 2010 10:30:36 -0700 (PDT), mfc <mfcp...(a)googlemail.com> wrote: >> >Hi, >> >> >I`ve a sdi application where I want to add multiple language support. >> >If the user press the button btn1, the language should be changed. >> >> >After the OnButtonClick-Function I`m using SendMessage to send a msg >> >to one function in the mainframe-class >> >(class CMainFrame : public CFrameWnd) >> >> >This is the function in the CMainFrame() - only a small demo: >> >> >HINSTANCE hInst = NULL; >> >> >if(!m_hInstGerman) >> > � �m_hInstGerman = LoadLibrary(_T("LangDeu.dll")); >> >> **** >> There are so many things wrong with the above code I cannot hope to list all of them. >> >> Why is there an m_hInstGerman? �Do you plan to add a variable for each of the several >> hundred languages supported? �Will there be an hInstItalian_Italy, hinstItalian_Swiss, an >> hInstSpanish_Mexican, an hInstFrench_Canadian? �Of course not. �One local instance >> variable will suffice for all possible languages and that's all you should ever need. �In >> the worst case, using a simple std::map to map language abbreviations to DLL handles might >> be used, if you want to support the user dynamically switching languages. �Or, you can >> compute the DLL name (GetModuleFileName) and only load the DLL if the name you get is >> different from the one you have (don't forget to FreeLibrary the one you are about to >> replace!) >> >> Why are you not forming the name from the user's current selected active language? �Why >> did you hardwire it to "LangDeu.dll"? >> >> Do you plan to add code like the above for each of the hundreds of languages supported by >> Windows? >> >> Play with my Locale Explorer (see my MVP Tips site). It will even generate the code for >> you! >> >> From the Locale Explorer: >> >> // LOCALE_SABBREVLANGNAME >> CString sabbrevlangname_data; >> LCID lcid = LOCALE_SYSTEM_DEFAULT; >> { /* get LOCALE_SABBREVLANGNAME */ >> �LPTSTR p = sabbrevlangname_data.GetBuffer(4); >> �VERIFY(::GetLocaleInfo(lcid, LOCALE_SABBREVLANGNAME, p, 4)); >> �sabbrevlangname_data.ReleaseBuffer();} /* get LOCALE_SABBREVLANGNAME */ >> >> // ... use sabbrevlangname_data here > >thanks for all these information. Do you know which steps I`ve to do >to start a new dll (during running the programm)? Or is it only >possible to restart the programm to start a new dll??? > >All the steps which are necessary after loading the new dll file with >LoadLibrary().. **** LoadLibrary is all you need to do to load the DLL. The AfxSetResourceHandle makes the DLL be the default source for the resources. Note that the DLL has to contain *all* the resources you need, not just some, and for safety, the executable should have none of these resources. It should only have enough resources to get the system up prior to InitInstance, which means, essentially, no resources at all, and a few to report that the DLL is missing. Use the above code to get the 3-letter locale ID (I found that there are five German languages supported: Austria, Germany, Switzerland, Leichtenstein and Luxembourg, so supporting DEU supports only one of them. And to get the LCID, you would use LOCALE_USER_DEFAULT as the constant instead of the MAKELCID macro. joe **** > > > > > Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm |