您的位置:首页 > 编程语言 > C语言/C++

Using Dialog Templates to create an InputBox() in C++

2013-04-25 16:17 1226 查看
Download source - 100 Kb



(Single line input box)



(Multi-line input box)


Introduction

One day, I was writing a small Windows tool, and wanted to get some input from the user. Since my application was not an MFC, nor a console application, to my knowledge, there was no simple way to get the input from the user. The Windows API does a pretty
job by giving us the 
MessageBox()
 function but nothing like the 
InputBox
function.
Since I wanted to keep my application slim and self-contained, I decided to investigate on how to use dialogs without using resources and without introducing too much of code.

Thus the Win32InputBox library was born.

In this article, I will illustrate how to create and use dialog boxes without creating dialog resources or using MFC. We will then use this technique to create an 
InputBox()
 function
that is similar to VB's 
InputBox()
.


Background

It is important for the reader to be familiar with Windows messaging, and the window/dialog procedure mechanism. Nonetheless, I will be giving a simple introduction for beginners.


Introduction to dialog boxes - the classical way

Currently, to create a dialog box driven application, you have many choices. I'll list the most popular methods:

MFC dialog based application (can be generated by the wizard).
Plain Win32 API - using the IDE's dialog designer.
Plain Win32 API - without using the dialog designer, instead, using the code to create all the controls and the dialog window.
Each of the mentioned methods above have their pros and cons, but that's beyond the scope of this article. Now as promised, here's a small overview on how each of the mechanisms work.

We start with the Plain Win32 API (using the dialog designer):

The design part:
We start by designing our dialog with the editor.
We create controls (buttons, textboxes, ...).
We assign IDs to the controls.

The coding part:
We write our 
WindowProc()
, which will handle all the events related
to our dialog.
We call the appropriate dialog creation method (
CreateDialog()
 family,
or 
DialogBox()
 function family).

If you are not using the dialog designer, you will have to create the controls in the code by calling the
CreateWindow()
 function.

As for MFC dialog based applications, the concept is similar, however everything is wrapped into neat classes. So, all you have to do is:

Design the dialog using the editor.
Subclass 
CDialog
, say as 
CMyDialog
.
Bind your subclassed class to the desired dialog ID.
Overwrite the needed 
CDialog
's methods to handle messages and events.


Introduction to dialog templates

What is a dialog template? It is a structure that defines the styles and dimensions of a given dialog. A dialog template is defined through the 
DLGTEMPLATE
 structure
found in the Windows headers. There is an extended version of this structure that renders the latter obsolete. The 
DLGTEMPLATEEX
 is
not defined anywhere in the header files, but is described in the MSDN. The extended dialog template (
DLGTEMPLATEEX
)
is newer, and introduces more features.

A dialog template alone is enough to describe the dialog, but not the dialog items, thus the 
DLGITEMTEMPLATE/EX
structures.
These 
DLGITEMTEMPLATE[EX]
 structures will define the items inside the dialog.

When you use the dialog editor (in VC++'s IDE), you are visually constructing the dialog templates and the dialog item templates (however, in source code form). When you compile your application, the resources get compiled separately using the RC.EXE (resource
compiler) tool, which will produce the .RES (binary file) out of the .RC (text file), and finally everything will be linked together to produce one executable module.

Here's how 
DLGTEMPLATE
 and 
DLGITEMTEMPLATE
 are
described in a .RC file:


 Collapse | Copy
Code
IDD_INPUTBOX DIALOGEX 22, 17, 231, 109
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS |
WS_CAPTION | WS_SYSMENU
CAPTION "Win32InputBox"
FONT 8, "MS Shell Dlg", 700, 0, 0x0
BEGIN
LTEXT           "Prompt:",IDC_INPUTBOX_PROMPT,6,4,157,
33,SS_NOPREFIX
EDITTEXT        IDC_INPUTBOX_DLG_EDIT1,6,37,216,14,
ES_AUTOHSCROLL
EDITTEXT        IDC_INPUTBOX_DLG_EDIT2,6,55,216,49,
ES_MULTILINE | ES_AUTOHSCROLL |
ES_WANTRETURN | WS_VSCROLL
DEFPUSHBUTTON   "OK",IDOK,171,4,51,14,WS_GROUP
PUSHBUTTON      "CANCEL",IDCANCEL,171,21,51,14,WS_GROUP
LTEXT           "",IDC_STATIC,0,39,8,8,NOT WS_VISIBLE
END

To thoroughly understand this source file, please refer to MSDN (check references below).

However, I would like you to note the following:

The numbers which denote the dimensions and positions.
The 
IDXXXX
 which denote the IDs. Those IDS are defined in the "resource.h"
file.
The commands "
LTEXT
", "
EDITTEXT
",
etc... that designate which control to create.
The style constants 
WS_VISIBLE
 or 
ES_MULTILINE
,
or 
DS_MODALFRAME
, etc...
If you're curious about how a .RES file looks like, I have included a small hex dump of this compiled structure here:



Here's how a "resource.h" (partial) looks like:


 Collapse | Copy
Code
#define IDD_INPUTBOX                    103
#define IDC_INPUTBOX_PROMPT             1000
#define IDC_INPUTBOX_DLG_EDIT1          1001
#define IDC_INPUTBOX_DLG_EDIT2          1002
#define IDC_STATIC                      -1

Please note that the RES file not only describes your dialog, but also all the items in the .RC file (icons, string table, etc...). Since the resource file holds a number of resource items, all defined by certain IDs and resource types, we need
a way to select the given resource and use it. That's why we have the 
FindResource()
 and other resource management
APIs.

This small code will illustrate how to create a dialog whose ID is defined in resource.h as 
IDD_MYDLG
:


 Collapse | Copy
Code
#include <windows.h>
#include "resource.h"

int main()
{
HMODULE hModule = ::GetModuleHandle(0);
HINSTANCE hInst = hModule;

HRSRC hrsrc = ::FindResource(hModule,
MAKEINTRESOURCE(IDD_MYDLG), RT_DIALOG);

HGLOBAL hglobal = ::LoadResource(hModule, hrsrc);

::DialogBoxIndirectParam(hInst,
(LPCDLGTEMPLATE) hglobal, 0, 0, 0);

return 0;
}

Notice how we pass the "
hglobal
" as "
LPCDLGTEMPLATE
".
This is the pointer to the compiled dialog template as discussed earlier. This code doesn't pass a dialog procedure, thus the dialog will not respond to the Close messages or anything like that, and you will have to kill the process or write an appropriate
dialog procedure.

A simple dialog procedure which we can write is:


 Collapse | Copy
Code
LRESULT CALLBACK dlgProc(HWND hDlg, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CLOSE:
::EndDialog(hDlg, IDOK);
return TRUE;
}
return 0;
}

And then we adjust the call to:


 Collapse | Copy
Code
::DialogBoxIndirectParam(hInst, (LPCDLGTEMPLATE) hglobal,
0, (DLGPROC)dlgProc, 0);


The DlgResToDlgTemplate tool

In the course of writing the Win32Inputbox library, I developed a small tool named "DlgResToDlgTemplate". This tool's sole purpose is to fetch a dialog resource from a binary (which is now in compiled form) and dump it as a C character array. After extracting
the dialog template, we can employ it in our own application.

A quick example would be, employing the NOTEPAD.EXE template in our own simple application.

Extract the template from notepad.exe using:


 Collapse | Copy
Code
DlgResToDlgTemplate.exe d:\windows\system32\notepad.exe 14 n.h



 Collapse | Copy
Code
DlgResToDlgTemplate v1.0 (c) <lallousx86@yahoo.com>

generated n.h (1195 bytes) successfully!


Now that we have the "n.h" which is the dialog template of the notepad.exe "Goto line" dialog, we can modify the sample code (mentioned above) as:


 Collapse | Copy
Code
static unsigned char dlg_14[] =
{
0xc0,0x20,0xc8,0x80,0x00,0x00,0x00,0x00,
0x04,0x00,0x00,0x00,0x00,0x00,0xb4,0x00,0x39,
0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x6f,
0x00,0x74,0x00,0x6f,0x00,0x20,0x00,0x6c,
0x00,0x69,0x00,0x6e,0x00,0x65,0x00,0x00,
0x00,0x08,0x00,0x4d,0x00,0x53,0x00,0x20,
0x00,0x53,0x00,0x68,0x00,0x65,0x00,0x6c,
0x00,0x6c,0x00,0x20,0x00,0x44,0x00,0x6c,
0x00,0x67,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x02,0x50,0x00,0x00,0x00,0x00,0x07,
0x00,0x09,0x00,0x32,0x00,0x0a,0x00,0xb0,
0x04,0xff,0xff,0x82,0x00,0x26,0x00,0x4c,
0x00,0x69,0x00,0x6e,0x00,0x65,0x00,0x20,
0x00,0x4e,0x00,0x75,0x00,0x6d,0x00,0x62,
0x00,0x65,0x00,0x72,0x00,0x3a,0x00,0x00,
0x00,0x00,0x00,0x80,0x00,0x81,0x50,0x00,
0x00,0x00,0x00,0x37,0x00,0x07,0x00,0x39,
0x00,0x0c,0x00,0x02,0x01,0xff,0xff,0x81,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x00,0x01,0x50,0x00,0x00,0x00,0x00,0x07,
0x00,0x22,0x00,0x32,0x00,0x0e,0x00,0x01,
0x00,0xff,0xff,0x80,0x00,0x4f,0x00,0x4b,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x50,0x00,0x00,0x00,0x00,0x4e,
0x00,0x22,0x00,0x32,0x00,0x0e,0x00,0x02,
0x00,0xff,0xff,0x80,0x00,0x43,0x00,0x61,
0x00,0x6e,0x00,0x63,0x00,0x65,0x00,0x6c,
0x00,0x00,0x00,0x00,0x00
};

void show_template_dlg()
{
::DialogBoxIndirectParam((HINSTANCE) ::GetModuleHandle(0),
(LPCDLGTEMPLATE) dlg_14, 0, (DLGPROC)dlgProc, 0);
}


Hope everything's clear so far. Next, we will see how practical it is to use the dialog templates to create small (self-contained) functions.


CWin32InputBox class overview

Now we can talk about the construction of the 
CWin32Inputbox
 class, after having introduced all the concepts needed
for this task.

In a nutshell, 
CWin32InputBox::InputBox()
:

Defines a proper dialog procedure to handle the OK and CANCEL buttons.
Defines a 
WM_INITDIALOG
 handler to properly initialize the dialog.
Having the dialog template needed, named as "
definputbox_dlg
", we can:
Call 
DialogBoxIndirectParam()
 to show the dialog.
Do some actions based on the return value of the modal dialog.

The class exports the two 
static
 methods:


 Collapse | Copy
Code
static INT_PTR InputBoxEx(WIN32INPUTBOX_PARAM *);
static INT_PTR InputBox(LPCTSTR szTitle,
LPCTSTR szPrompt,
LPTSTR szResult,
DWORD nResultSize,
bool bMultiLine = false,
HWND hwndParent = 0);

You may simply call the 
InputBox
 method as:


 Collapse | Copy
Code
CWin32InputBox::InputBox("hello", "what?", buf, 100, false);

to produce something like:



The extended version uses the 
WIN32INPUTBOX_PARAM
 structure to allow you to customize the input box. So to use this
class in your project, all you have to do is simply add the "Win32InputBox.cpp/.h" to your project. No need for resources or anything.

You may freely use the code under the zlib/libpng license; check the "Win32InputBox.h" file.


Points of interest

It was fun learning about dialog templates and more fun to write the reusable 
CWin32InputBox
 class. Hope you enjoyed
and learned from this article. If you give me a low rating, I'd appreciate dropping me a comment and telling me how I can improve my article.

Before closing this article, I'd like to give a small tip for those who don't know: you can use your Visual Studio IDE to peek around other binary file resources'! Just press CTRL+O, locate a Win32 PE file, and open it!


References

MSDN -> Win32 and COM Development -> Tools -> Platform SDK Tools -> SDK Tools -> Resource Tools -> Resource Compiler -> Resource Definition Statements.
MSDN -> 
CreateWindowEx()
 function.
MSDN -> Using Resources.
MSDN -> 
DLGTEMPLATEEX
 structure.


转自:http://www.codeproject.com/Articles/13330/Using-Dialog-Templates-to-create-an-InputBox-in-C

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐