From: David Webber on
"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)

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.

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

--
David Webber
Mozart Music Software
http://www.mozart.co.uk
For discussion and support see
http://www.mozart.co.uk/mozartists/mailinglist.htm



From: Joseph M. Newcomer on
See below...
On Sat, 19 Jun 2010 08:12:55 -0700 (PDT), mfc <mfcprog(a)googlemail.com> wrote:

>On 19 Jun., 16:20, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
>> See below...
>>
>> On Sat, 19 Jun 2010 04:56:30 -0700 (PDT), mfc <mfcp...(a)googlemail.com> wrote:
>> >The whole application is a sdi application with the doc/view modell;
>> >therefore I`m loading a dialog at the startup with e.g. buttons etc.
>>
>> >CMLSampleView::CMLSampleView()
>> > � �: CFormView(CMLSampleView::IDD)
>> >{
>> > � �// TODO: add construction code here
>>
>> >}
>>
>> >IDD is the id from the dialog box, generated by the resoure editor.
>> >I`ve copied this dialog box to the other projects (satellite dlls for
>> >German and for English); Maybe this approach is wrong....
>>
>> ****
>> No, it looks fine. �Key here is that you have to switch languages in the InitInstance
>> handler.
>> ****
>>
>> >In the end, when the programm is started, the user should see a sdi
>> >window app where he can switch to different languages by some
>> >cbuttons. There will be no menu in the end application.
>>
>> ****
>> Switching the resource which is the SDI CFormView is much harder. �What you have to do is
>> create a new CFormView using the new dialog template, attach it to the document, and
>> destroy the original CFormView. �Note that you should use UpdateAllViews with a nonzero
>> lHint to tell any existing view to store its control contents in the document, and upon
>> completion, use UpdateAllViews with a different nonzero lHint to tell the form to retrieve
>> any existing data from the document and put it into the current view. �Otherwise, if you
>> switch views with information in the controls, the information would be lost.
>>
>> See the MSDN example on how to switch views of an SDI app.
>> � � � � � � � � � � � � � � � � joe
>
>That means every dialog box (having the same content but for a
>different language) has its own id (id for the main-dialog in English !
>= id for the main-dialog in German)? Moreover you will need a
>different CFormView-Class for every language and for every dialogbox?
>Ok it doesn`t matter how many classes a project will include...
***
The dialog boxes would have the same ID in each DLL. You do not need a different
CFormView class, because the CFormView works with a specific dialog ID to create it. The
point is that you have to have the correct DLL selected (AfxSetInstanceHandle) at the
*point of creation*. Once it is created, it is forever the same dialog because the
*template* was selected *at the time of creation*. Consequently, you have to create a new
instance of the CFormView after the AfxSetInstanceHandle, because you want to (re-)create
it with the correct language resources. The CFormView will not magically morph to German
because the only time anyone cared about the resource (dialog template) was when the view
was created. Switching the DLL doesn't change the CFormView that already exists.
*****
>
>All the stuff to change the view is correct placed in the mainframe
>class?
****
Read the MSDN view-switch example. I think it is under CreateView. You will essentially
do the switch, but then destroy the old view when you have switched. So the code is
useful as an indicator of what to do, but is not definitive; it has to be adapted.
joe
****
>
>
>CRuntimeClass* pNewViewRTClass;
>CView *pOldView;
>pOldView = GetActiveView();
>
>// load the specific view to be the current view (only a demo-example
>with one view)
>pNewViewRTClass = RUNTIME_CLASS(CMLSampleView);
>
>if(m_pCFirstView == NULL)
>{
> m_pCFirstView = STATIC_DOWNCAST(CView, pNewViewRTClass-
>>CreateObject());
> m_pCFirstView->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW,rectDefault,
>this,AFX_IDW_PANE_FIRST+1,NULL);
>
> m_pCFirstView->OnInitialUpdate();
>}
>
>m_pNewView = m_pCFirstView;
>
>int nChildId = m_pNewView->GetDlgCtrlID();
>m_pNewView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
>pOldView->SetDlgCtrlID(nChildId);
>
>
>CDocument *pDoc = pOldView->GetDocument();
>
>pDoc->AddView(m_pNewView);
>pDoc->RemoveView(pOldView);
>
>pDoc->m_bAutoDelete = FALSE;
>
>SetActiveView(m_pNewView);
>RecalcLayout();
>m_pNewView->ShowWindow(SW_SHOW);
>pOldView->ShowWindow(SW_HIDE);
>
>Or is it better to Destroy the old window?
***
THe above code looks reasonable with a casual reading. But I can't really know until it
executes exactly what it does.

Yes, you want to do pOldView->DestroyWindow() because it is now useless.
****
>
>pDoc->UpdateAllViews(NULL); will only call the active view in a sdi
>application where only one view could be availabe at the same time....
>But all the stuff (information in the controls; e.g. checkbox is
>checked or not) have to be stored and loaded to the new view.... where
>is the best place to do this step by step in the above code?
****
You would call UpdateAllViews (which takes three arguments, and you must supply a nonzero
lHint, which your OnUpdate handler recognizes); there are two lHint values: one transfers
control contents to the document, the other loads the controls from the document.

You issue the controls-to-document request BEFORE doing anything about the views, and the
document-to-controls request AFTER you have done the swap.

You would *not* call UpdateAllViews(NULL).
joe
****
>
>
>
>
>
>
>
>
>
>
>
>
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on
See below...
On Sat, 19 Jun 2010 10:16:19 -0700 (PDT), mfc <mfcprog(a)googlemail.com> wrote:

>ok I`ve tried to add a demo modification in the OnUpdate() handler.
>
>
>void CMLSampleView::OnUpdate(CView* pSender, LPARAM lHint, CObject*
>pHint)
>{
> if(pSender == NULL)
> return; //after startup oninitialupdate
****
erroneous. You do not care about the pSender
****
>
> CButton * button = (CButton *)pSender->GetDlgItem(IDC_CHECK1);
****
Why do you not have a CButton variable here? Why did you not change the silly IDC_CHECK1
name to something meaningful? The above line should be finely ground and buried in a
toxic waste site.
*****
> UINT test = button->GetCheck();
> if(button->GetCheck() == BST_CHECKED)
****
Why do you get the value, then get it again?
*****
> TRACE("checked\n");
>
> CView::OnUpdate (pSender, lHint, pHint);
****
You only call this if lHint == 0 && pHint == NULL. Otherwise, you obey the request of
your lHint.
*****
>}
>
>It`s only a small demo - I already know that GetDlgItem is not the
>best solution as well as the general id - but it should only help me
>to get an idea.... of how it could / should work...
>Moreover all checkboxes or other information from the dialog has to be
>checked and stored in private variables in the view-class?? And loaded
>to the new language dialog box?
>
>Therefore I added following lines to the code above
>
>CDocument *pDoc = pOldView->GetDocument();
>pDoc->AddView(m_pNewView);
>
>pDoc->UpdateAllViews(pOldView);
>
>So there`s first of all the old-view loaded (and the onupdate-method
>for this oldview to store all these information) - and after that the
>new view OnUpdate()-method is loaded to get these information back
>from the private variables from the document...
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
On 19 Jun., 21:11, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
> See below...
>
> On Sat, 19 Jun 2010 10:16:19 -0700 (PDT), mfc <mfcp...(a)googlemail.com> wrote:
> >ok I`ve tried to add a demo modification in the OnUpdate() handler.
>
> >void CMLSampleView::OnUpdate(CView* pSender, LPARAM lHint, CObject*
> >pHint)
> >{
> >  if(pSender == NULL)
> >      return;    //after startup oninitialupdate
>
> ****
> erroneous.  You do not care about the pSender
> ****
>
> >  CButton * button = (CButton *)pSender->GetDlgItem(IDC_CHECK1);
>
> ****
> Why do you not have a CButton variable here?  Why did you not change the silly IDC_CHECK1
> name to something meaningful?  The above line should be finely ground and  buried in a
> toxic waste site.
> *****>  UINT test = button->GetCheck();
> >  if(button->GetCheck()  == BST_CHECKED)
>
> ****
> Why do you get the value, then get it again?
> *****>       TRACE("checked\n");
>
> >   CView::OnUpdate (pSender, lHint, pHint);
>
> ****
> You only call this if lHint == 0 && pHint == NULL.  Otherwise, you obey the request of
> your lHint.
> *****
>
>
>
> >}
>
> >It`s only a small demo - I already know that GetDlgItem is not the
> >best solution as well as the general id - but it should only help me
> >to get an idea.... of how it could / should work...
> >Moreover all checkboxes or other information from the dialog has to be
> >checked and stored in private variables in the view-class?? And loaded
> >to the new language dialog box?
>
> >Therefore I added following lines to the code above
>
> >CDocument *pDoc = pOldView->GetDocument();
> >pDoc->AddView(m_pNewView);
>
> >pDoc->UpdateAllViews(pOldView);
>
> >So there`s first of all the old-view loaded (and the onupdate-method
> >for this oldview to store all these information) - and after that the
> >new view OnUpdate()-method is loaded to get these information back
> >from the private variables from the document...
>
> Joseph M. Newcomer [MVP]
> email: newco...(a)flounder.com
> Web:http://www.flounder.com
> MVP Tips:http://www.flounder.com/mvp_tips.htm- Zitierten Text ausblenden -
>
> - Zitierten Text anzeigen -

do you mean this example from the msdn?
http://msdn.microsoft.com/en-us/library/s199bks0(VS.80).aspx

Unfortunately, I can`t open this collect programm in vs2010.
From: Joseph M. Newcomer on
More below...
On Sat, 19 Jun 2010 15:08:54 -0400, Joseph M. Newcomer <newcomer(a)flounder.com> wrote:

>See below...
>On Sat, 19 Jun 2010 08:12:55 -0700 (PDT), mfc <mfcprog(a)googlemail.com> wrote:
>
>>On 19 Jun., 16:20, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
>>> See below...
>>>
>>> On Sat, 19 Jun 2010 04:56:30 -0700 (PDT), mfc <mfcp...(a)googlemail.com> wrote:
>>> >The whole application is a sdi application with the doc/view modell;
>>> >therefore I`m loading a dialog at the startup with e.g. buttons etc.
>>>
>>> >CMLSampleView::CMLSampleView()
>>> > � �: CFormView(CMLSampleView::IDD)
>>> >{
>>> > � �// TODO: add construction code here
>>>
>>> >}
>>>
>>> >IDD is the id from the dialog box, generated by the resoure editor.
>>> >I`ve copied this dialog box to the other projects (satellite dlls for
>>> >German and for English); Maybe this approach is wrong....
>>>
>>> ****
>>> No, it looks fine. �Key here is that you have to switch languages in the InitInstance
>>> handler.
>>> ****
>>>
>>> >In the end, when the programm is started, the user should see a sdi
>>> >window app where he can switch to different languages by some
>>> >cbuttons. There will be no menu in the end application.
>>>
>>> ****
>>> Switching the resource which is the SDI CFormView is much harder. �What you have to do is
>>> create a new CFormView using the new dialog template, attach it to the document, and
>>> destroy the original CFormView. �Note that you should use UpdateAllViews with a nonzero
>>> lHint to tell any existing view to store its control contents in the document, and upon
>>> completion, use UpdateAllViews with a different nonzero lHint to tell the form to retrieve
>>> any existing data from the document and put it into the current view. �Otherwise, if you
>>> switch views with information in the controls, the information would be lost.
>>>
>>> See the MSDN example on how to switch views of an SDI app.
>>> � � � � � � � � � � � � � � � � joe
>>
>>That means every dialog box (having the same content but for a
>>different language) has its own id (id for the main-dialog in English !
>>= id for the main-dialog in German)? Moreover you will need a
>>different CFormView-Class for every language and for every dialogbox?
>>Ok it doesn`t matter how many classes a project will include...
>***
>The dialog boxes would have the same ID in each DLL. You do not need a different
>CFormView class, because the CFormView works with a specific dialog ID to create it. The
>point is that you have to have the correct DLL selected (AfxSetInstanceHandle) at the
>*point of creation*. Once it is created, it is forever the same dialog because the
>*template* was selected *at the time of creation*. Consequently, you have to create a new
>instance of the CFormView after the AfxSetInstanceHandle, because you want to (re-)create
>it with the correct language resources. The CFormView will not magically morph to German
>because the only time anyone cared about the resource (dialog template) was when the view
>was created. Switching the DLL doesn't change the CFormView that already exists.
>*****
>>
>>All the stuff to change the view is correct placed in the mainframe
>>class?
>****
>Read the MSDN view-switch example. I think it is under CreateView. You will essentially
>do the switch, but then destroy the old view when you have switched. So the code is
>useful as an indicator of what to do, but is not definitive; it has to be adapted.
> joe
>****
>>
>>
>>CRuntimeClass* pNewViewRTClass;
>>CView *pOldView;
>>pOldView = GetActiveView();
>>
>>// load the specific view to be the current view (only a demo-example
>>with one view)
>>pNewViewRTClass = RUNTIME_CLASS(CMLSampleView);
****
You do not need this variable; get rid of it.
****
>>
>>if(m_pCFirstView == NULL)
>>{
>> m_pCFirstView = STATIC_DOWNCAST(CView, pNewViewRTClass-
>>>CreateObject());
*****
You can use the RUNTIME_CLASS here without the need for the variable.

You do not check to see if this succeeds, but blindly go off and use m_pCFirstView as it
it exists. Why is it a class member?
****
>> m_pCFirstView->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW,rectDefault,
>>this,AFX_IDW_PANE_FIRST+1,NULL);
****
I would think you would want to create one as large as the client area of the current
view....and why the particular ID?

This is where you would do
GetDocument()->UpdateAllViews(NULL, UPDATE_CONTROLS_TO_DOC, NULL);
where
static const UINT UPDATE_CONTROLS_TO_DOC = 1;
static const UINT UPDATE_DOC_TO_CONTROLS = 2;
or
#define UPDATE_CONTROLS_TO_DOC 1
#define UPDATE_DOC_TO_CONTROLS 2
or
typedef enum { UPDATE_CONTROLS_TO_DOC=1, UPDATE_DOC_TO_CONTROLS} UpdateTypes;
****
>>
>> m_pCFirstView->OnInitialUpdate();
>>}
>>
>>m_pNewView = m_pCFirstView;
>>
>>int nChildId = m_pNewView->GetDlgCtrlID();
>>m_pNewView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
>>pOldView->SetDlgCtrlID(nChildId);
****
You would destroy the old view long before you need to set the ID, but you still need it
to get the document.
*****
>>
>>
>>CDocument *pDoc = pOldView->GetDocument();
>>
>>pDoc->AddView(m_pNewView);
>>pDoc->RemoveView(pOldView);
****
*Now* you can detroy the old view
****
>>
>>pDoc->m_bAutoDelete = FALSE;
>>
>>SetActiveView(m_pNewView);
>>RecalcLayout();
>>m_pNewView->ShowWindow(SW_SHOW);
>>pOldView->ShowWindow(SW_HIDE);
****
The old view is already destroyed
****
>>
>>Or is it better to Destroy the old window?
>***
>THe above code looks reasonable with a casual reading. But I can't really know until it
>executes exactly what it does.
>
>Yes, you want to do pOldView->DestroyWindow() because it is now useless.
>****
>>
>>pDoc->UpdateAllViews(NULL); will only call the active view in a sdi
>>application where only one view could be availabe at the same time....
>>But all the stuff (information in the controls; e.g. checkbox is
>>checked or not) have to be stored and loaded to the new view.... where
>>is the best place to do this step by step in the above code?
>****
>You would call UpdateAllViews (which takes three arguments, and you must supply a nonzero
>lHint, which your OnUpdate handler recognizes); there are two lHint values: one transfers
>control contents to the document, the other loads the controls from the document.
>
>You issue the controls-to-document request BEFORE doing anything about the views, and the
>document-to-controls request AFTER you have done the swap.
>
>You would *not* call UpdateAllViews(NULL).
> joe
****
void CWhateverView::OnUpdate(CView * view, LPARAM lHint, Object * pHint)
{
if(lHint == 0 && pHint == NULL)
{
CView::OnUpdate(view, lHint, pHint);
return;
}

switch(lHint)
{ /* lHint */
case UPDATE_CONTROLS_TO_DOC:
...stuff
break;
case UPDATE_DOC_TO_CONTROLS:
...stuff
break;
} /* lHint */
}
>****
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>Joseph M. Newcomer [MVP]
>email: newcomer(a)flounder.com
>Web: http://www.flounder.com
>MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9
Prev: I love MFC!
Next: Using CMFCToolBar and CMFCMenuBar?