Child window for Internet explorer flickering - c++

I am writing a browser helper object and want to show a child window inside the internet explorer window to show the user some messages. I use DS_CONTROL and WS_CHILDWINDOW and want to get a behaviour similar to the message in this image:
I succeeded in inserting and showing a child window, but the window is flickering and sometimes it's visible and sometimes the website content is above the window in the z coordinate. I tried to set the child window as topmost window, but that didn't change anything. How can I get the child window to be always visible until it is closed? Here is some source code I use:
resource.rc:
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"
//
// Dialog resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_NOTIFICATIONBAR DIALOG 0, 0, 186, 95
STYLE DS_3DLOOK | DS_CONTROL | DS_MODALFRAME | DS_SYSMODAL | DS_SHELLFONT | WS_VISIBLE | WS_CHILDWINDOW
EXSTYLE WS_EX_TOPMOST
FONT 8, "Ms Shell Dlg"
{
DEFPUSHBUTTON "OK", IDOK, 129, 7, 50, 14
PUSHBUTTON "Cancel", IDCANCEL, 129, 24, 50, 14
LTEXT "Static", IDC_STATIC, 25, 16, 68, 21, SS_LEFT
}
Dialog class:
#include "atlbase.h"
#include "atlwin.h"
#include "resources/resource.h"
class CMyDialog : public CDialogImpl<CMyDialog>
{
public:
enum { IDD = IDD_NOTIFICATIONBAR };
BEGIN_MSG_MAP(CMyDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnBnClickedCancel)
END_MSG_MAP()
CMyDialog() {Create(::GetActiveWindow());}
~CMyDialog() {DestroyWindow();}
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/,
BOOL& /*bHandled*/)
{
// ::MessageBox(NULL,_T("OnInit"),_T("OnInit"),MB_ICONINFORMATION|MB_OK);
// Do some initialization code
return 1;
}
static CMyDialog &getInstance()
{
static CMyDialog dlg;
return dlg;
}
public:
LRESULT OnBnClickedCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
ShowWindow(SW_HIDE);
return 0;
}
};
Call:
CMyDialog &bar=CMyDialog::getInstance();
bar.ShowWindow(SW_SHOWNORMAL);

You have to resize the MSHTML window to make room for your control.

Try making room for your control by manipulating
IWebBrowser2.Top or
the HWND returned by IWebBrowser2.HWND
The second link also contains an example for getting the window handle of tabs. But I don't know if this also works from a BHO or only if hosting the control.

Finally I could solve it (with the help of the information I got from the many different answers below).
For those of you having the same problem, here the solution:
I have to shrink the window that is displaying the HTML website, so my own window doesn't overlap with it.
For this I get the current tab like in the example here.
This tab window contains the html document window and the status bar.
So I call FindWindowEx twice to get the HWNDs of those two windows:
FindWindowEx(tab,NULL,_T("Shell DocObject View"),_T("")) //html document window
FindWindowEx(tab,NULL,_T("msctls_statusbar32"),_T("")) //status bar
Then I resize the document window so that it fills the whole client area except for the place taken by the status bar and the place taken by my dialog. Here is the code (webbrowser.getCurrentTabHwnd() is an implementation of the example here mentioned above. isShown is a variable indicating, if my dialog should be shown or not):
CWindow tab(webbrowser.getCurrentTabHwnd());
CWindow child(FindWindowEx(tab,NULL,_T("Shell DocObject View"),_T("")));
CWindow statusbar(FindWindowEx(tab,NULL,_T("msctls_statusbar32"),_T("")));
RECT statusbarrect;
statusbar.GetWindowRect(&statusbarrect);
RECT documentrect;
tab.GetClientRect(&documentrect);
documentrect.bottom-=(statusbarrect.bottom-statusbarrect.top);
if(isShown)
{
//Request document window rect
static const unsigned int DLGHEIGHT=50;
RECT dialogrect=documentrect;
documentrect.top+=DLGHEIGHT;
dialogrect.bottom=dialogrect.top+DLGHEIGHT;
//Shrink document window
MoveWindow(&dialogrect);
}
child.MoveWindow(&documentrect);
This piece of code now has to be called on each browser window resize and on dialog show/hide.

Related

Who should be the parent of a tab control child dialog?

According to some sources, a tab child dialog should be the child of the actual main dialog window, not the tab control itself. I think some of the docs suggest the opposite, namely this function example:
// Creates a child window (a static control) to occupy the tab control's
// display area.
// Returns the handle to the static control.
// hwndTab - handle of the tab control.
//
HWND DoCreateDisplayWindow(HWND hwndTab)
{
HWND hwndStatic = CreateWindow(WC_STATIC, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER,
100, 100, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, g_hInst, // g_hInst is the global instance handle
NULL);
return hwndStatic;
}
So is there a definitive view on this? I checked Petzold, by the way, but didn't locate anything on the subject. Thanks for any help.

How to get the background colour of CTabCtrl?

I have a CTabCtrl on my dialog, and it has several labels (CStatic) on them. The problem is, the tab control has a white background, and the labels have grey backgrounds. I know why - the parent of the labels is actually the dialog, not the tab control. However, I should be able to use CWnd::OnCtlColor to provide a custom background brush for the labels:
HBRUSH MyDialog::OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor)
{
HBRUSH hBrush = __super::OnCtlColor(pDC, pWnd, nCtlColor);
const int dialogId = pWnd->GetDlgCtrlID();
if (dialogId == IDC_MY_CONTROL)
{
pDC->SetBkMode(TRANSPARENT);
hBrush = m_nullBrush;
}
return hBrush;
}
Here I use m_nullBrush to provide a brush to paint the background of the labels with, the only trouble is, I don't know how to get the tab's background colour, and instead have got it hardcoded with m_nullBrush.CreateStockObject(WHITE_BRUSH);.
Even if I re-parent the labels onto the tab control, they still end up with a grey background (even though the tab control has a white background).
How do I retrieve the background colour of a CTabCtrl?
You can put your controls in a child dialog and you must enable theme for this child dialog using EnableThemeDialogTexture.
#include "Uxtheme.h"
...
BOOL CTabDemoDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
COneDlg* OneDlg= new COneDlg;
OneDlg->Create(IDD_ONE, this);
AddPage(OneDlg, L"One");
return TRUE;
}
void CTabDemoDlg::AddPage(CDialog *Dialog, const wchar_t* Title)
{
if (IsAppThemed())
EnableThemeDialogTexture(*Dialog, ETDT_ENABLETAB);
CRect Rect;
TabCtl.GetWindowRect(Rect);
Rect.top+= 20;
Rect.InflateRect(-4, -4);
ScreenToClient(Rect);
Dialog->MoveWindow(Rect);
TabCtl.InsertItem(0, Title);
}
IDD_ONE DIALOGEX 0, 0, 224, 111
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
EXSTYLE WS_EX_CONTROLPARENT
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "Check1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,16,39,10
LTEXT "Static",IDC_STATIC,20,36,19,8
EDITTEXT IDC_EDIT1,20,48,40,14,ES_AUTOHSCROLL
PUSHBUTTON "Button1",IDC_BUTTON1,84,16,50,14
END

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;
}

CDialog doesnt show in task bar

Im trying to get a CDialog that has no border or frame to show in the task bar.
It is created in the InitInstance of CWinApp (used to update the app) and i have tried setting the WS_EX_APPWINDOW flag but it still doesnt show in the task bar.
Any ideas?
Edit:
As defined in the resource:
IDD_UPDATEFORM_DIALOG DIALOGEX 0, 0, 246, 124
STYLE WS_POPUP
EXSTYLE WS_EX_APPWINDOW
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
As used:
UpdateForm *dlg = new UpdateForm(UPDATE_FILES, CWnd::GetDesktopWindow());
INT_PTR nResponse = dlg->DoModal();
UpdateForm::UpdateForm(int updateType, CWnd* pParent) : CDialog(IDD_UPDATEFORM_DIALOG, pParent)
{
m_bInit = false;
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON);
m_Progress = new DesuraProgress();
m_updateType = updateType;
}
Still Shows up like so:
http://update.goldeneyesource.net/lodle/noicon.jpg http://update.goldeneyesource.net/lodle/noicon.jpg
Edit #2:
To set the icon for this window (essentially a splash screen), you can send the window a WM_SETICON message along with a desired icon.
For a dialog, you can do this in OnInitDialog(). Here's a snippet that uses the default windows information icon as noted here: LoadIcon # MSDN.
// CHelperDlg message handlers
BOOL CHelperDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 32516 is also known as IDI_INFORMATION
HICON hIcon = LoadIcon(0, MAKEINTRESOURCE(32516));
// 0 in WPARAM is 'small version'
::SendMessage(GetSafeHwnd(), WM_SETICON, 0, (LPARAM)hIcon);
// 1 in WPARAM is 'large version'
::SendMessage(GetSafeHwnd(), WM_SETICON, 1, (LPARAM)hIcon);
// No cleanup as HICONs are free from disposal rules.
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
--
Edit:
I created a second project to mimic your update, but I don't see any differences except the inclusion of DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS) in my .rc file. These dialog style definitions don't affect the display of the dialog.
I've uploaded key parts for my minimal example to http://gist.github.com/461057 for your reference, in case you'd like to try adding this dialog ahead of yours for testing.
Also, I'm using VS2010. I have VS2008 available if you'd like me to repeat this test in that version as well.
--
Original:
Try specifying the desktop window (via CWnd::GetDesktopWindow()) as the parent window when you create the dialog.
// Member Variable
CHelperDlg *dlg;
// Meanwhile, elsewhere...
dlg = new CHelperDlg();
dlg->Create(IDD_HELPERDLG, CWnd::GetDesktopWindow());
dlg->ShowWindow(SW_SHOW);
// or...
// dlg->DoModal();
Also, don't forget to destroy the dialog when you're done with it, either in the destructor of the class owner, or other convenient location.
I figured out a hack to get this to work. Instead of disabling the toolbar/caption bar styles to get no border, i used SetWindowRgn to clip the frame and title bar. Same affect, less issues.
RECT rect;
GetWindowRect(&rect);
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
HRGN region = CreateRoundRectRgn(5, 30, w-5, h-5-30, 5, 5);
SetWindowRgn(region, true);

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