How to make a window open in a cascade position (using MFC) - c++

I am using Windows MFC to create a small program.
I would like to make multiple instances of the program appear in a cascaded position(s).
Currently the program always appear centered, i.e. it is not possible to see it multiple windows.
Is there an automatic way to let windows create multiple instance in cascaded positions?
To test i use a batch script with multiple lines of:
"start MyProgram.exe"
"start MyProgram.exe"
"start MyProgram.exe"
The dialogs i use are derived from CDialogEx (but i had same using CDialog)
I expected this to be a flag/properties of the dialog.
Before changing the .rc-file have properties like this
IDD_MAIN_DLG DIALOGEX 0, 0, 260, 185 STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION
I am aware of the CascadeWindows() function, but to my knowledge it requires more awareness of which instances that already run

How about the following code as a starting point?
#include <Psapi.h>
namespace {
size_t nWnds = 0;
HWND hWnds[10];
BOOL CALLBACK enumerate(HWND hWnd, LPARAM This)
{
HWND hWndThis = reinterpret_cast<HWND>(This);
TCHAR nameThis[MAX_PATH], nameOther[MAX_PATH];
VERIFY(GetWindowModuleFileName(hWndThis, nameThis, _countof(nameThis)));
TCHAR wndclass[32];
VERIFY(RealGetWindowClass(hWnd, wndclass, _countof(wndclass)));
if (_tcscmp(wndclass, _T("#32770")) == 0) {
DWORD pid;
GetWindowThreadProcessId(hWnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
if (GetModuleFileNameEx(hProcess, NULL, nameOther, _countof(nameOther))) {
if (_tcscmp(nameThis, nameOther) == 0) {
hWnds[nWnds++] = hWnd;
}
}
VERIFY(CloseHandle(hProcess));
hProcess = NULL;
}
}
return TRUE;
}
}
BOOL CMFCApplication1Dlg::OnInitDialog()
{
// ...
VERIFY(EnumWindows(enumerate, reinterpret_cast<LPARAM>(m_hWnd)));
if (nWnds > 1) {
VERIFY(CascadeWindows(NULL, MDITILE_ZORDER, NULL, nWnds, hWnds));
}
return TRUE;
}
It consists of a change to OnInitDialog to scan for all top level dialogs that have been created by your executable and then call CascadeWindows. Of course in enumerate you can also move every window you find to a point that starts at CPoint(x, y) and changes by CSize(xoffset, yoffset) with every found window.
Some things to keep in mind:
CascadeWindows does not look like the right solution, it restores all maximized windows and does not only touch windows created by your process (which I would prefer).
If your process creates multiple top level dialogs, then you might need to detect which dialogs to move.
If the user makes a copy of your program file then the module file name will be different.
Just proof of concept code, you'll need to add error checking and bounds checking.

Related

unable to set focus to CEdit control

I encounter a problem with CEdit textbox , the exact problem is that i unable to Set Focus to the control after creating it.
What i want to do is:
Create CEdit control temporary.
Set focus to the control.
Get the number from the control and store it in a value.
Destroy control after 10 second.
After some research on internet i couldn’t find solution to the problem , therefore i address to you.
Hope to find a solution. Thanks in advance.
i tried
editctrl.SetFocus();
DWORD dw = LOWORD(editctrl.GetDlgCtrlID()) | HIWORD(EN_SETFOCUS);
SendMessage(WM_COMMAND,(WPARAM)dw, (LPARAM)editctrl.GetHandle());
BOOL CViewsDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == 0xBB /*+*/)
{
if (!editctrl)
{
editctrl.Create(ES_NUMBER | WS_CHILD|WS_VISIBLE | WS_BORDER | WS_TABSTOP, CRect(0, 0, 100, 20), this, NULL);
editctrl.ShowWindow(SW_SHOW);
editctrl.SetFocus();
//DWORD dw = LOWORD(editctrl.GetDlgCtrlID()) | HIWORD(EN_SETFOCUS);
//SendMessage(WM_COMMAND,(WPARAM)dw, (LPARAM)editctrl.GetHandle());
telestis = e_sinplin;
SetTimer(1, 10000, NULL);
}
}
return CDialogEx::PreTranslateMessage(pMsg);
}
You need to use CDialog::GotoDlgCtrl to set focus in dialog windows.

Open Qt MainWindow on top of every other window in single instance Qt application version 5.11.1 in Visual Studio

I have made single instance running Qt application (Qt version 5.11.1) in Visual Studio. Once it executed the first time, my main window will open and I am closing it. It keeps running in the background.
When I run .exe the second time, I want to open the previous mainWindow which I opened the first time.
I am enumerating available windows title and I am getting "Test Window" title. but using this HWND I am trying to set in the foreground on top of every other window using SetForegroundWindow(hwnd);.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
if (IsWindowVisible(hwnd)) // check whether window is visible
{
char wnd_title[256];
GetWindowText(hwnd, wnd_title, sizeof(wnd_title));
MessageBox(0, wnd_title, "Installation Error", MB_OK | MB_ICONEXCLAMATION);
if (strcmp(wnd_title, "Test Window") == 0)
{
SetForegroundWindow(hwnd);
int err = GetLastError();
string msg = "error code " + std::to_string(err);
MessageBox(0, msg.c_str(),"Installation Error ", MB_OK | MB_ICONEXCLAMATION);
return false;
}
}
return true; // function must return true if you want to continue enumeration
}
How do I open on Qt MainWindow on top of all other windows when I run second time.
check out the project QtSingleApplication found in https://github.com/qtproject/qt-solutions.
In QtSingleApplication class there is a method named activateWindow. In the Loader Example this method gets called whenever a second instance of the program is run.
To make the main window go on top when you try to open a second instance you've got to modify this method like this.
void QtSingleApplication::activateWindow()
{
if (actWin) {
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
actWin->activateWindow();
actWin->raise();
//winapi call
SetWindowPos((HWND)actWin->winId() , HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
//hack to prevent sticking window to the fore
SetWindowPos((HWND)actWin->winId() , HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
}
Warning: this is a windows-only solution and it works on my machine. Be also sure to include windows.h in the implementation.
[edit] My code had the problem that once activated, window stayed to the fore. This hack sort of fixes it.

DialogBoxIndirect creates dialog bigger than asked

For my application I need to create a Dialog Box without using resource.
I am trying to do it with DialogBoxInderect function.
The code is unbelievably ugly but somehow I succeeded to do it.
The problem is that dialog, for some reason, is much bigger than I asked with much bigger fonts.
Here is how the dialog looks like if I load it from resource:
And here is the dialog with the same size stated when I call DialogBoxInderect function.
Here is how it is defined in code:
HGLOBAL hGlobal;
LPDLGTEMPLATE wlsDialogTemplate;
LPDLGITEMTEMPLATE wlsDialogItemTemplate;
LPWORD nextItem;
LPWSTR itemString;
int32_t itemStringLength;
// Check for memory allocation errors
hGlobal = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hGlobal)
return -1;
wlsDialogTemplate = (LPDLGTEMPLATE)GlobalLock(hGlobal);
// Define a dialog box.
wlsDialogTemplate->style = WS_CAPTION;
wlsDialogTemplate->x = 0;
wlsDialogTemplate->y = 0;
wlsDialogTemplate->cx = 320;
wlsDialogTemplate->cy = 115;
GlobalUnlock(hGlobal);
retCode = DialogBoxIndirect(0, (LPDLGTEMPLATE)hGlobal, 0, ActivateWlsMsgDialog);
And here is how it is defined in RC file:
IDD_WLS_SMALL_MESSAGE_DLG DIALOGEX 0, 0, 320, 115
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",ID_CUSTOM_OK,175,95,120,15
PUSHBUTTON "Cancel",ID_CUSTOM_CANCEL,45,95,120,15
CTEXT "Static",IDC_HEADER_TEXT,120,10,170,70
CONTROL "",IDC_LOGO,"Static",SS_BITMAP,16,10,83,70
END
As you can see, the second dialog is much bigger than defined. I tried to play with various style flags but without any success (That is why there is red cross on the bigger dialog).
Any help with that?
Thanks!
The larger size is easy to explain. Windows automatically sizes the dialog in accordance with its font, and the larger dialog uses a different font. In fact, it is using the default system font (more info on the confusing issue of Windows dialog fonts is found in my answer here).
So the real issue to focus on is why it's using a different font, and fixing that will solve the size problem.
In the dialog box resource file, you specify the DS_SETFONT flag as one of the dialog box styles. According to the documentation, this flag
[i]ndicates that the header of the dialog box template (either standard or extended) contains additional data specifying the font to use for text in the client area and controls of the dialog box. If possible, the system selects a font according to the specified font data. The system passes a handle to the font to the dialog box and to each control by sending them the WM_SETFONT message.
So that explains why that one is displaying with the expected font.
The next logical question is what's different about your dynamically-created dialog template, shown with the DialogBoxIndirect function. The culprit is, once again, the DS_SETFONT flag, but in this case, the flag is absent. That means that the dialog doesn't contain any information about which font to use to display its controls, and the system defaults to the default system font (which is the ugly Windows 2.0-era font that you see in the second screenshot).
Once we've come to this understanding, the solution should be obvious: you need to tell the dialog which font you want it to use. There are two possible ways of doing so that come to mind:
You can set the DS_SETFONT flag and provide the font information in the header of the dialog box template as described in the above-linked documentation.
Or you can simply create and set the dialog's font in response to the WM_INITDIALOG message.
The latter is probably what you really want to do, as it allows you to use the actual system font (which, confusingly, is different from what I've been calling the "default" system font), which is Segoe UI in Windows Vista and later. Note that even in your first screenshot, it's using MS Sans Serif and therefore sticks out like a sore thumb in the Aero interface. Again, see this answer for more about fonts than you ever wanted to know and sample code for making this work. You'll need to make sure that you set the font for the dialog itself and all of its child controls.
I had played with DialogBoxIndirect (actually with DialogBoxIndirectParam), and here's the part of the code that sets the font. Observe the DS_SHELLFONT option.
LPWORD lpwAlign(LPWORD lpIn, int nAlignment)
{
return (LPWORD)(((ULONG_PTR)lpIn + nAlignment - 1) & -nAlignment);
}
LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner, LPMYMESSAGEPARAMS pParams)
{
WORD mem[1024]; // Buffer for dialog resource
LPDLGTEMPLATEW lpdt; // Pointer to heading resource structure
LPDLGITEMTEMPLATEW lpdit; // Pointer to current control
LPWORD lpw; // Cursor to resource buffer
LPWSTR lpwsz; // Cursor to resource buffer (of type WCHAR)
LPCWSTR lpwszCaption; // Aux pointer for text copying
LRESULT ret; // Function's return value
lpdt = (LPDLGTEMPLATEW)lpwAlign( mem, 4 );
//-----------------------
// Define a dialog box.
//-----------------------
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION |
DS_MODALFRAME | DS_CENTER | DS_SHELLFONT;
lpdt->dwExtendedStyle = 0;
lpdt->cdit = 3; // number of controls
lpdt->x = 0; lpdt->y = 0;
lpdt->cx = 164; lpdt->cy = 49;
lpw = (LPWORD)(lpdt + 1);
// Dialog menu
*lpw++ = 0;
// Dialog class
*lpw++ = 0;
// Dialog title
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"Choose language";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
// Dialog font
if ( lpdt->style & (DS_SETFONT | DS_SHELLFONT) )
{
// Size
*lpw++ = 8;
// Typeface name
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"MS Shell Dlg";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
}
// Define the rest of the controls
...
ret = DialogBoxIndirectParamW( hinst, lpdt,
hwndOwner, MyMessageProc, (LPARAM)pParams );
return ret;
}
This can be solved in your dialog handler by looking for the WM_INITDIALOG message, and then setting the font for all the controls in the dialog.
int CALLBACK SetChildFont(HWND child, LPARAM font) {
SendMessage(child, WM_SETFONT, font, TRUE);
return TRUE;
}
static int CALLBACK MyMessageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG:
/* Set font for dialog and all child controls */
EnumChildWindows(hwnd, (WNDENUMPROC)SetChildFont, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
break;
}
return 0;
}

BringWindowToTop is Not working even if I get the handle to Class Window

I am registering my Class in the following method:
BOOL CNDSClientDlg::InitInstance()
{
//Register Window Updated on 16th Nov 2010, #Subhen
// Register our unique class name that we wish to use
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS));
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndcls.lpszMenuName = NULL;
//Class name for using FindWindow later
wndcls.lpszClassName = _T("CNDSClientDlg");
// Register new class and exit if it fails
if(!AfxRegisterClass(&wndcls)) // [C]
{
return FALSE;
}
}
and then calling the InitInstance method and creating the window in constructor of the Class:
CNDSClientDlg::CNDSClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNDSClientDlg::IDD, pParent)
{
InitInstance();
HWND hWnd;
hInst = AfxGetInstanceHandle(); // Store instance handle in our global variable
hWnd = CreateWindow(_T("CNDSClientDlg"), "NDS", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
}
Now in my other application I am finding the window and trying to bring to top:
Edit
Able to bring newlyCreated Windows with below code
CWnd *pWndPrev = NULL;
CWnd *FirstChildhWnd = NULL;
pWndPrev = CWnd::FindWindow(_T("CNDSClientDlg"),NULL);
if(pWndPrev != NULL)
{
//pWndPrev->BringWindowToTop();
WINDOWPLACEMENT wndplacement;
pWndPrev->GetWindowPlacement(&wndplacement);
wndplacement.showCmd = SW_RESTORE;
pWndPrev->SetWindowPlacement(&wndplacement);
pWndPrev->SetForegroundWindow();
FirstChildhWnd = pWndPrev->GetLastActivePopup();
if (pWndPrev != FirstChildhWnd)
{
// a pop-up window is active, bring it to the top too
FirstChildhWnd->GetWindowPlacement(&wndplacement);
wndplacement.showCmd = SW_RESTORE;
FirstChildhWnd->SetWindowPlacement(&wndplacement);
FirstChildhWnd->SetForegroundWindow();
}
I am able to find the window as pWndPrev is not NULL , but It is not bringing up my application to front. Do I need to register any other class Instead of CNDSClientDlg. I want to bring my MFC application to top.
A few things to look at...
1) Try SetForegroundWindow() instead of BringWindowToTop(). It's been awhile since I've done Win32 programming, but I seem to recall that BringWindowToTop() has some limitations (especially when working with windows in different processes).
2) There are some rules that Microsoft put in place regarding SetForegroundWindow() starting with Windows 2000. The short version is that only the front-most application can change the foreground window. The idea is that an application that is not front-most cannot "jump in front of" the active application. If a background application calls SetForegroundWindow(), Windows will flash the taskbar button for the app, but will not actually bring the app to the front. The user must do that. I'm oversimplifying the rules, but this may be something to look at depending on your specific scenario.
BringWindowToTop() only works if the calling process is the foreground process or if it received the last input event.
Call CWnd::SetForegroundWindow() instead.
You may need to call AllowSetForegroundWindow in your "other" application before calling SetForegroundWindow.
That is assuming your other application is the foreground app and is trying to pass on its foreground status to the application with the window.
If neither app is the foreground app then you're not supposed to be able to bring a window to the front, although there are ways to do it (both accidentally and on purpose).
SetWindowPos(&wndTopMost, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
SetForegroundWindow();

Windows API dialogs without using resource files

I'm trying to create a dialog box using C++ and the windows API, but I don't want the dialog defined in a resource file. I can't find anything good on this on the web, and none of the examples I've read seem to define the dialog programmatically.
How can I do this?
A simple example is fine. I'm not doing anything complicated with it yet.
Raymond Chen wrote a few posts about the dialog manager:
The dialog manager, part 1: Warm-ups
The dialog manager, part 2: Creating the frame window
The dialog manager, part 3: Creating the controls
The dialog manager, part 4: The dialog loop
The dialog manager, part 5: Converting a non-modal dialog box to modal
The dialog manager, part 6: Subtleties in message loops
The dialog manager, part 7: More subtleties in message loops
The dialog manager, part 8: Custom navigation in dialog boxes
The dialog manager, part 9: Custom accelerators in dialog boxes
If all you want to do is show a window with controls, it's possible to create a window without using resource (.rc) files / scripts.
This isn't the same as a dialog, but it might be easier than creating a dialog programmatically.
First, a few notes about how this is done:
Instead of designing the dialog in the rc file, you could manually use CreateWindow (or CreateWindowEx) to create child windows of a main window. (for .NET Windows Forms programmers, these windows are like Controls).
This process will not be graphical at all (you will need to manually type in the location and size of each window), but I think this can be a great way to understand how dialogs are created under the hood.
There are some disadvantages to not using a real dialog, namely that tab will not work when switching between controls.
About the example:
This example features a dialog box with two buttons, an edit box (.NET Windows Forms programmers would think of it as a TextBox), and a check box.
It has been tested under the following conditions:
x86 build
x64 build
Unicode build (UNICODE and _UNICODE defined)
Non-Unicode build (UNICODE and _UNICODE not defined)
Built with Visual Studio's C compiler
Built with Visual Studio's C++ compiler
OS: Windows 10 64 bit
Note: UNICODE
As of the time of writing, UTF-8 is still in beta for Windows 10
If you have not enabled this setting, you should assume that any char* is ACP, not UTF-8, this applies to standard library functions too
Even though in Linux, that same standard library function would be UTF-8.
Sadly, some C++ standard library features only work with char* (e.g., exception messages).
You can still use UTF-8 in Windows without the option set, you will just have to encode it back to UTF-16 before calling winapi functions.
Here is a reddit thread with a reply from somebody who claims to have worked on UTF-8 on Windows, it has some good information.
UNICODE in Windows means "UTF-16", not "UTF-8".
Using Unicode of some kind is strongly recommended for any version of Windows that is not very old.
Be aware that if you don't use Unicode, your program may be utterly unable to open file names containing Unicode characters, handle directories (e.g., usernames) with non-ACP characters, etc.
Using ACP functions (SendMessageA,etc) without somehow verifying that UTF-8 is enabled (it's disabled by default) is probably a bug.
For max portability/flexibility, I would recommend using UTF-16 and the W version of all API functions, translating from UTF-8 to UTF-16 at the last minute. Read this page very carefully.
Now for the code:
Note that a large amount of comments have been added to try to document the windows functions, I recommend copy/pasting this into a text editor, for best results.
// This sample will work either with or without UNICODE, it looks like
// it's recommended now to use UNICODE for all new code, but I left
// the ANSI option in there just to get the absolute maximum amount
// of compatibility.
//
// Note that UNICODE and _UNICODE go together, unfortunately part
// of the Windows API uses _UNICODE, and part of it uses UNICODE.
//
// tchar.h, for example, makes heavy use of _UNICODE, and windows.h
// makes heavy use of UNICODE.
#define UNICODE
#define _UNICODE
//#undef UNICODE
//#undef _UNICODE
#include <windows.h>
#include <tchar.h>
// I made this struct to more conveniently store the
// positions / size of each window in the dialog
typedef struct SizeAndPos_s
{
int x, y, width, height;
} SizeAndPos_t;
// Typically these would be #defines, but there
// is no reason to not make them constants
const WORD ID_btnHELLO = 1;
const WORD ID_btnQUIT = 2;
const WORD ID_CheckBox = 3;
const WORD ID_txtEdit = 4;
const WORD ID_btnShow = 5;
// x, y, width, height
const SizeAndPos_t mainWindow = { 150, 150, 300, 300 };
const SizeAndPos_t btnHello = { 20, 50, 80, 25 };
const SizeAndPos_t btnQuit = { 120, 50, 80, 25 };
const SizeAndPos_t chkCheck = { 20, 90, 185, 35 };
const SizeAndPos_t txtEdit = { 20, 150, 150, 20 };
const SizeAndPos_t btnShow = { 180, 150, 80, 25 };
HWND txtEditHandle = NULL;
// hwnd: All window processes are passed the handle of the window
// that they belong to in hwnd.
// msg: Current message (e.g., WM_*) from the OS.
// wParam: First message parameter, note that these are more or less
// integers, but they are really just "data chunks" that
// you are expected to memcpy as raw data to float, etc.
// lParam: Second message parameter, same deal as above.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
// Create the buttons
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Note that the "parent window" is the dialog itself. Since we are
// in the dialog's WndProc, the dialog's handle is passed into hwnd.
//
//CreateWindow( lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam
//CreateWindow( windowClassName, initial text, style (flags), xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( TEXT("Button"), TEXT("Hello"), WS_VISIBLE | WS_CHILD, btnHello.x, btnHello.y, btnHello.width, btnHello.height, hwnd, (HMENU)ID_btnHELLO, NULL, NULL);
CreateWindow( TEXT("Button"), TEXT("Quit"), WS_VISIBLE | WS_CHILD, btnQuit.x, btnQuit.y, btnQuit.width, btnQuit.height, hwnd, (HMENU)ID_btnQUIT, NULL, NULL);
// Create a checkbox
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CreateWindow( TEXT("button"), TEXT("CheckBox"), WS_VISIBLE | WS_CHILD | BS_CHECKBOX, chkCheck.x, chkCheck.y, chkCheck.width, chkCheck.height, hwnd, (HMENU)ID_CheckBox, NULL, NULL);
// Create an edit box (single line text editing), and a button to show the text
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//Handle = CreateWindow(windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
txtEditHandle = CreateWindow(TEXT("Edit"), TEXT("Initial Text"), WS_CHILD | WS_VISIBLE | WS_BORDER, txtEdit.x, txtEdit.y, txtEdit.width, txtEdit.height, hwnd, (HMENU)ID_txtEdit, NULL, NULL);
//CreateWindow( windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( TEXT("Button"), TEXT("Show"), WS_VISIBLE | WS_CHILD, btnShow.x, btnShow.y, btnShow.width, btnShow.height, hwnd, (HMENU)ID_btnShow, NULL, NULL);
// Create an Updown control. Note that this control will allow you to type in non-number characters, but it will not affect the state of the control
break;
// For more information about WM_COMMAND, see
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647591(v=vs.85).aspx
case WM_COMMAND:
// The LOWORD of wParam identifies which control sent
// the WM_COMMAND message. The WM_COMMAND message is
// sent when the button has been clicked.
if (LOWORD(wParam) == ID_btnHELLO)
{
MessageBox(hwnd, TEXT("Hello!"), TEXT("Hello"), MB_OK);
}
else if (LOWORD(wParam) == ID_btnQUIT)
{
PostQuitMessage(0);
}
else if (LOWORD(wParam) == ID_CheckBox)
{
UINT checked = IsDlgButtonChecked(hwnd, ID_CheckBox);
if (checked)
{
CheckDlgButton(hwnd, ID_CheckBox, BST_UNCHECKED);
MessageBox(hwnd, TEXT("The checkbox has been unchecked."), TEXT("CheckBox Event"), MB_OK);
}
else
{
CheckDlgButton(hwnd, ID_CheckBox, BST_CHECKED);
MessageBox(hwnd, TEXT("The checkbox has been checked."), TEXT("CheckBox Event"), MB_OK);
}
}
else if (LOWORD(wParam) == ID_btnShow)
{
int textLength_WithNUL = GetWindowTextLength(txtEditHandle) + 1;
// WARNING: If you are compiling this for C, please remember to remove the (TCHAR*) cast.
TCHAR* textBoxText = (TCHAR*) malloc(sizeof(TCHAR) * textLength_WithNUL);
GetWindowText(txtEditHandle, textBoxText, textLength_WithNUL);
MessageBox(hwnd, textBoxText, TEXT("Here's what you typed"), MB_OK);
free(textBoxText);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// hInstance: This handle refers to the running executable
// hPrevInstance: Not used. See https://blogs.msdn.microsoft.com/oldnewthing/20040615-00/?p=38873
// lpCmdLine: Command line arguments.
// nCmdShow: a flag that says whether the main application window
// will be minimized, maximized, or shown normally.
//
// Note that it's necessary to use _tWinMain to make it
// so that command line arguments will work, both
// with and without UNICODE / _UNICODE defined.
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS mainWindowClass = { 0 };
// You can set the main window name to anything, but
// typically you should prefix custom window classes
// with something that makes it unique.
mainWindowClass.lpszClassName = TEXT("JRH.MainWindow");
mainWindowClass.hInstance = hInstance;
mainWindowClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
mainWindowClass.lpfnWndProc = WndProc;
mainWindowClass.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&mainWindowClass);
// Notes:
// - The classname identifies the TYPE of the window. Not a C type.
// This is a (TCHAR*) ID that Windows uses internally.
// - The window name is really just the window text, this is
// commonly used for captions, including the title
// bar of the window itself.
// - parentHandle is considered the "owner" of this
// window. MessageBoxes can use HWND_MESSAGE to
// free them of any window.
// - menuHandle: hMenu specifies the child-window identifier,
// an integer value used by a dialog box
// control to notify its parent about events.
// The application determines the child-window
// identifier; it must be unique for all
// child windows with the same parent window.
//CreateWindow( windowClassName, windowName, style, xPos, yPos, width, height, parentHandle, menuHandle, instanceHandle, param);
CreateWindow( mainWindowClass.lpszClassName, TEXT("Main Window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, mainWindow.x, mainWindow.y, mainWindow.width, mainWindow.height, NULL, 0, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// This code is based roughly on tutorial code present at http://zetcode.com/gui/winapi/
Further reading
The builtin set of window classes are rather limited, so you might be curious as to how you can define your own window classes ("Controls") using the Windows API, see the articles below:
Custom Controls in Win32 API: The Basics (Code Project)
The WINE emulator source serves as a good example of how the Windows API could be implemented, and how you can make your own window classes that imitate the behavior of builtin classes.
Zetcode.com's tutorials
NOTE: I originally intended this post to cover the creation of dialogs programmatically. Due to a mistake on my part I didn't realize that you can't just "show" a window as a dialog. Unfortunately I wasn't able to get the setup mentioned by Raymond Chen working. Even looking at WINE's source, it's not super clear.
Take a look at this toolkit that describes how to create dialogs without resource files.
It's in WTL. However, I'm sure you can pick apart the internals to achieve the same thing using the Win32 API directly.
Here you can find how to use Windows API dialogs without using resource files.
The Windows API (only the C Win32 API, no MFC) tutorial:
Windows API tutorial
Try to search MSDN for "dialog templates in memory".
See this for example: Dialog Boxes