Dialogs
Dialog windows or dialogs are an indispensable part of most modern GUI applications. A dialog is defined as a conversation between two or more persons. In a computer application a dialog is a window which is used to "talk" to the application. A dialog is used to input data, modify data, change the application settings etc. Dialogs are important means of communication between a user and a computer program.
Modeless Dialog
Modeless dialogs does not restrict you to working with a particular window. A user can switch between a dialog box and other windows of a program. A typical modeless dialog is a Find/Replace dialog or a floating toolbar.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
void CreateDialogBox(HWND);
void RegisterDialogClass(HWND);
HINSTANCE ghInstance;
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
MSG msg ;
HWND hwnd;
WNDCLASS wc = {0};
wc.lpszClassName = TEXT( "Window" );
wc.hInstance = hInstance ;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
RegisterClass(&wc);
hwnd = CreateWindow( wc.lpszClassName, TEXT("Window"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 250, 150, NULL, NULL, hInstance, NULL);
ghInstance = hInstance;
while( GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch(msg)
{
case WM_CREATE:
RegisterDialogClass(hwnd);
CreateWindow(TEXT("button"), TEXT("Show dialog"),
WS_VISIBLE | WS_CHILD ,
20, 50, 95, 25,
hwnd, (HMENU) 1, NULL, NULL);
break;
case WM_COMMAND:
CreateDialogBox(hwnd);
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK DialogProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch(msg)
{
case WM_CREATE:
CreateWindow(TEXT("button"), TEXT("Ok"),
WS_VISIBLE | WS_CHILD ,
50, 50, 80, 25,
hwnd, (HMENU) 1, NULL, NULL);
break;
case WM_COMMAND:
DestroyWindow(hwnd);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
void RegisterDialogClass(HWND hwnd)
{
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = (WNDPROC) DialogProc;
wc.hInstance = ghInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpszClassName = TEXT("DialogClass");
RegisterClassEx(&wc);
}
void CreateDialogBox(HWND hwnd)
{
CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_TOPMOST, TEXT("DialogClass"), TEXT("Dialog Box"),
WS_VISIBLE | WS_SYSMENU | WS_CAPTION , 100, 100, 200, 150,
NULL, NULL, ghInstance, NULL);
}
A dialog is only a special kind of a window. It is created as a normal window with some specific flags.
CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_TOPMOST, TEXT("DialogClass"), TEXT("Dialog Box"),
WS_VISIBLE | WS_SYSMENU | WS_CAPTION , 100, 100, 200, 150,
NULL, NULL, ghInstance, NULL);
The dialog is crated with a combination of regular flags WS_VISIBLE | WS_SYSMENU | WS_CAPTION and extended flags WS_EX_DLGMODALFRAME | WS_EX_TOPMOST.
Common Dialog Boxes
These are dialogs for performing common tasks. Opening and saving files, printing documents, choosing color etc. Common dialog boxes save programmers a lot of work. They help promote standards in applications.
Color dialog box
This is a common dialog for choosing color.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK PanelProc(HWND, UINT, WPARAM, LPARAM);
void RegisterPanel(void);
COLORREF ShowColorDialog(HWND);
COLORREF gColor = RGB(255, 255, 255);
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
MSG msg ;
WNDCLASS wc = {0};
wc.lpszClassName = TEXT( "Color dialog box" );
wc.hInstance = hInstance ;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc ;
RegisterClass(&wc);
CreateWindow( wc.lpszClassName, TEXT("Color dialog box"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
150, 150, 250, 200, 0, 0, hInstance, 0);
while( GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
static HWND hwndPanel;
switch(msg)
{
case WM_CREATE:
{
CreateWindow(TEXT("button"), TEXT("Color"),
WS_VISIBLE | WS_CHILD ,
20, 30, 80, 25,
hwnd, (HMENU) 1, NULL, NULL);
RegisterPanel();
hwndPanel = CreateWindow(TEXT("Panel"), NULL,
WS_CHILD | WS_VISIBLE,
130, 30, 80, 80,
hwnd, (HMENU) 2, NULL, NULL);
break;
}
case WM_COMMAND:
{
gColor = ShowColorDialog(hwnd);
InvalidateRect(hwndPanel, NULL, TRUE);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK PanelProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch(msg)
{
case WM_PAINT:
{
GetClientRect(hwnd, &rect);
hdc = BeginPaint(hwnd, &ps);
SetBkColor(hdc, gColor);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, TEXT(""), 0, NULL);
EndPaint(hwnd, &ps);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
COLORREF ShowColorDialog(HWND hwnd) {
CHOOSECOLOR cc;
static COLORREF crCustClr[16];
ZeroMemory(&cc, sizeof(cc));
cc.lStructSize = sizeof(cc);
cc.hwndOwner = hwnd;
cc.lpCustColors = (LPDWORD) crCustClr;
cc.rgbResult = RGB(0, 255, 0);
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
ChooseColor(&cc);
return cc.rgbResult;
}
void RegisterPanel(void) {
WNDCLASS rwc = {0};
rwc.lpszClassName = TEXT( "Panel" );
rwc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
rwc.lpfnWndProc = PanelProc;
RegisterClass(&rwc);
}
In our example, we have a button control and a child window. The color of the child window is white at the beginning.We can change the color of the child window, by pressing on the button and choosing a custom color value.
COLORREF gColor = RGB(255, 255, 255);
We define a global color value. White by default.
gColor = ShowColorDialog(hwnd);
The color dialog box is shown in the ShowColorDialog() user function. The function returns the chosen color value.
CHOOSECOLOR cc;
To create a color dialog box, we must define and fill a CHOOSECOLOR structure.
cc.rgbResult = RGB(0, 255, 0); cc.Flags = CC_FULLOPEN | CC_RGBINIT;
If we provide the CC_RGBINIT than the rgbResult member is the initial selected color, when the dialog is displayed. If the user clicks the OK button, rgbResult specifies the user's color selection.
ChooseColor(&cc);
The color dialog box is displayed.
gColor = ShowColorDialog(hwnd); InvalidateRect(hwndPanel, NULL, TRUE);
After we obtain the color value, we call the InvalidateRect() function. This function will send WM_PAINT message to our child window.
SetBkColor(hdc, gColor);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, TEXT(""), 0, NULL);
In the panel procedure, we change the background color of the child window. Besides displaying text on the window, the ExtTextOut() function can also change the window background color. We won't display any text, we only change the background color. If we provide the ETO_OPAQUE flag, the ExtTextOut() function will use the color, specified by the SetBkColor() function.
Openfile dialog box
This is a common dialog for opening files. Don't use UNICODE, to compile this example.
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void CreateMenubar(HWND);
void OpenDialog(HWND);
void LoadFile(LPSTR);
#define IDM_FILE_NEW 1
HWND ghwndEdit;
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
MSG msg ;
WNDCLASS wc = {0};
wc.lpszClassName = TEXT( "Opendialog" );
wc.hInstance = hInstance ;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc ;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&wc);
CreateWindow( wc.lpszClassName, TEXT("Opendialog"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
150, 150, 265, 200, 0, 0, hInstance, 0);
while( GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch(msg)
{
case WM_CREATE:
ghwndEdit = CreateWindowEx(WS_EX_RIGHTSCROLLBAR, TEXT("edit"), NULL,
WS_VISIBLE | WS_CHILD | WS_HSCROLL | WS_VSCROLL | ES_MULTILINE,
0, 0, 260, 180,
hwnd, (HMENU) 1, NULL, NULL);
CreateMenubar(hwnd);
break;
case WM_SIZE:
SetWindowPos(ghwndEdit, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam),
SWP_NOMOVE | SWP_NOZORDER);
break;
case WM_COMMAND:
if (wParam==IDM_FILE_NEW) {
OpenDialog(hwnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void CreateMenubar(HWND hwnd) {
HMENU hMenubar;
HMENU hMenu;
hMenubar = CreateMenu();
hMenu = CreateMenu();
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hMenu, TEXT("&File"));
AppendMenu(hMenu, MF_STRING, IDM_FILE_NEW, TEXT("&Open"));
SetMenu(hwnd, hMenubar);
}
void OpenDialog(HWND hwnd)
{
OPENFILENAME ofn;
TCHAR szFile[MAX_PATH];
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFile = szFile;
ofn.lpstrFile[0] = '\0';
ofn.hwndOwner = hwnd;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = TEXT("All files(*.*)\0*.*\0");
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = NULL;
ofn.lpstrFileTitle = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn))
LoadFile(ofn.lpstrFile);
}
void LoadFile(LPSTR file)
{
HANDLE hFile;
DWORD dwSize;
DWORD dw;
LPBYTE lpBuffer = NULL;
hFile = CreateFile(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
dwSize = GetFileSize(hFile, NULL);
lpBuffer = (LPBYTE) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, dwSize + 1);
ReadFile(hFile, (LPWSTR)lpBuffer, dwSize, &dw, NULL);
CloseHandle(hFile);
lpBuffer[dwSize] = 0;
SetWindowText(ghwndEdit, (LPSTR) lpBuffer);
HeapFree(GetProcessHeap(), 0, lpBuffer);
}
In this example, we create a window with a multiline edit control.
To create an openfile dialog box, we create and fill the OPENFILENAME structure.
ofn.lpstrFile = szFile;
If the OpenFileName() function returns TRUE, the name of the selected file is in the lpstrFile member.
ofn.lpstrFilter = TEXT("All files(*.*)\0*.*\0");
This defines the file filter. In our example, the dialog shows all file types.
ofn.nFilterIndex = 1;
Specifies the index of the currently selected filter in the File Types combo box control.
if(GetOpenFileName(&ofn))
LoadFile(ofn.lpstrFile);
We call the GetOpenFileName() function to show the Openfile dialog box. If we click on the Open button, the function returns TRUE and we call the user defined LoadFile() function.
Inside the LoadFile() function, we read the file and put the contents of the file into the edit control. We create a file handle. Than we find out the file size. Allocate dynamic memory for the contents of the file. Read the contents into the memory and put them into the edit control. To put the contents into the edit control, we call the SetWindowText() function. We must not forget to close the file handle and free the dynamic memory.
In this part of the Winapi tutorial, we worked with dialogs.