I am writing a quite simple WinAPI application. Just a window with single button in client area (this is minimum reproducible example). Button creation code is in WM_CREATE main window message handler:
case WM_CREATE:
hInst = ((LPCREATESTRUCT)lParam)->hInstance;
hwndButton = CreateWindowW(L"BUTTON", L"Start", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
3, 30, 60, 30, hwnd, NULL, hInst, NULL);
break;
In real application I have to update window content when user moves mouse over window and when user resizes window.
All update here is just filling client area with single color:
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW + 10));
EndPaint(hwnd, &ps);
return 0
WM_size and WM_MOUSEMOVE message handlers just invalidate all client area:
case WM_SIZE:
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_MOUSEMOVE:
InvalidateRect(hwnd, NULL, TRUE);
break;
The problem is, behaviour of application differs in case of resizing window and in case of moving mouse pointer over it. In the first case, nothing happens except of window resizing - just as I want.
But in second case, when mouse pointer moves over window, window begins to flicker. It's annoying. Moreover, button in client area also disappears - and appears again only after mouse pointer stops. This is absolutely unacceptable.
What can I do to fix this situation?
Full text of program, if it will be useful:
#include <tchar.h>
#include <windows.h>
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
HINSTANCE hInst;
/* Make the class name into a global variable */
WCHAR szClassName[ ] = L"WindowsApp";
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/*Application entry point. Function made from template. */
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd, hWndToolbar; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEXW wincl; /* Data structure for the windowclass */
hInst = hThisInstance;
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = NULL;
wincl.hIconSm = wincl.hIcon; //LoadIcon(NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassExW (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowExW (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
L"Check button", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
CW_USEDEFAULT, /* The programs width */
CW_USEDEFAULT, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* Class menu used */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* Message handler: */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndButton;
PAINTSTRUCT ps;
HDC hdc;
switch (message) /* handle the messages */
{
case WM_CREATE:
hInst = ((LPCREATESTRUCT)lParam)->hInstance;
hwndButton = CreateWindowW(L"BUTTON", L"Start", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
3, 30, 60, 30, hwnd, NULL, hInst, NULL);
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW + 10));
EndPaint(hwnd, &ps);
return 0;
case WM_SIZE:
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_MOUSEMOVE:
InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
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.
I am an absolute beginner. This is my first C++ code. Taking from the default project in Dev C++, youtube tutorials, and some intuition, I came up with the simple code below. I know the answer is going to be easy. I just can't seem to paste together answers from other posts the fix for mine. Any help you provide is GREATLY appreciated!!!
I get "undefined reference to CreateProcessWithLogonW" error.
#include <windows.h>
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
HWND textfield;
/* Make the class name into a global variable */
char szClassName[ ] = "WindowsApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default color as the background of the window */
wincl.hbrBackground = GetSysColorBrush (COLOR_3DFACE);
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Files open on Mars",/* Title Text */
WS_SYSMENU, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
444, /* The programs width */
175, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nFunsterStil);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
CreateWindow(TEXT("button"), TEXT("Open files"),
WS_VISIBLE | WS_CHILD,
10,10,80,25,
hwnd, (HMENU) 1, NULL, NULL
);
textfield = CreateWindow("STATIC",
"Please click the button to retrieve a list of open files on server",
WS_VISIBLE | WS_CHILD,
10,50,400,25, hwnd, NULL, NULL, NULL);
textfield = CreateWindow("STATIC",
"Message at bottom of box",
WS_VISIBLE | WS_CHILD,
10,120,400,25, hwnd, NULL, NULL, NULL);
break;
case WM_COMMAND:
if (LOWORD(wParam) == 1) {
CreateProcessWithLogonW(L"me", L"company", L"xxxxxx", 0, 0, L"c:\\files.cmd", 0, NULL, NULL, NULL, NULL);
MessageBox(hwnd, "A text file with all of the open files has been placed on your desktop", "Open Files", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
According to the documentation, CreateProcessWithLogonW is defined in Advapi32.lib. You need to pass that library to the linker.
I have put a procedure for capturing screenshots into memoryDC in a Winapi timer.
I can successfully blit the said image to the window, but how would i do this repeatedly, lets say every 1-2 seconds?
The currenct code i have can blit it 1-2 seconds at a time, but it wont blit it to the Window correctly (the image is misplaced).
How shall i go about doing this?
#include <windows.h>
#include <iostream>
#include <windowsx.h>
#define TIMERID 3232
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
RECT rectangle{
50,
50,
690,
409
};
/* Make the class name into a global variable */
char szClassName[ ] = "CodeBlocksWindowsApp";
HDC handle_WindowDC;
HDC handle_MemoryDC;
HDC handle_ScreenDC;
//BITMAP bitmap;
HBITMAP handle_Bitmap;
int x, y;
HWND hand;
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Code::Blocks Template Windows App", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
1600, /* The programs width */
900, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
SetTimer(hwnd, TIMERID, 1000, (TIMERPROC)NULL);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:{
}
//hand = CreateWindowEx(NULL, "STATIC", "", SS_BITMAP|WS_VISIBLE, 500,300, 640 ,360 , hwnd, HMENU(IDCSTATIC_BITMAP), GetModuleHandle(NULL), NULL); }
break;
case WM_TIMER:
switch(LOWORD(wParam)){
case TIMERID:{
//MessageBox(NULL,NULL,NULL,NULL);
handle_ScreenDC = GetDC(NULL);
handle_MemoryDC = CreateCompatibleDC(handle_ScreenDC);
x = GetDeviceCaps(handle_ScreenDC, HORZRES);
y = GetDeviceCaps(handle_ScreenDC, VERTRES);
handle_Bitmap = CreateCompatibleBitmap(handle_ScreenDC, 640, 360);
SelectObject(handle_MemoryDC, handle_Bitmap);
StretchBlt(handle_MemoryDC, 0, 0, 640, 360, handle_ScreenDC, 0, 0, x, y, SRCCOPY);
UpdateWindow(hwnd);
BitBlt(handle_WindowDC, 50, 50, x, y, handle_MemoryDC, 0, 0, SRCCOPY);
}
break;
}break;
case WM_PAINT:{
PAINTSTRUCT paintstruct;
handle_WindowDC = BeginPaint(hwnd, &paintstruct);
//BitBlt(handle_WindowDC, 50, 50, x, y, handle_MemoryDC, 0, 0, SRCCOPY);
EndPaint(hwnd, &paintstruct);
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
case WM_LBUTTONDOWN:{
std::cout <<"\nx: " << GET_X_LPARAM(lParam) << "\ny: " << GET_Y_LPARAM(lParam);
tagPOINT point;
point.x = GET_X_LPARAM(lParam);
point.y = GET_Y_LPARAM(lParam);
if( PtInRect(&rectangle, point)){
int x, y;
x = 2.5*(point.x - 50);
y = 2.5*(point.y - 50);
//I juse use setcursorpos for now, but when connecting to server.exe i will do a send() and send x,y coordinates along with
//a click or rightclick, or whatever.
SetCursorPos(x, y);
}
}
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
You are using the DC from WM_PAINT to paint in the WM_TIMER code, that DC would have been released during EndPaint() -- the MSDN Docs says "EndPaint releases the display device context that BeginPaint retrieved'.
Also make sure you release your DCs with ReleaseDC(handle_ScreenDC) and DeleteObject(handle_MemoryDC).
The code for WM_TIMER should just invalidate the rectangle, do all The painting during WM_PAINT.
See this article for sample code.