Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Dynamic comboboxes

71 views
Skip to first unread message

Nogat

unread,
Aug 30, 2000, 3:00:00 AM8/30/00
to

Hi there,

I would like to submit to you a question i have to solve.
I'm using MS VC++ 6.0, MFC, and the WCE toolkit... no, no, this isn't the
main problem ;-)
I have to create dynamically some dialog boxes in which to insert different
kinds of controls.
Which is the structure of the template for the portion relative to the combo
box? Where do I put
the strings and how much memory does it require?


The first step is to allocate memory to define the dialog. The following is
the structure
I used for the most simple controls. And for the combo box?

1. DLGTEMPLATE structure
2. 0x0000 (Word) indicating the dialog has no menu
3. 0x0000 (Word) Let windows assign default class to the dialog
4. (Caption) Null terminated unicode string
5. 0x000B (size of the font to be used)
6. "Arial" (name of the typeface to be used)
7. DLGITEMTEMPLATE structure for the button (HAS TO BE DWORD ALIGNED)
8. 0x0080 to indicate the control is a button
9. (Title). Unicode null terminated string with the caption
10. 0x0000 0 extra bytes of data for this control
11. DLGITEMTEMPLATE structure for the Static Text (HAS TO BE DWORD
ALIGNED)
12. 0x0081 to indicate the control is static text
13. (Title). Unicode null terminated string with the text
14 0x0000. 0 extra bytes of data for this control
15. DLGITEMTEMPLATE structure for the Edit Control (HAS TO BE DWORD ALIGNED)
16. 0x0082 to indicate an Edit control
17. (Text) - Null terminated unicode string to appear in the edit control
18. 0x0000. 0 extra bytes of data for this control


I want to create a buffer in memory to use in the following manner:

CDialog dlg;
dlg.InitModalIdirect((DLGTEMPLATE*)pBuffer);
dlg.DoModal();


May I use CComboBox::AddString? If yes, how to create a CComboBox object
from the previous template?
Is there another way?

Thank you to who will help me!

Bye,
Emidio < emid...@engineer.com >.

Jeff Partch

unread,
Aug 30, 2000, 3:00:00 AM8/30/00
to

Hi!

I'm sorry , but I'm not exactly sure what you're asking, but maybe some of this will help...

First, the class atom for the combobox is 0x0085 in case that's part of your questions. If you are
asking how to create an initialized combobox from a DLGTEMPLATE in memory, you could try to figure
out the CWnd::ExecuteDlgInit function, but even if it's not a dead end, it's a bad idea if you ask
me. You should initialize your combobox in the response to WM_INITDIALOG, or some other message
event. If you are asking what the best way to accomplish this whole template in memory thing is,
then here's the way I've taken to doing it...

1. Design your dialogbox in the resource editor just like normal, and use ClassWizard to create the
CDialog class,
and add message map entries, and subclass controls and all like that there.

2. When your dialogbox is working the way you want it, add a call to this function to your app
temporarily...

#ifdef _DEBUG
BOOL DebugOutputDlgTemplate(LPCTSTR lpszClassName, LPCTSTR lpszResName)
{
ASSERT(AfxIsValidString(lpszClassName));
ASSERT(HIWORD(lpszResName) == 0 || AfxIsValidString(lpszResName));

HRSRC hRes = FindResource(NULL, lpszResName, RT_DIALOG);
CString strBuf;
LPSTR pBuf;
int n = 0;

if (!hRes)
return FALSE;

int nSize = (int)SizeofResource(NULL, hRes);

if (!nSize)
return FALSE;

try
{
pBuf = strBuf.GetBufferSetLength((6*nSize));
}
catch(CMemoryException* e)
{
e->Delete();
return FALSE;
}

if (!pBuf)
return FALSE;

HGLOBAL hg = LoadResource(NULL, hRes);

if (!hg)
return FALSE;

char* p = (char*)LockResource(hg);

for (int i=0; i<nSize; i++)
n += sprintf(&pBuf[n], _T("0x%02X, "), (BYTE)p[i]);

strBuf.ReleaseBuffer(n-2);
UnlockResource(hg);

if (strBuf.IsEmpty())
return FALSE;

try
{
TRACE2(_T("\nclass %sTempl : public %s\n{\n"), lpszClassName, lpszClassName);
TRACE0(_T("\tstatic const BYTE m_templ[];\npublic:\n"));
TRACE2(_T("\t%sTempl::%sTempl()\n\t\t{ m_lpszTemplateName = NULL; }\n"), lpszClassName,
lpszClassName);
TRACE0(_T("\tLPCDLGTEMPLATE GetTemplate() const\n\t\t{ return
(LPCDLGTEMPLATE)m_templ; }\n};\n\n"));

TRACE2("const BYTE %sTempl::m_templ[%d] = {\n", , lpszClassName, nSize);

for (int i=0; i<n; i+=48)
TRACE1("\t%s\n", (LPCTSTR)strBuf.Mid(i, 47));

TRACE("};\n\n");
}
catch(CMemoryException* e)
{
e->Delete();
return FALSE;
}

return TRUE;
}
#endif

4. For example, say you wanted to use the standard MFC CAboutDlg but create it from a DLGTEMPLATE,
you'd add this
first line to the standard OnAppAbout function...

void CMyApp::OnAppAbout()
{
DebugOutputDlgTemplate(_T("CAboutDlg"), MAKEINTRESOURCE(IDD_ABOUTBOX));

CAboutDlg aboutDlg;
aboutDlg.DoModal();
}

5. This will then output -- to the debugoutput window, formatted code for a class called
CAboutDlgTempl that derives
from your class, as well as an array of bytes representing all of the DLGTEMPLATE information
from your dialog
resource. All you have to do is copy it and paste it in the *.cpp file just before the
OnAppAbout function.

6. Now modify your OnAppAbout like so...

class CAboutDlgTempl : public CAboutDlg
{
static const BYTE m_templ[];
public:
CAboutDlgTempl::CAboutDlgTempl()
{ m_lpszTemplateName = NULL; }
LPCDLGTEMPLATE GetTemplate() const
{ return (LPCDLGTEMPLATE)m_templ; }
};

const BYTE CAboutDlgTempl::m_templ[266] = {
0xC0, 0x00, 0xC8, 0x80, 0x00, 0x00, 0x00, 0x00,
...
0x00, 0x00
};

void CMyApp::OnAppAbout()
{
// DebugOutputDlgTemplate(_T("CAboutDlg"), MAKEINTRESOURCE(IDD_ABOUTBOX));

CAboutDlgTempl aboutDlg;
aboutDlg.InitModalIndirect(aboutDlg.GetTemplate());
aboutDlg.DoModal();
}

7. During development, you can still use all of the tools in the IDE to modify and tweak your
dialog, just remember to
regenerate the data if you alter the resource. And once you're sure that the dialog is
finalized, you can delete the
actual template resource. Or you could do all the design and implementation in a separate
project.

HTH,

Jeff...

--
Please post all follow-ups to the newsgroup only.

Nogat wrote in message ...

Nogat

unread,
Aug 31, 2000, 10:00:55 AM8/31/00
to
Hi Jeff, and tanks a lot.

> 1. Design your dialogbox in the resource editor just like normal, and use
ClassWizard to create the
> CDialog class,
> and add message map entries, and subclass controls and all like that
there.

Ops, The problem in that I'm not using the resource editor, because I dont
know which is the shape and how are made the controls until I run the
application. I tried to use the DTempl (by Sridhar Madhugiri) classes
provided by Microsoft but I dont know how to initialize the controls created
and if I can use CComboBox::AddString classic function. The problem is the
same with my own classes.

I'm going to try your suggestions, tank you.

Bye,
Emidio < emid...@engineer.com >.

Jeff Partch

unread,
Aug 31, 2000, 3:58:31 PM8/31/00
to

Hi!

Well, I guess that last post was way off. I still can't pretend to understand exactly what the
source of your confusion is. You really do seem to have a pretty good understanding of the
DLGTEMPLATE and DLGITEMTEMPLATE structures, and you seem to know what controls you want to use when
you want to use them. So there might be a little trial and error getting the thing aligned just
right, but that's just par for the course IMHO. Is it that you are having trouble seeing the thing
in the context of an MFC CDialog derived class? Once you get the template right, it's the same thing
really. Only instead of passing a resource ID to the constructor -- which the CDialog uses to load
the resource template into memory, you pass the template that is already in memory via
InitModalIndirect or CreateIndirect. Then you just handle the initialization in OnInitDialog just
like you always do. If you know the control types and ID's in advance you can even add the
DDX_Control calls to your CDialog class's DoDataExchange function to subclass them in the usual way.
Or you can subclass them manually using CWnd::SubclassWindow. In either event, once you get a member
variable of class CComboBox attached to the DIALOGBOX COMBOBOX control's HWND, then you can
definately use CComboBox::AddString. Or if you forego the MFC subclassing, you can always deal with
it via SendMessage(hWndCombo, CB_ADDSTRING,...).

Jeff...

--
Please post all follow-ups to the newsgroup only.

Nogat wrote in message ...

Nogat

unread,
Sep 1, 2000, 11:19:06 AM9/1/00
to
Hi Jeff,

I tried your code and I must say that it was very useful, expecially for
understanding the structures of the templates. But I've got some other
questions.

you say...

> Well, I guess that last post was way off. I still can't pretend to
understand exactly what the
> source of your confusion is. You really do seem to have a pretty good
understanding of the
> DLGTEMPLATE and DLGITEMTEMPLATE structures,

yes... but I've some dubts about how are organized the strings used by
comboboxes and listboxes... for example, CComboBox::AddString where does it
put the string in the memory template structure? You know, I must create
dialog boxes at runtime and I want to add controls dynamically without using
the resource editor.

One question: Are the strings of a combobox placed in the DLGTEMPLATE (that
is to say after it) or somewhere else (the initialization creates another
structure)???

With your good debug function I'm not able to find the strings!

> and you seem to know what controls you want to use when
> you want to use them. So there might be a little trial and error getting
the thing aligned just
> right, but that's just par for the course IMHO. Is it that you are having
trouble seeing the thing
> in the context of an MFC CDialog derived class? Once you get the template
right, it's the same thing
> really. Only instead of passing a resource ID to the constructor -- which
the CDialog uses to load
> the resource template into memory, you pass the template that is already
in memory via
> InitModalIndirect or CreateIndirect.

My problem is now *only* with the memory template, that is to say creating
it and initializing it (for example adding strings to comboboxes).

> Then you just handle the initialization in OnInitDialog just
> like you always do. If you know the control types and ID's in advance you
can even add the
> DDX_Control calls to your CDialog class's DoDataExchange function to
subclass them in the usual way.
> Or you can subclass them manually using CWnd::SubclassWindow. In either
event, once you get a member
> variable of class CComboBox attached to the DIALOGBOX COMBOBOX control's
HWND, then you can
> definately use CComboBox::AddString. Or if you forego the MFC subclassing,
you can always deal with
> it via SendMessage(hWndCombo, CB_ADDSTRING,...).

Which is the better way for adding strings in comboboxes (e.g.) when dialog
boxes are created dynamically (I'm using WCE)?

Thanks a lot and bye,

Emidio < emid...@engineer.com >.

Jeff Partch

unread,
Sep 1, 2000, 5:31:18 PM9/1/00
to
Hi, Again!

Well, the strings don't go in the template at all. You must initialize the combobox in your
OnInitDialog handler using CComboBox::AddString or the SendMessage(hWndCombo, CB_ADDSTRING...), or
one of the InsertString variants. Which of those methods is better is really just a coin-toss if you
ask me. The MFC version is a really thin wrapper around SendMessage...

_AFXWIN_INLINE int CComboBox::AddString(LPCTSTR lpszString)
{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_ADDSTRING, 0,
(LPARAM)lpszString); }

Now, what the combobox does with them after you add or insert them is really not something we are
supposed to know or care about.

HTH,

Jeff...

PS: Thanks for the kind words

--
Please post all follow-ups to the newsgroup only.

Nogat wrote in message ...

0 new messages