Add Controls To Specific Tab Page in TabControl in C++ Win32 - winapi

I want to add some controls to the tab page in tabcontrol but it seems that it will be added to all pages and there is not tab page in tabcontrol by default.
I have read these links below but they did not help me and in some parts of them, confused me.
How to add controls to a Tab control
http://www.cplusplus.com/forum/windows/37161/
https://msdn.microsoft.com/en-us/library/bb760551.aspx
https://msdn.microsoft.com/en-us/library/hh298366.aspx
https://msdn.microsoft.com/en-us/library/ms645398.aspx
Here is my code :
[Code]:
#define ID_LBL 500
#define ID_BTN 501
#define ID_TBC 502
HWND hWnd;
void InserTabItem(HWND handle, LPWSTR text, int id)
{
TCITEM tci = { 0 };
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = wcslen(text);
SendMessage(handle, TCM_INSERTITEM, id, LPARAM(&tci));
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CREATE:
{
HWND button_handle = 0;
HWND label_handle = 0;
HWND tab_handle = 0;
tab_handle = CreateWindowEx(WS_EX_CONTROLPARENT, WC_TABCONTROL, 0, WS_VISIBLE | WS_CHILD, 10, 10, 200, 150, hWnd, HMENU(ID_TBC), 0, 0);
InserTabItem(tab_handle, L"page1", 0);
InserTabItem(tab_handle, L"page2", 1);
button_handle = CreateWindowEx(0, WC_BUTTON, L"test-button-page2", WS_VISIBLE | WS_CHILD, 10, 50, 150, 30, tab_handle, HMENU(ID_BTN), 0, 0);
label_handle = CreateWindowEx(0, WC_STATIC, L"test-label-page1", WS_VISIBLE | WS_CHILD, 10, 100, 150, 30, tab_handle, HMENU(ID_LBL), 0, 0);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
break;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviewInstance, LPSTR lpcmdline, int ncmdshow)
{
WNDCLASSEX wndexcls;
wndexcls.lpszClassName = L"win";
wndexcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndexcls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndexcls.hCursor = LoadCursor(NULL, IDC_ARROW);
wndexcls.hbrBackground = (HBRUSH)(COLOR_3DSHADOW + 1);
wndexcls.lpszMenuName = NULL;
wndexcls.style = NULL;
wndexcls.hInstance = hInstance;
wndexcls.cbSize = sizeof(WNDCLASSEX);
wndexcls.cbClsExtra = 0;
wndexcls.cbWndExtra = 0;
wndexcls.lpfnWndProc = WndProc;
RegisterClassEx(&wndexcls);
hWnd = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT, L"win", L"TestApp", WS_OVERLAPPEDWINDOW, 100, 100, 640, 380, 0, 0, hInstance, 0);
ShowWindow(hWnd, ncmdshow);
UpdateWindow(hWnd);
MSG wnd_msg;
while (GetMessage(&wnd_msg, NULL, 0, 0)>0)
{
TranslateMessage(&wnd_msg);
DispatchMessage(&wnd_msg);
}
return (int)wnd_msg.wParam;
}
I am looking for a safe and proper implementation.
Thanks for any help
========================================================
[Update]:
Thanks for comments but no answer in detail :(
Although that is not the implementation I am looking for(NotDialogBased), But from the forth link I mentioned :
How to Create a Tabbed Dialog Box :
https://msdn.microsoft.com/en-us/library/hh298366.aspx
Here is my code of that page :
[resource.h]:
#define IDD_Page1 101
#define IDD_Page2 102
#define IDD_Page3 103
#define IDD_Main_Dialog 104
#define IDC_BTN_Page1 1001
#define IDC_BTN2_Page1 1002
#define IDC_BTN_Page2 1013
#define IDC_BTN_Page3 1014
[Resource.rc]:
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//////////////////////////////////////////////////
//
// Dialog
//
IDD_Page1 DIALOGEX 0, 0, 313, 178
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Button2-Page1",IDC_BTN2_Page1,129,107,67,22
PUSHBUTTON "Button-Page1",IDC_BTN_Page1,127,77,67,22
END
IDD_Page2 DIALOGEX 0, 0, 309, 177
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Button-Page2",IDC_BTN_Page2,120,77,60,18
END
IDD_Page3 DIALOGEX 0, 0, 309, 177
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Button-Page3",IDC_BTN_Page3,120,73,64,25
END
IDD_Main_Dialog DIALOGEX 0, 0, 309, 177
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_Page1, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 306
TOPMARGIN, 7
BOTTOMMARGIN, 171
END
IDD_Page2, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
BOTTOMMARGIN, 170
END
IDD_Page3, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
BOTTOMMARGIN, 170
END
IDD_Main_Dialog, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
BOTTOMMARGIN, 170
END
END
#endif // APSTUDIO_INVOKED
#endif
[Main.cpp]:
#include <windows.h>
#include <CommCtrl.h>
#include "resource.h"
#pragma comment(lib, "ComCtl32.lib")
#define C_PAGES 3
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
HWND Win_Handle;
HWND Dailog_Handle;
HINSTANCE hInstance_Win_Global;
typedef struct {
WORD dlgVer;
WORD signature;
DWORD helpID;
DWORD exStyle;
DWORD style;
WORD cDlgItems;
short x;
short y;
short cx;
short cy;
WORD pointsize;
WORD weight;
BYTE italic;
BYTE charset;
} DLGTEMPLATEEX;
typedef struct tag_dlghdr {
HWND hwndTab; // tab control
HWND hwndDisplay; // current child dialog box
RECT rcDisplay; // display rectangle for the tab control
DLGTEMPLATEEX *apRes[C_PAGES];
} DLGHDR;
void InserTabItem(HWND handle, LPWSTR text, int id)
{
TCITEM tci = { 0 };
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = wcslen(text);
SendMessage(handle, TCM_INSERTITEM, id, LPARAM(&tci));
}
DLGTEMPLATEEX* DoLockDlgRes(LPCTSTR lpszResName)
{
HRSRC hrsrc = FindResource(NULL, lpszResName, RT_DIALOG);
HGLOBAL hglb = LoadResource(hInstance_Win_Global, hrsrc);
return (DLGTEMPLATEEX *)LockResource(hglb);
}
VOID WINAPI OnChildDialogInit(HWND hwndDlg)
{
HWND hwndParent = GetParent(hwndDlg);
DLGHDR *pHdr = (DLGHDR *)GetWindowLong(
hwndParent, GWL_USERDATA);
SetWindowPos(hwndDlg, NULL, pHdr->rcDisplay.left,
pHdr->rcDisplay.top,//-2,
(pHdr->rcDisplay.right - pHdr->rcDisplay.left),
(pHdr->rcDisplay.bottom - pHdr->rcDisplay.top),
SWP_SHOWWINDOW);
return;
}
VOID OnSelChanged(HWND hwndDlg)
{
DLGHDR *pHdr = (DLGHDR *)GetWindowLong(hwndDlg, GWL_USERDATA);
int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);
if (pHdr->hwndDisplay != NULL)
DestroyWindow(pHdr->hwndDisplay);
pHdr->hwndDisplay = CreateDialogIndirect(hInstance_Win_Global,
(DLGTEMPLATE *)pHdr->apRes[iSel], hwndDlg,DialogProc);
}
HRESULT OnTabbedDialogInit(HWND hwndDlg)
{
INITCOMMONCONTROLSEX iccex;
DWORD dwDlgBase = GetDialogBaseUnits();
int cxMargin = LOWORD(dwDlgBase) / 4;
int cyMargin = HIWORD(dwDlgBase) / 8;
TCITEM tie;
RECT rcTab;
HWND hwndButton;
RECT rcButton;
int i;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&iccex);
DLGHDR *pHdr = (DLGHDR *)LocalAlloc(LPTR, sizeof(DLGHDR));
SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)pHdr);
pHdr->hwndTab = CreateWindow(
WC_TABCONTROL, L"",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, 300, 200,
hwndDlg, NULL, hInstance_Win_Global, NULL
);
if (pHdr->hwndTab == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = L"First";
TabCtrl_InsertItem(pHdr->hwndTab, 0, &tie);
tie.pszText = L"Second";
TabCtrl_InsertItem(pHdr->hwndTab, 1, &tie);
tie.pszText = L"Third";
TabCtrl_InsertItem(pHdr->hwndTab, 2, &tie);
pHdr->apRes[0] = DoLockDlgRes(MAKEINTRESOURCE(IDD_Page1));
pHdr->apRes[1] = DoLockDlgRes(MAKEINTRESOURCE(IDD_Page2));
pHdr->apRes[2] = DoLockDlgRes(MAKEINTRESOURCE(IDD_Page3));
SetRectEmpty(&rcTab);
for (i = 0; i < C_PAGES; i++)
{
if (pHdr->apRes[i]->cx > rcTab.right)
rcTab.right = pHdr->apRes[i]->cx;
if (pHdr->apRes[i]->cy > rcTab.bottom)
rcTab.bottom = pHdr->apRes[i]->cy;
}
MapDialogRect(hwndDlg, &rcTab);
TabCtrl_AdjustRect(pHdr->hwndTab, TRUE, &rcTab);
OffsetRect(&rcTab, cxMargin - rcTab.left, cyMargin - rcTab.top);
CopyRect(&pHdr->rcDisplay, &rcTab);
TabCtrl_AdjustRect(pHdr->hwndTab, FALSE, &pHdr->rcDisplay);
SetWindowPos(pHdr->hwndTab, NULL, rcTab.left, rcTab.top,
rcTab.right - rcTab.left, rcTab.bottom - rcTab.top,
SWP_NOZORDER);
hwndButton = GetDlgItem(hwndDlg, IDC_BTN_Page1);
SetWindowPos(hwndButton, NULL,
rcTab.left, rcTab.bottom + cyMargin, 0, 0,
SWP_NOSIZE | SWP_NOZORDER);
GetWindowRect(hwndButton, &rcButton);
rcButton.right -= rcButton.left;
rcButton.bottom -= rcButton.top;
hwndButton = GetDlgItem(hwndDlg, IDC_BTN2_Page1);
SetWindowPos(hwndButton, NULL,
rcTab.left + rcButton.right + cxMargin,
rcTab.bottom + cyMargin, 0, 0,
SWP_NOSIZE | SWP_NOZORDER);
SetWindowPos(hwndDlg, NULL, 0, 0,
rcTab.right + cyMargin + (2 * GetSystemMetrics(SM_CXDLGFRAME)),
rcTab.bottom + rcButton.bottom + (2 * cyMargin)
+ (2 * GetSystemMetrics(SM_CYDLGFRAME))
+ GetSystemMetrics(SM_CYCAPTION),
SWP_NOMOVE | SWP_NOZORDER);
OnSelChanged(hwndDlg);
return S_OK;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CREATE:
{
Dailog_Handle = CreateDialogParam(hInstance_Win_Global, MAKEINTRESOURCE(IDD_Main_Dialog), hWnd, DialogProc, 0);
ShowWindow(Dailog_Handle, SW_SHOWDEFAULT);
UpdateWindow(Dailog_Handle);
SetWindowPos(Dailog_Handle, 0, 10, 10, 500, 300, SWP_NOZORDER);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
break;
}
return 0;
}
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_INITDIALOG:
{
OnTabbedDialogInit(hWnd);
OnChildDialogInit(hWnd);
return (INT_PTR)TRUE;
}
break;
case WM_NOTIFY:
{
switch (((LPNMHDR)lParam)->code)
{
case TCN_SELCHANGE:
{
OnSelChanged(hWnd);
}
break;
default:
break;
}
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return (INT_PTR)FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviewInstance, LPSTR lpcmdline, int ncmdshow)
{
WNDCLASSEX wndexcls;
wndexcls.lpszClassName = L"win";
wndexcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndexcls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndexcls.hCursor = LoadCursor(NULL, IDC_ARROW);
wndexcls.hbrBackground = (HBRUSH)(COLOR_3DSHADOW + 1);
wndexcls.lpszMenuName = NULL;
wndexcls.style = NULL;
wndexcls.hInstance = hInstance;
wndexcls.cbSize = sizeof(WNDCLASSEX);
wndexcls.cbClsExtra = 0;
wndexcls.cbWndExtra = 0;
wndexcls.lpfnWndProc = WndProc;
RegisterClassEx(&wndexcls);
Win_Handle = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT, L"win", L"TestApp", WS_OVERLAPPEDWINDOW, 100, 100, 640, 380, 0, 0, hInstance, 0);
hInstance_Win_Global = hInstance;
ShowWindow(Win_Handle, SW_SHOWDEFAULT);
UpdateWindow(Win_Handle);
MSG wnd_msg;
while (GetMessage(&wnd_msg, NULL, 0, 0)>0)
{
TranslateMessage(&wnd_msg);
DispatchMessage(&wnd_msg);
}
return (int)wnd_msg.wParam;
}
The Problem is that , after debugging , the application exites and does not show anything. if I comment the OnSelChanged(hWnd) and OnChildDialogInit(hWnd)
the application starts normally and shows the tabcontrol but not the controls on the pages. it seems that the problem is here.
the output log :
First-chance exception at 0x00BE1886 in testcppapp.exe: 0xC0000005: Access violation reading location 0x00000014.
The program '[16220] testcppapp.exe' has exited with code 0 (0x0).
I have Read the link below about Access violation reading location:
http://www.cplusplus.com/forum/general/17094/
But I can not fix the problem.
Please Post your Answer and Explain about it , not just brief in comments !
Thanks for any help.

One problem is here:
pHdr->hwndDisplay = CreateDialogIndirect(hInstance_Win_Global,
(DLGTEMPLATE*)pHdr->apRes[iSel], hwndDlg, DialogProc);
You are reusing the same dialog procedure for both main dialog and child dialogs. Main dialog creates child dialogs, child dialogs use the same procedure to create child dialogs... Also there are no error checks.
Beyond that, this code is too complicated. Just use a dialog box for main window. Create a new dialog IDD_DIALOG1 and drag/drop a tab control in it. Assign IDC_TAB1 for tab control ID. Try starting with this code instead:
#include <Windows.h>
#include <CommCtrl.h>
#include "Resource.h"
#pragma comment(lib,"comctl32.lib")
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
HINSTANCE g_hinst;
struct TData {
HWND page1, page2, page3;
HWND tab;
} data;
BOOL CALLBACK DialogPage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch(msg) {
case WM_COMMAND:
switch (wp) {
//...
}
}
return FALSE;
}
void OnSelChange() {
int sel = TabCtrl_GetCurSel(data.tab);
ShowWindow(data.page1, (sel == 0) ? SW_SHOW : SW_HIDE);
ShowWindow(data.page2, (sel == 1) ? SW_SHOW : SW_HIDE);
}
BOOL CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_INITDIALOG: {
data.page1 = CreateDialog(g_hinst, MAKEINTRESOURCE(IDD_Page1), hwnd, DialogPage);
data.page2 = CreateDialog(g_hinst, MAKEINTRESOURCE(IDD_Page2), hwnd, DialogPage);
data.tab = GetDlgItem(hwnd, IDC_TAB1);
if (data.tab)
{
TCITEM tci = { 0 };
tci.mask = TCIF_TEXT;
tci.pszText = L"Page1";
TabCtrl_InsertItem(data.tab, 0, &tci);
tci.pszText = L"Page2";
TabCtrl_InsertItem(data.tab, 1, &tci);
RECT rc;//find tab control's rectangle
GetWindowRect(data.tab, &rc);
POINT offset = { 0 };
ScreenToClient(hwnd, &offset);
OffsetRect(&rc, offset.x, offset.y); //convert to client coordinates
rc.top += 50;
SetWindowPos(data.page1, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_HIDEWINDOW);
SetWindowPos(data.page2, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_HIDEWINDOW);
OnSelChange();
}
break;
}
case WM_NOTIFY: {
switch (((LPNMHDR)lp)->code) {
case TCN_SELCHANGE:
OnSelChange();
break;
}
}
break;
case WM_COMMAND:
switch (wp) {
case IDOK: EndDialog(hwnd, wp); break;
case IDCANCEL: EndDialog(hwnd, wp); break;
}
}
return FALSE;
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE, LPWSTR, int)
{
g_hinst = hinst;
DialogBox(hinst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc);
return 0;
}

An approach that I am testing and looks promising is to use a dialog box template for each pane of the tab control within the modal dialog box.
For testing, I generated a starting Win32 GUI application and then hijacked the About box display triggered by IDM_ABOUT to display my own dialog box with a tab control rather than a standard About dialog.
case IDM_ABOUT:
// DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
{
CDialogTabTest x;
x.CreateModal (hWnd, hInst);
}
break;
After some research and refactoring and development I have the following approach.
I have created three classes for implementation: CDialogTest (handles the dialog box functionality), CDialogTabTest (handles the tab control within the dialog box), and CDialogTabPane (handles the individual tab panes that are displayed in the tab control).
The CDialogTest class provides the functionality for basic dialog box behavior. It allows for two kinds of dialog boxes, modal used to create the actual modal dialog box and non-modal used to create the tab control panes.
The CDialogTest class is designed to be used as a subclass and be extended for a particular dialog box or tab control pane.
The CDialogTabTest class extends CDialogTest to implement a modal dialog box. The CDialogTabPane class extends CDialogTest to implement a non-modal dialog box that is used as a tab control tab pane.
For MFC programmers some of the names may sound vaguely familiar as while working this out, I now understand some of the mechanics of the MFC classes for dialog boxes.
I put added some additional include files in the the stdafx.h file as that was a central place to put them for what I needed.
// TODO: reference additional headers your program requires here
#include "commctrl.h"
#include "windowsx.h"
#include <vector>
DialogTest.h
#pragma once
class CDialogTest
{
private:
static INT_PTR CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
public:
HINSTANCE m_hInst;
HWND m_hParent;
HWND m_hDlg;
CDialogTest();
CDialogTest(HINSTANCE hInst, HWND hParent = NULL);
virtual ~CDialogTest(void);
HWND CreateThing (HWND hWnd, LPCWSTR lpTemplateName, HINSTANCE hInst);
INT_PTR WINAPI CreateModal (HWND hWnd, LPCWSTR lpTemplateName, HINSTANCE hInst);
virtual int DoDataExchange (int iDir) { return 0; }
virtual int OnWmCommandInit () { return 0; }
virtual int OnWmNotify (LPNMHDR pNmhdr) { return 0; }
virtual int OnWmCommand (WPARAM wParam, LPARAM lParam) { return 0; }
};
and DialogTest.cpp
#include "StdAfx.h"
#include "DialogTest.h"
CDialogTest::CDialogTest(void)
{
}
CDialogTest::CDialogTest(HINSTANCE hInst, HWND hParent /* = NULL */) :
m_hInst (hInst), m_hParent(hParent)
{
}
CDialogTest::~CDialogTest(void)
{
}
INT_PTR CALLBACK CDialogTest::DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
// Set the provided object pointer into the dialog box user area
// so that we can use it to provide the necessary notifications
// to what ever object which has derived from this class.
::SetWindowLongPtr (hDlg, DWLP_USER, lParam);
// ensure that the object knows its dialog handle.
CDialogTest *pObj = (CDialogTest *)lParam;
pObj->m_hDlg = hDlg;
// call the objects handlers to initialize the dialog further
// and to then populate the data displayed in the dialog.
pObj->OnWmCommandInit ();
pObj->DoDataExchange (1);
}
return (INT_PTR)TRUE;
case WM_COMMAND:
// if this command is an Ok or Cancel button press then we are
// done. other command messages are routed to the derived object's
// how command message handler for further processing.
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
if (LOWORD(wParam) == IDOK) {
LPARAM lP = ::GetWindowLongPtr (hDlg, DWLP_USER);
CDialogTest *pObj = (CDialogTest *)lP;
pObj->DoDataExchange (0);
}
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
} else {
LPARAM lP = ::GetWindowLongPtr (hDlg, DWLP_USER);
CDialogTest *pObj = (CDialogTest *)lP;
pObj->OnWmCommand (wParam, lParam);
}
break;
case WM_NOTIFY:
{
LPARAM lP = ::GetWindowLongPtr (hDlg, DWLP_USER);
CDialogTest *pObj = (CDialogTest *)lP;
LPNMHDR pNmhdr = ((LPNMHDR)lParam);
pObj->OnWmNotify (pNmhdr);
}
break;
}
return (INT_PTR)FALSE;
}
// We need two different kinds of dialog create functions as we support
// both a modal dialog and a modeless dialog. The modal dialog is used to
// display an actual dialog box. The modeless dialog is used to display
// a tab control pane using a dialog template.
INT_PTR WINAPI CDialogTest::CreateModal (HWND hWnd, LPCWSTR lpTemplateName, HINSTANCE hInst)
{
m_hInst = hInst;
m_hParent = hWnd;
// display the modal dialog box and return the identifier for the button clicked.
return DialogBoxParam(hInst, lpTemplateName, hWnd, &CDialogTest::DlgProc, (LPARAM)this);
}
HWND CDialogTest::CreateThing (HWND hWnd, LPCWSTR lpTemplateName, HINSTANCE hInst)
{
m_hInst = hInst;
m_hParent = hWnd;
// create a modeless dialog box to be used as a tab control pane or similar
// non-modal dialog box use.
m_hDlg = ::CreateDialogParam(hInst, lpTemplateName, hWnd, &CDialogTest::DlgProc, (LPARAM)this);
return m_hDlg;
}
The class CDialogTabTest creates the modal dialog box that is being displayed as a result of the IDM_ABOUT menu selection message in the main application message handler.
DialogTabTest.h
#pragma once
#include "stdafx.h"
#include "DialogTest.h"
#include "DialogTabPane.h"
#include "resource.h"
struct CCheckBoxData
{
UINT iCntrlId;
int iCheck;
std::wstring prompt;
};
typedef std::vector<CCheckBoxData> CCheckBoxVector;
class CDialogTabTest : public CDialogTest
{
protected:
CDialogTabPane m_hTabPane1;
CDialogTabPane m_hTabPane2;
CDialogTabPane m_hTabPane3;
enum {IDD_DIALOG = IDD_DIALOG_TAB00};
public:
CDialogTabTest(void);
virtual ~CDialogTabTest(void);
INT_PTR WINAPI CreateModal (HWND hWnd, HINSTANCE hInst);
static int SetValues (CCheckBoxData &x, HWND hDlg);
static int GetValues (CCheckBoxData &x, HWND hDlg);
virtual int DoDataExchange (int iDir);
virtual int OnWmCommandInit ();
virtual int OnWmNotify (LPNMHDR pNmhdr);
};
and DialogTabTest.cpp which creates the modal dialog box and initializes it.
#include "StdAfx.h"
#include "DialogTabTest.h"
CDialogTabTest::CDialogTabTest(void)
{
}
CDialogTabTest::~CDialogTabTest(void)
{
}
int CDialogTabTest::SetValues (CCheckBoxData &x, HWND hDlg)
{
HWND hWnd = GetDlgItem (hDlg, x.iCntrlId);
::SetWindowText (hWnd, x.prompt.c_str());
Button_SetCheck (hWnd, x.iCheck);
return 0;
}
int CDialogTabTest::GetValues (CCheckBoxData &x, HWND hDlg)
{
HWND hWnd = GetDlgItem (hDlg, x.iCntrlId);
x.iCheck = Button_GetCheck (hWnd);
return 0;
}
int CDialogTabTest::OnWmCommandInit ()
{
// get the window handle for the tab control. This is going to
// be the parent window for all of the tab panes that are inserted
// into the tab control. By making the tab control the parent,
// the tab panes will be contained within the tab control and
// will flow with it should it be moved about.
HWND hTabCntrl = GetDlgItem (m_hDlg, IDC_TAB1);
TCITEM tie = {0};
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = L"First";
m_hTabPane1.CreateThing (&tie, 0, MAKEINTRESOURCE(IDD_DIALOG_TAB01), m_hInst, hTabCntrl);
tie.pszText = L"Second";
m_hTabPane2.CreateThing (&tie, 1, MAKEINTRESOURCE(IDD_DIALOG_TAB02), m_hInst, hTabCntrl);
tie.pszText = L"Third";
m_hTabPane3.CreateThing (&tie, 2, MAKEINTRESOURCE(IDD_DIALOG_TAB03), m_hInst, hTabCntrl);
// set the first tab to be displayed.
NMHDR Nmhdr = {hTabCntrl, 0, TCN_SELCHANGE};
m_hTabPane1.OnWmNotify (&Nmhdr);
return 0;
}
int CDialogTabTest::OnWmNotify (LPNMHDR pNmhdr)
{
// propagate the notification to the various panes in our tab control
// so that they can do what they need to do.
m_hTabPane1.OnWmNotify (pNmhdr);
m_hTabPane2.OnWmNotify (pNmhdr);
m_hTabPane3.OnWmNotify (pNmhdr);
return 0;
}
int CDialogTabTest::DoDataExchange (int iDir)
{
if (iDir) {
CCheckBoxData iVal = {IDC_CHECK1, BST_UNCHECKED, L"DoData: Check Box 1 Set and Not Checked"};
SetValues (iVal, m_hTabPane1.m_hDlg);
iVal.iCntrlId = IDC_CHECK2;
iVal.iCheck = BST_CHECKED;
iVal.prompt = L"DoData: Check Box 2 is Set and Checked.";
SetValues (iVal, m_hTabPane1.m_hDlg);
iVal.iCntrlId = IDC_CHECK4;
iVal.iCheck = BST_CHECKED;
iVal.prompt = L"DoData: Check Box 4 is Set, Checked Tab 3.";
SetValues (iVal, m_hTabPane3.m_hDlg);
} else {
CCheckBoxData iVal = {IDC_CHECK1, BST_UNCHECKED, L""};
GetValues (iVal, m_hTabPane1.m_hDlg);
}
return 0;
}
INT_PTR WINAPI CDialogTabTest::CreateModal (HWND hWnd, HINSTANCE hInst)
{
// this is a modal dialog box so we use the CreateModal() method
// in order to create the dialog box and display it.
return CDialogTest::CreateModal(hWnd, MAKEINTRESOURCE(IDD_DIALOG), hInst);
}
Finally there is the CDialogTabPane class which implements the functionality for individual tab control tab panes.
DialogTabPane.h
#pragma once
#include "stdafx.h"
#include "DialogTest.h"
class CDialogTabPane : public CDialogTest
{
protected:
int m_iTab;
public:
DWORD m_dwLastError;
CDialogTabPane(void);
virtual ~CDialogTabPane(void);
HWND CreateThing (LPTCITEM pTie, int iTab, LPCWSTR lpTemplateName, HINSTANCE hInstance, HWND hWndParent);
// virtual int DoDataExchange (int iDir);
// virtual int OnWmCommandInit ();
virtual int OnWmNotify (LPNMHDR pNmhdr);
};
and DialogTabPane.cpp
#include "StdAfx.h"
#include "DialogTabPane.h"
CDialogTabPane::CDialogTabPane(void)
{
}
CDialogTabPane::~CDialogTabPane(void)
{
}
HWND CDialogTabPane::CreateThing (LPTCITEM pTie, int iTab, LPCWSTR lpTemplateName, HINSTANCE hInstance, HWND hWndParent)
{
// insert the new tab into the tab control with the specified parameters.
TabCtrl_InsertItem(hWndParent, iTab, pTie);
m_iTab = iTab;
// We need to figure out the adjustment of the dialog window position
// within the tab control display area so that when the dialog and its
// controls are displayed for a given tab the tab selection list can
// still be seen above the top of the displayed dialog.
// The tab selection list must be visible so that the user can select
// any of the specified tabs.
RECT tabDisplay = {0};
GetWindowRect (hWndParent, &tabDisplay);
RECT dialogDisplay = tabDisplay;
// NOTE: TabCtrl_AdjustRect() - This message applies only to tab controls that
// are at the top. It does not apply to tab controls that are on the
// sides or bottom.
// But then tab controls on the side or bottom are an abomination.
TabCtrl_AdjustRect (hWndParent, FALSE, &dialogDisplay);
dialogDisplay.left -= tabDisplay.left; dialogDisplay.top -= tabDisplay.top;
m_dwLastError = 0;
// create our dialog and then position it within the tab control properly.
CDialogTest::CreateThing(hWndParent, lpTemplateName, hInstance);
if (!::SetWindowPos (m_hDlg, HWND_TOP, dialogDisplay.left, dialogDisplay.top, 0, 0, SWP_NOSIZE)) {
m_dwLastError = GetLastError ();
}
return m_hDlg;
}
int CDialogTabPane::OnWmNotify (LPNMHDR pNmhdr)
{
int currentSel = TabCtrl_GetCurSel(pNmhdr->hwndFrom);
switch (pNmhdr->code)
{
case TCN_SELCHANGING:
if (currentSel == m_iTab)
::ShowWindow (m_hDlg, SW_HIDE);
break;
case TCN_SELCHANGE:
if (currentSel == m_iTab)
::ShowWindow (m_hDlg, SW_SHOW);
break;
}
return 0;
}
The dialog box resources used for the individual tab control tab panes are similar and look like:
IDD_DIALOG_TAB01 DIALOGEX 0, 0, 186, 115
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "First tab",IDC_STATIC,68,7,96,14
CONTROL "Check1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,21,150,13
CONTROL "Check2",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,36,150,13
CONTROL "Check3",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,53,150,13
CONTROL "Check4",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,69,150,13
CONTROL "Check5",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,84,150,13
END
And the resource for the actual dialog containing the tab control looks like:
IDD_DIALOG_TAB00 DIALOGEX 0, 0, 336, 179
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog Tab Test"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,279,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,279,24,50,14
CONTROL "",IDC_TAB1,"SysTabControl32",0x0,47,35,226,137
END
Displaying dialog box with tab 1 selected and then tab 3 selected.

Related

Win32Api windows move

how i can move my window when middle mouse button pressed?
in case with left mouse button it would be
case WM_LBUTTONDOWN:
{
SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
return 0;
but it does not work with middle button
case WM_MBUTTONDOWN:
{
SendMessage(hwnd, WM_NCMBUTTONDOWN, HTCAPTION, 0);
}
return 0;
but i am not sure about WM_NCMBUTTONDOWN
i`m out of variants, need help please
You have to do this the hard way I'm afraid. I tried all the obvious things and WM_NCHITTEST doesn't cut it if you want to drag the window with anything other than the left mouse button.
Here's some code that works for me (tested on Windows 10). I've excluded error checking for brevity:
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
// WndProc
LRESULT CALLBACK MyWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static int xClick, yClick;
switch (uMsg)
{
case WM_NCMBUTTONDOWN:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
{
SetCapture (hWnd);
POINT pt = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) };
if (uMsg == WM_NCMBUTTONDOWN)
ScreenToClient (hWnd, &pt);
xClick = pt.x;
yClick = pt.y;
return 0;
}
case WM_LBUTTONUP:
case WM_MBUTTONUP:
ReleaseCapture ();
return 0;
case WM_MOUSEMOVE:
{
if (GetCapture() == hWnd)
{
RECT wr;
GetWindowRect (hWnd, &wr);
int xMouse = GET_X_LPARAM (lParam);
int yMouse = GET_Y_LPARAM (lParam);
int xWindow = wr.left + xMouse - xClick;
int yWindow = wr.top + yMouse - yClick;
SetWindowPos (hWnd, NULL ,xWindow, yWindow, 0, 0 , SWP_NOSIZE | SWP_NOZORDER);
}
return 0;
}
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}
// WinMain
int CALLBACK _tWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
HINSTANCE hInstance = NULL;
WNDCLASS wc = { };
wc.lpszClassName = __T ("MyWindowClass");
wc.lpfnWndProc = MyWndProc;
RegisterClass (&wc);
HWND hWnd = CreateWindow (wc.lpszClassName, __T ("My Window"),
WS_CAPTION | WS_BORDER | WS_VISIBLE, 100, 100, 200, 200, NULL, NULL, hInstance, 0);
MSG msg;
while (GetMessage (&msg, NULL, 0, 0))
DispatchMessage (&msg);
return 0;
}
Hope this helps.

Is there a way to get the handle of the entry field in a date time picker (DTP)?

The DATETIMEPICKERINFOstructure obtained by sending the DTM_GETDATETIMEPICKERINFOmessage has a field hwndEdit which might be what I'm looking for. However, I'm getting always NULL for it so I'm wondering what's its actual meaning. If not, is there a way to get the handle of the entry field?
hwndEdit only seems to be valid when the control has the DTS_APPCANPARSE style and you click the date text with the mouse (I tested this with OutputDebugString and a timer). The edit control is created and destroyed dynamically. The hwndUD handle is only valid if DTS_UPDOWN is set and the hwndDropDown is only valid while the dropdown is visible.
It is not called out in the documentation but DTM_GETDATETIMEPICKERINFO is marked Vista+ and this often means the feature is only implemented in ComCtl32 v6 so you also have to make sure you have a manifest that requests this version.
To change the color you can try DTM_SETMCCOLOR but only MCSC_BACKGROUND is documented to work when Visual Styles are active.
I'm afraid there is no way to get what you wanted. I just created a simple Win32 application just to test the possibility. If I use the DTM_GETDATETIMEPICKERINFO, hwndDropDown, hwndEdit and hwndUD give me NULL. If I try to enum child window, well before I do so I check it with Spy++, no luck, there is no child window associated with it.
Finally, I tried GetFocus() and WindowFromPoint(), both give me the HWND of the DateTimePicker itself only.
Here is my testing code:
#pragma comment(lib, "comctl32.lib")
#include <windows.h>
#include <tchar.h>
#include <commctrl.h>
enum MYID {
MYID_FIRST = WM_APP,
MYID_DTP
};
LPCTSTR const g_MyWndClass = _T("DTPTest");
LPCTSTR const g_MyWndTitle = _T("DTPTest");
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void OnWindowCreate(HWND);
void OnTimer(HWND);
int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int nCmdShow)
{
INITCOMMONCONTROLSEX icex{};
icex.dwSize = sizeof(icex);
icex.dwICC = ICC_DATE_CLASSES;
InitCommonControlsEx(&icex);
WNDCLASSEX wcex{};
wcex.cbSize = sizeof(wcex);
wcex.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = g_MyWndClass;
wcex.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wcex);
HWND hwnd = CreateWindowEx(0,
g_MyWndClass, g_MyWndTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 600, 400,
nullptr, nullptr, nullptr, nullptr);
if (!hwnd) { return 99; }
SetTimer(hwnd, 0, 100, nullptr);
ShowWindow(hwnd, nCmdShow);
MSG msg{};
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w, LPARAM l)
{
switch (msg) {
case WM_CREATE:
OnWindowCreate(hwnd);
break;
case WM_TIMER:
OnTimer(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, w, l);
}
return 0;
}
void OnWindowCreate(HWND hwnd)
{
HWND hwndDTP = CreateWindowEx(0, DATETIMEPICK_CLASS, nullptr,
WS_CHILD | WS_VISIBLE | DTS_SHOWNONE,
20, 50, 220, 20,
hwnd, reinterpret_cast<HMENU>(MYID_DTP), nullptr, nullptr);
DATETIMEPICKERINFO info{};
info.cbSize = sizeof(DATETIMEPICKERINFO);
SendMessage(hwndDTP, DTM_GETDATETIMEPICKERINFO, 0,
reinterpret_cast<LPARAM>(&info));
if (!info.hwndDropDown && !info.hwndEdit && !info.hwndUD)
{
MessageBox(hwnd, _T("No luck with DTM_GETDATETIMEPICKERINFO"),
nullptr, MB_ICONERROR);
}
}
void OnTimer(HWND hwnd)
{
POINT pt{};
GetCursorPos(&pt);
HWND hwndPoint = WindowFromPoint(pt);
HWND hwndFocus = GetFocus();
TCHAR buf[99]{};
wsprintf(buf, _T("Pointing at %p, focusing %p"),
hwndPoint, hwndFocus);
SetWindowText(hwnd, buf);
}

How to implement "teamviewer quickconnect"-like button into foreign window?

I'd like to put a button in a foreign windows' title bar, much like Teamviewer does with the Quickconnect feature, or like Chrome has one in the top-right for switching users.
I know this is a repeat of How is Teamviewers Quickconnect button accomplished?
I'm just wondering if it would be possible to get a working example or a link to an open-source program that implements this. The answers given there are rather advanced for me. As in, how am I supposed to "hook" and "intercept" WM_NCPAINT message and so on.
This is the most simple example i can develop:
You need Visual Studio, add 2 project to the solution:
first project (HookDLL) is a dll project, second (Running app) is a win32 console project
in main.cpp (at project Running app) add this:
__declspec(dllimport) void RunHook();
int _tmain(int argc, _TCHAR* argv[])
{
RunHook();
return 0;
}
in dllmain button.cpp (at HookDLL project) add this code:
#include <Windows.h>
#include <stdio.h>
HINSTANCE hinstDLL;
HHOOK hhook_wndproc;
HWND b = NULL;
HBRUSH blue_brush = NULL, yellow_brush, red_brush;
int button_status = 0;
LRESULT CALLBACK DefaultWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch(Msg)
{
case WM_CREATE:
if(!blue_brush)
{
blue_brush = CreateSolidBrush(RGB(0, 0, 255));
yellow_brush = CreateSolidBrush(RGB(255, 255, 0));
red_brush = CreateSolidBrush(RGB(255, 0, 0));
}
break;
case WM_PAINT:
{
HBRUSH b;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
switch(button_status)
{
case 0:
b = blue_brush;
break;
case 1:
b = yellow_brush;
break;
default:
b = red_brush;
}
FillRect(hdc, &ps.rcPaint, b);
EndPaint(hwnd, &ps);
}
return 0;
case WM_MOUSEMOVE:
if(button_status == 0)
{
SetTimer(hwnd, 1, 100, NULL);
button_status = 1;
InvalidateRect(hwnd, NULL, false);
}
return 0;
case WM_TIMER:
{
POINT pt;
GetCursorPos(&pt);
if(button_status == 1 && WindowFromPoint(pt) != hwnd)
{
KillTimer(hwnd, 1);
button_status = 0;
InvalidateRect(hwnd, NULL, false);
}
}
return 0;
case WM_MOUSELEAVE:
button_status = 0;
InvalidateRect(hwnd, NULL, false);
return 0;
case WM_LBUTTONDOWN:
button_status = 2;
InvalidateRect(hwnd, NULL, false);
return 0;
case WM_LBUTTONUP:
if(button_status == 2) MessageBox(GetParent(hwnd), "teamviewer like button clicked", "Message", MB_OK);
button_status = 1;
InvalidateRect(hwnd, NULL, false);
return 0;
}
return DefWindowProc(hwnd, Msg, wParam, lParam);
}
void InitButton(HWND parent, int xPos, int yPos)
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = DefaultWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstDLL;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "DEFAULT_CLASS";
RegisterClass(&wc);
b = CreateWindowEx(WS_EX_TOOLWINDOW, "DEFAULT_CLASS", NULL, WS_BORDER | WS_POPUP | WS_VISIBLE, xPos, yPos, 20, 20, parent, NULL, hinstDLL, NULL);
}
LRESULT WINAPI HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode >= 0 && lParam != 0)
{
CWPRETSTRUCT *msg = (CWPRETSTRUCT*)lParam;
if(!IsWindow(msg->hwnd) || (GetWindowLong(msg->hwnd, GWL_STYLE) & WS_CHILD) != 0) return CallNextHookEx(hhook_wndproc, nCode, wParam, lParam);
switch(msg->message)
{
case WM_SHOWWINDOW:
if(!b && msg->wParam != 0)
{
b = (HWND)1;// see NOTES 5
RECT a;
GetWindowRect(msg->hwnd, &a);
InitButton(msg->hwnd, a.right - 150, a.top);
}
break;
case WM_SIZE:
if(GetParent(b) == msg->hwnd)
{
RECT a;
GetWindowRect(msg->hwnd, &a);
SetWindowPos(b, 0, a.right - 150, a.top, 0, 0, SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}
break;
case WM_SIZING:
case WM_MOVING:
if(GetParent(b) == msg->hwnd)
{
RECT* lprc = (LPRECT) msg->lParam;
SetWindowPos(b, 0, lprc->right - 150, lprc->top, 0, 0, SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}
}
}
return CallNextHookEx(hhook_wndproc, nCode, wParam, lParam);
}
__declspec(dllexport) void RunHook()
{
hhook_wndproc = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallWndProc, hinstDLL, 0);
char aux[10];
gets_s(aux);
UnhookWindowsHookEx(hhook_wndproc);
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hinstDLL = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Now, make dll project depedent of running app project in project->project dependencies:
NOTES:
1) i dont use NC paint code, because not always works, if windows buffer non client region, erases customized NC paint buttons
2) in 64 bits enviroment, you need to run a 32 bits hook for 32 bits apps, and other hook for 64 bits apps
3) YOU CAN NOT DEBUG YOUR HOOK WHEN IS CONNECTED TO ANOTHER PROCCESS, i suggest you debug it with a windows in your app and thread, and test it late in another proccess when is working
4) i use a button like approach for simplicity
5) this line
b = (HWND)1;
I use it for "solve" a multi thread problem, i suggest you make better code (syncronization) this case
HOW THIS WORKS:
run the app
when it start install a hook
open any other app (same 32/64 bits, see NOTE 2)
you must see a blue button at left side of title bar
click it and see a message box
for finish hook: just press ENTER at console window
CODE FLOW:
Running app just calls RunHook() procedure in dll, and dll do the work
RunHook() in dll starts a hook HookCallWndProc (global)
HookCallWndProc captures required message and creates the window button using InitButton() procedure
DefaultWindowProc handles button message

What is the correct designpattern for UI?

I am making a small app for loading data from an external device. It uses a DLL.
I want to make the app running in one window. With the menu it should be possible to bring up the correct state of UI. I dont want to use dialogs or seperate windows.
My idea is to use a state variable and have the WM_PAINT message handle the different content of the windows (createwindowEx for different text and button items i.e.).
Is this the correct way of doing so? I have searched the internet, read Programming Windows and searched stackoverflow and could not find a simple example. It is always using different windows with dedicated winproc functions. It feels like i dont need that...
Can someone help me with a direction or small example/link ?
thx
EDIT:
I enclose the code that i have so far now. Can someone have a look on that, Thx.
#if defined _MSC_VER || defined __BORLANDC__
#define OEMRESOURCE
#endif
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#include <windows.h> //include all the basics
#include <tchar.h> //string and other mapping macros
#include <iostream>
#include <string>
#include "hrmcom.h"
#include "resource.h"
typedef std::basic_string<TCHAR> ustring;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildProc(HWND, UINT, WPARAM, LPARAM);
inline int ErrMsg(const ustring&);
bool CreateChild(HWND);
bool CreateChildScreen(HWND);
ustring classname = TEXT("MAINWND");
ustring childname = TEXT("CHILDWND");
HWND hwndChild[3], hwndCtrl[CTRNUM];
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR pStr, int nCmd)
{
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WndProc;
wcx.hInstance = hInst;
wcx.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));
wcx.hCursor = reinterpret_cast<HCURSOR>(LoadImage(0, IDC_ARROW,
IMAGE_CURSOR, 0, 0, LR_SHARED));
wcx.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1);
wcx.lpszClassName = classname.c_str();
if (!RegisterClassEx(&wcx))
{
ErrMsg(_T("Failed to register wnd class"));
return -1;
}
wcx.lpfnWndProc = ChildProc;
wcx.cbWndExtra = sizeof (long);
wcx.hIcon = NULL;
wcx.lpszClassName = childname.c_str();
if (!RegisterClassEx(&wcx))
{
ErrMsg(_T("Failed to register wnd class"));
return -1;
}
HMENU hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU));
HWND hwnd = CreateWindowEx(0,
classname.c_str(),
TEXT("Polar Loader"),
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
400, 200, 600, 300,
0,
hMenu,
hInst,
0);
if (!hwnd)
{
ErrMsg(TEXT("Failed to create wnd"));
return -1;
}
ShowWindow(hwnd, nCmd);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, 0, 0, 0)>0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
//Create the Childwindows
if (!CreateChild(hwnd))
{
ErrMsg(TEXT("Failed to create Childwindows"));
return -1;
}
//Create controls of the Childwindows
if (!CreateChildScreen(hwnd))
{
ErrMsg(TEXT("Failed to create Conrols of Childwindows"));
return -1;
}
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_Acc:
ShowWindow(hwndChild[0], SW_SHOW);
return 0;
case IDM_Con:
case IDM_Help:
case IDM_Log:
case IDM_Pol:
case IDM_Trans:
ShowWindow(hwndChild[0], SW_HIDE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0); //signal end of application
return 0;
default:
//let system deal with msg
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
LRESULT CALLBACK ChildProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
SetWindowLong(hwnd, 0, 0);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_CTRL+5:
MessageBeep(0);
return 0;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
inline int ErrMsg(const ustring& s)
{
return MessageBox(0, s.c_str(), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
}
bool CreateChild(HWND hwnd)
{
static int x;
for (x = 0; x < 3; x++)
{
hwndChild[x] = CreateWindowEx(0, childname.c_str(), NULL,
WS_CHILDWINDOW,
0, 0, 600, 300,
hwnd, (HMENU)x,
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
NULL);
if (!hwndChild[x]) return FALSE;
}
return TRUE;
}
bool CreateChildScreen(HWND hwnd)
{
LPCWSTR lpType[CTRNUM] = { TEXT("static"), TEXT("edit"), TEXT("edit"), TEXT("static"), TEXT("static"), TEXT("button") };
LPCWSTR lpName[CTRNUM] = { TEXT("Log on to Gedysan Training App:"), TEXT(""), TEXT(""), TEXT("Username:"), TEXT("Password:"), TEXT("Log on") };
DWORD dStyle[CTRNUM] = { WS_CHILD | WS_VISIBLE | ES_LEFT,
WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER | ES_AUTOHSCROLL,
WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER | ES_PASSWORD | ES_AUTOHSCROLL,
WS_CHILD | WS_VISIBLE | ES_LEFT,
WS_CHILD | WS_VISIBLE | ES_LEFT,
WS_CHILD | WS_VISIBLE | ES_LEFT
};
RECT rc[CTRNUM] = { { 15, 10, 400, 25 }, { 100, 40, 150, 25 }, { 100, 70, 150, 25 }, { 15, 45, 70, 25 }, { 15, 75, 70, 25 }, { 15, 110, 70, 25 } };
int iChildNum[CTRNUM] = { 0, 0, 0, 0, 0, 0 };
static int x;
for (x = 0; x < CTRNUM; x++)
{
RECT x1 = rc[x];
hwndCtrl[x] = CreateWindowEx(0, lpType[x], lpName[x], dStyle[x],
x1.left, x1.top, x1.right, x1.bottom,
hwndChild[iChildNum[0]], (HMENU)(ID_CTRL + x),
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), 0);
if (!hwndChild[x]) return FALSE;
}
return TRUE;
}
With your proposed approach you will get a bunch of unrelated stuff all in the WM_PAINT handler, making a messy design. When a menu selection is made you get a message. Run code related to that menu command in that message handler.
If your UI is composed of controls then WM_PAINT is not involved at all: Those controls do their own painting. Your WM_PAINT handler should do any custom painting you need, and nothing else.

Window Edit Control Not Displaying

Here is my code. I'm trying to create an edit control. It's not showing, however. Can some take a look at my code and point out the errors please. I can't figure out where the error is. I feel It might have something to do with the parent child relationship.
#include <cstdlib>
#include <windows.h>
#define MAINWINDOW_CLASS_ID 140;
const char* MAINWINDOW_CLASS_NAME = "Main Window";
const char* TEXTAREA_CLASS_NAME = "EDIT";
using namespace std;
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam);
/*
* Initialize the window class and register it.
*/
BOOL initInstance(HINSTANCE hInstance);
/*
* Create and show the window
*/
HWND initWindow(HINSTANCE hInstance);
HWND createTextArea(HWND hParent);
/*
*
*/
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, LPSTR lpCmdline, INT cmdlShow)
{
if (!initInstance(hInstance))
return 0;
HWND hwndMain = initWindow(hInstance);
ShowWindow(hwndMain, cmdlShow);
MSG msg = {} ;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BOOL initInstance(HINSTANCE hInstance)
{
WNDCLASS wc = {};
wc.lpfnWndProc = WinProc;
wc.hInstance = hInstance,
wc.lpszClassName = MAINWINDOW_CLASS_NAME;
return RegisterClass(&wc);
}
HWND initWindow(HINSTANCE hInstance)
{
HWND hwndMain = CreateWindow(
MAINWINDOW_CLASS_NAME, // The class name
"Text Editor", // The window name
WS_OVERLAPPEDWINDOW,// The window style
CW_USEDEFAULT, // The x pos
CW_USEDEFAULT, // The y pos
CW_USEDEFAULT, // The width
CW_USEDEFAULT, // The height
(HWND) NULL, // Handle to parent
(HMENU) NULL, // Handle to the menu
hInstance, // Handle to the instance
NULL // Window creation data
);
if (!hwndMain) {
return NULL;
}
else {
return hwndMain;
}
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) {
HWND htextArea;
char sztestText[] = "I should be able to see this text.";
switch (uMsg) {
case WM_CREATE:
htextArea = createTextArea(hwnd);
SendMessage(htextArea, WM_SETTEXT, 0, (LPARAM) sztestText);
break;
case WM_PAINT:
break;
case WM_CLOSE:
break;
case WM_SIZE:
RECT rectMainWindow;
GetWindowRect(hwnd, &rectMainWindow);
INT x = rectMainWindow.right - rectMainWindow.left + 50;
INT y = rectMainWindow.bottom - rectMainWindow.top + 50;
MoveWindow(htextArea, 0, 0, x, y, TRUE);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
/*******************************************************************/
HWND createTextArea(HWND hParent) {
return CreateWindow(
TEXTAREA_CLASS_NAME, // Class control name
NULL, // Title
WS_CHILD | WS_VISIBLE | ES_MULTILINE, // Styles
0, 0, 0, 0, // Sizing and position
hParent,
(HMENU) MAKEINTRESOURCE(100),
(HINSTANCE) GetWindowLong(hParent, GWL_HINSTANCE),
NULL
);
}
You've defined htextArea as a local variable in WinProc and so every time your window procedure is called its value will be uninitialized. You should make it static or move it to global data outside the function.
(The actual problem is that when you get a WM_SIZE message, you've lost the handle to the edit control, and so its size remains as 0,0).

Resources