Prev: I love MFC!
Next: Using CMFCToolBar and CMFCMenuBar?
From: Joseph M. Newcomer on 19 Jun 2010 15:47 See below... On Sat, 19 Jun 2010 19:59:56 +0100, "David Webber" <dave(a)musical-dot-demon-dot-co.uk> wrote: >"mfc" <mfcprog(a)googlemail.com> wrote in message >news:b9035371-3a58-4c69-85f4-da5ba2210472(a)h13g2000yqm.googlegroups.com... > >> 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. >>... > >Vis a vis some of Joe's criticisms, the way I do it is as follows: > >Resource only DLLs are in the same directory as the exe. They all have >names of the form > >mozartfra.dll >mozartdeu.dll >mozartcym.dll > >At launch the program looks for all dlls with names of this form >(mozart???.dll) , and attempts to load one or two strings from their >resources, including the full name of the language > > (francais) > (deutsch) > (cymraeg) *** I didn't bother to load the DLLs explicitly, I used a field in the VERSIONINFO to hold the printable string I wanted: "Keyboard", "Fretted Instrument", "Score" and just used that to find my menu string **** > >which is (by my defined convention) always present with the same resource >ID. > >From this I construct a table of language-name vs dll-name (the letters in >the dll name are just for my convenience - the program doesn't need them). >Then it unloads all the DLLs. **** I did the same trick **** > >When you need to change language, the program presents a list of language >names, and selecting the language loads the corresponding DLL, and remembers >its HINSTANCE. > >All resources are loaded from within members of a language manager class, >which holds the HINSTANCE of the language DLL in use (or NULL if English) >and the hInstance of the main program (with the English resources). > >The language manager class constructor, remembers the current resource >handle and calls AfxSetResourceHandle() to the DLL where the resources are >required. The destructor sets AfxSetResurceHandle() to the old HINSTANCE. >All calls to loading strings, menus, dialogues, toolbars,.... are done from >members of the language manager class, so they must be done between >construction and destruction, when the resource handle is as desired. > >It works quite transparently, and no-one knows what language any DLL >contains except the DLL itself! > >Dave Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Mihai N. on 20 Jun 2010 05:09 > 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. For anything beyond a trivial application, you should just give up. Once you change the current resource dll, to update everything you would really have to destroy all existing menus and dialogs and re-load them from the new dll, refresh all views, update all titles, etc. The use cases where an "on they fly" update is justified are realy low. I would recomend to do what most applications do: once the user changes the language, save the setting somewhere, show a message saying "the change will take effect the next time you start the application" and call it a day. At the next application start read the saved setting very-very early in the startup process and load the resource dll. -- Mihai Nita [Microsoft MVP, Visual C++] http://www.mihai-nita.net ------------------------------------------ Replace _year_ with _ to get the real email
From: mfc on 20 Jun 2010 07:27 >Note also that features that *require* correct settings in the Registry are *very* >suspect. You *must* assume that *no* Registry key or value is defined, and do something >intelligent anyway. Defaulting to the default user locale is a good approach. I refuse >to use SetRegistryKey because of all the problems it has. joe Which way do you prefer in the initInstance method instead of using SetRegistryKey? InitCommonControls(); SetRegistryKey(_T("Local AppWizard-Generated Applications")); m_LanguageSupport.LoadBestLanguage(); // <-- Add this line (after the call to SetRegistryKey) LoadStdProfileSettings(4); best regards Hans And many thanks for your time to help me get this prog working
From: David Webber on 20 Jun 2010 09:39 "Mihai N." <nmihai_year_2000(a)yahoo.com> wrote in message news:Xns9D9D15F01DF9DMihaiN(a)207.46.248.16... >> 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. > > For anything beyond a trivial application, you should just give up. > Once you change the current resource dll, to update everything you > would really have to destroy all existing menus and dialogs and > re-load them from the new dll, refresh all views, update all titles, > etc. > > The use cases where an "on they fly" update is justified are realy low. > > I would recomend to do what most applications do: once the user changes > the language, save the setting somewhere, show a message saying > "the change will take effect the next time you start the application" > and call it a day. > At the next application start read the saved setting very-very early > in the startup process and load the resource dll. With the *old* menu structure generated by the AppWizard, it isn't hard to do it on the fly. Just load the new menu from the DLL for Document present (hMenuDoc) and no Document present, (hMenuNoDoc) and then: // Update the document menu, which is held as a static member // of CMyDoc: HMENU hMenuDocOld = CMyDoc::mdDefaultMenuSet( hMenuDoc ); // Update the non-document menu, which is held as // m_hMenuDefault in the frame window: HMENU hMenuNoDocOld = pFrameWnd->m_hMenuDefault; // the current default. pFrameWnd->m_hMenuDefault = hMenuNoDoc; pFrameWnd->OnUpdateFrameMenu( NULL ); pFrameWnd->DrawMenuBar(); // Tidy up old menus: if( hMenuDocOld ) ::DestroyMenu( hMenuDocOld ); if( hMenuNoDocOld ) ::DestroyMenu( hMenuNoDocOld ); with: HMENU CMyDoc::mdDefaultMenuSet( HMENU hMenuDoc ) { HMENU hMenuOld = m_hMenuMzDocument; m_hMenuMzDocument = hMenuDoc; return hMenuOld; } Caveat: I have yet to find out whether this works with fancy new CMFCMenuBar, but I intend to explore it before too long. Dave -- David Webber Mozart Music Software http://www.mozart.co.uk For discussion and support see http://www.mozart.co.uk/mozartists/mailinglist.htm
From: Goran on 20 Jun 2010 13:19
On Jun 19, 4:15 pm, Joseph M. Newcomer <newco...(a)flounder.com> wrote: > Why is code to manipulate TheApp not part of the CWinApp-derived class? > > If this code is manipulating the CWinApp-derived class, this handler should be part of the > CWinApp-derived class, not the main frame! > > Oh, I see. To avoid a "global variable", you tossed some random stuff into the CWinApp > class. As a style, this sucks. Yes, yes, yes. To expand: doing this as a matter of fact, over time, creates MASSIVE compile-time dependencies. I have that (decade,5 old code base). I can't tell how much I've come to despise them. I really wish MSDN said something on the lines of "never add, only override, members of CWinApp" from the get go (when I was learning it). In fact, I remember tutorials saying quite the opposite. :-( I also wish tutorials said: "apply interface segregation principle to your document class", for same compile-time dependencies reason. But I can't blame MFC people for that; I don't think ISP was even formulated when MFC was coming out :-(. Goran. |