Detect when mouse leaves my app - c++

Hello I am creating an app in win32 that will display the x, y position(In screen coords) of the mouse whereever the mouse is (inside my app client/NC area & outside).
I am at the stage where I want to detect when the mouse leaves my application completely. I have written a simple win32 app that should detect & notify myself when the mouse leaves my app, BUT its not working, I never receive the messages WM_MOUSELEAVE & WM_NCMOUSELEAVE.
What do you think is wrong? Am I using the wrong win32 functions?
// Track Mouse.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include <windows.h>
#include <vector>
#include <string>
#include <cstdlib>
static HINSTANCE gInstance;
// Globals //
enum MouseStatus { DEFAULT = 50001, LEFT_CLIENT, LEFT_NCLIENT };
static MouseStatus mouseState = DEFAULT;
static COLORREF bkCol = RGB(0,255,255);
// Functions List //
BOOL TrackMouse( HWND hwnd )
{
// Post:
TRACKMOUSEEVENT mouseEvt;
ZeroMemory( &mouseEvt, sizeof(TRACKMOUSEEVENT) );
mouseEvt.cbSize = sizeof(TRACKMOUSEEVENT);
mouseEvt.dwFlags = TME_LEAVE | TME_NONCLIENT;
//mouseEvt.dwHoverTime = HOVER_DEFAULT;
mouseEvt.hwndTrack = hwnd;
return TrackMouseEvent( &mouseEvt );
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
// Track mouse so I can be notified when it leaves my application (Client & NC areas)
BOOL trackSuccess = TrackMouse( hwnd ); // Returns successful, so I correctly track the mouse
if ( trackSuccess == 0 )
{
MessageBoxW( hwnd, L"Failed to track mouse", L"Error", MB_OK|MB_ICONEXCLAMATION );
}
else MessageBoxW( hwnd, L"Tracking mouse", L"Success", MB_OK|MB_ICONEXCLAMATION );
}
break;
case WM_MOUSELEAVE:
{
// I never receive this message
// Detect when the mouse leaves the client area
mouseState = LEFT_CLIENT;
bkCol = RGB(50,50,50);
InvalidateRect( hwnd, NULL, true );
}
break;
case WM_NCMOUSELEAVE :
{
// I never receive this message
// If the mouse has left the client area & then leaves the NC area then I know
// that the mouse has left my app
if ( mouseState == LEFT_CLIENT )
{
mouseState = LEFT_NCLIENT;
BOOL trackSuccess = TrackMouse( hwnd );
if ( trackSuccess == 0 )
{
bkCol = RGB(255,255,0);
MessageBoxW( hwnd, L"On WM_NCMOUSELEAVE: Failed to track mouse", L"Error", MB_OK|MB_ICONEXCLAMATION );
}
else MessageBoxW( hwnd, L"On WM_NCMOUSELEAVE: Tracking mouse", L"Success", MB_OK|MB_ICONEXCLAMATION );
InvalidateRect( hwnd, NULL, true );
}
}
break;
case WM_ACTIVATE:
case WM_MOUSEHOVER:
{
// The mouse is back in my app
mouseState = DEFAULT;
bkCol = RGB(0,255,255);
InvalidateRect( hwnd, NULL, true );
}
break;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint( hwnd, &ps );
SetBkColor( hdc, bkCol );
Rectangle( hdc, 10, 10, 200, 200 );
EndPaint( hwnd, &ps );
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE gInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = gInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(DKGRAY_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"Custom Class";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// if registration of main class fails
if(!RegisterClassEx(&wc))
{
MessageBoxW(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"Custom Class",
L"App Name",
WS_CAPTION|WS_MINIMIZEBOX|WS_VISIBLE|WS_OVERLAPPED|WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 600, 500,
NULL, NULL, gInstance, NULL);
if(hwnd == NULL)
{
MessageBoxW(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

The key component your missing is SetCapture(hwnd); which directs all mouse messages to that hwnd until you call ReleaseCapture();
HANDLE_DLGMSG(hwnd, WM_RBUTTONDOWN, SKDemo_OnRButtonDown);
HANDLE_DLGMSG(hwnd, WM_MOUSEMOVE, SKDemo_OnMouseMove);
HANDLE_DLGMSG(hwnd, WM_RBUTTONUP, SKDemo_OnRButtonUp);
void SKDemo_OnRButtonDown (HWND hwnd, BOOL fDbClk, int x, int y, UINT keyFlags)
{
// Force all mouse messages to come to this window.
SetCapture(hwnd);
// Change the mouse cursor to eyes. This provides a visual indication
// to the user that Voyeur is "peering."
SetCursor(LoadCursor(GetWindowInstance(hwnd),
MAKEINTRESOURCE(IDC_POINTER)));
}
void SKDemo_OnMouseMove (HWND hwnd, short x, short y, UINT keyFlags)
{
if( GetCapture() == NULL ) {
return;
}
// do something with the message here
}
void SKDemo_OnRButtonUp (HWND hwnd, int x, int y, UINT keyFlags)
{
ReleaseCapture();
}

I think you need the mouse to be over your window before you all TrackMouseEvent. Try calling whilst you handle a mouse move message.

As written in Win32 documentation, the request expires each time the mouse leaves the window. So you need to call TrackMouseEvent also in your WM_MOUSELEAVE handler. Note also that if the mouse isn't in your window at the time TrackMouseEvent is called, WM_MOUSELEAVE is generated immediately.

The win32 API is more or less ridiculous. It doesn't have a mouse enter/leave. A google search for "MFC mouse enter leave" turned up this:
http://www.codeproject.com/KB/cpp/mouseenterleave.aspx
Note that MFC is just a thin wrapper around win32 proper. You can basically take any member function of a WND and call a C function with the exact same name and HWND as first parameter...the rest being all exactly the same.
Have fun. This kind of crap is why I hate all things win32.

Related

How do I show controls on top of a gradient background with pure WINAPI?

In my program I am trying to create a child window (via CreateWindow("STATIC", ...)) to contain some other controls such as edit boxes and buttons. However, I want the background for this static control to be a gradient.
My goal is to have something that looks like this as a child window:
My efforts so far have yielded the window being created with controls visible but as soon as it is redrawn with WM_ERASEBKGND, the controls are hidden behind the drawn gradient.
I can find plenty of examples on drawing a gradient (or other such graphic backgrounds) and also, independently, creating a window with controls. But I have yet to find any resource of having both at the same time.
Here is my example code:
#include <windows.h>
#pragma comment( lib, "Msimg32" ) // load that dll for GradientFill
// Global macros
inline COLOR16 ToColor16(BYTE byte) { return byte << 8; }
inline COLOR16 RVal16(COLORREF color) { return ToColor16(GetRValue(color)); }
inline COLOR16 GVal16(COLORREF color) { return ToColor16(GetGValue(color)); }
inline COLOR16 BVal16(COLORREF color) { return ToColor16(GetBValue(color)); }
// Global variables
HINSTANCE hInst;
// Forward declarations
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// Entry point
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const TCHAR CLASS_NAME[] = "mcvewinapi";
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
"MCVE WINAPI", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
300, //horizontal position
50, //vertical position
700, //width
500, //height
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
hInst = hInstance;
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// vill geven area with vertical gradient
void VerticalGradient(HDC hDC, const RECT &RectToFill, COLORREF rgbTop, COLORREF rgbBottom) {
GRADIENT_RECT gradRect;
TRIVERTEX TriVert[2];
// references for the verticies
gradRect.UpperLeft = 0; // point to TriVert[0]
gradRect.LowerRight = 1; // point to TriVert[1]
//setup top of gradient attributes
TriVert[0].x = RectToFill.left - 1;
TriVert[0].y = RectToFill.top - 1;
TriVert[0].Red = RVal16(rgbTop);
TriVert[0].Green = GVal16(rgbTop);
TriVert[0].Blue = BVal16(rgbTop);
TriVert[0].Alpha = 0x0000;
//setup bottom of gradient attributes
TriVert[1].x = RectToFill.right;
TriVert[1].y = RectToFill.bottom;
TriVert[1].Red = RVal16(rgbBottom);
TriVert[1].Green = GVal16(rgbBottom);
TriVert[1].Blue = BVal16(rgbBottom);
TriVert[1].Alpha = 0x0000;
// draw the shaded rectangle
GradientFill(hDC, TriVert, 2, &gradRect, 1, GRADIENT_FILL_RECT_V);
}
// discover area to fill with gradient
void vFill(HWND ctrlhwnd) {
HDC gBoxDC;
HWND gBoxH;
RECT gBoxR;
POINT xWhere;
// get rectangle from control
gBoxH = ctrlhwnd;
GetWindowRect(gBoxH, &gBoxR);
// get DC for control
gBoxDC = GetDC(gBoxH);
// load up RECT from POINT
xWhere = { gBoxR.left, gBoxR.top };
ScreenToClient(gBoxH, &xWhere);
gBoxR.left = xWhere.x + 2;
gBoxR.top = xWhere.y + 2;
// load up RECT from POINT
xWhere = { gBoxR.right, gBoxR.bottom };
ScreenToClient(gBoxH, &xWhere);
gBoxR.right = xWhere.x - 1;
gBoxR.bottom = xWhere.y - 1;
//paint area
VerticalGradient(gBoxDC, gBoxR, RGB(250, 191, 145), RGB(191, 191, 191));
ReleaseDC(gBoxH, gBoxDC);
}
// Processes messages for the main window.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CREATE:
struct wAnchor {
int udPos;
int lrPos;
int width;
int height;
};
wAnchor Section1[4], TextLine;
unsigned int LineHeight, k;
HWND FillBox;
LineHeight = 24;
Section1[1].lrPos = 5;
Section1[1].udPos = 20;
Section1[1].width = 325;
Section1[1].height = 360;
TextLine.lrPos = Section1[1].lrPos + 5;
TextLine.udPos = Section1[1].udPos + 5;
TextLine.width = 0;
TextLine.height = LineHeight;
k = 1;
FillBox = CreateWindow("STATIC",
"",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_EX_CLIENTEDGE,
Section1[1].lrPos,
Section1[1].udPos,
Section1[1].width,
Section1[1].height,
hWnd, // child of parent
(HMENU)8200,
hInst,
NULL);
CreateWindow("STATIC",
"Section title",
WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER | WS_EX_CLIENTEDGE,
TextLine.lrPos,
TextLine.udPos + (TextLine.height * k++),
TextLine.width + 315,
TextLine.height,
FillBox, // child of FillBox
(HMENU)8201,
hInst,
NULL);
CreateWindow("STATIC",
"Entry:",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_EX_CLIENTEDGE,
TextLine.lrPos,
TextLine.udPos + (TextLine.height * k),
TextLine.width + 75,
TextLine.height,
FillBox, // child of FillBox
(HMENU)8202,
hInst,
NULL);
CreateWindow("EDIT", // edit bos
"109",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP | ES_MULTILINE,
TextLine.lrPos + 75,
TextLine.udPos + (TextLine.height * k),
TextLine.width + 35,
TextLine.height,
FillBox, // child of FillBox
(HMENU)8203,
hInst,
NULL);
CreateWindow(
"BUTTON", // Predefined class; Unicode assumed
"test", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
50, // x position
150, // y position
50, // Button width
30, // Button height
FillBox, // child of FillBox
(HMENU)8204, // No menu
hInst,
NULL); // Pointer not needed
UpdateWindow(FillBox);
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_ERASEBKGND:
vFill(GetDlgItem(hWnd, 8200)); //fill background with gradient
return 1L;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Initially, no gradient is drawn until I resize the window, then the gradient covers the controls. Of course, I would like the gradient to be redrawn as needed, but the controls to remain visible.
How do I accomplish this?
You can add the WS_CLIPCHILDREN style to the parent window:
FillBox = CreateWindow(TEXT("STATIC"),
TEXT(""),
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_EX_CLIENTEDGE | WS_CLIPCHILDREN,
Section1[1].lrPos,
Section1[1].udPos,
Section1[1].width,
Section1[1].height,
hWnd, // child of parent
(HMENU)8200,
hInst,
NULL);
This will not include its child windows when drawing the parent window, which works for me:
If you're going to create a window to act as a container for some controls, the obvious choice is usually to create a dialog. It already (automatically) handles most of what you're doing right now, and a few things you might want to (like using the tab to move between controls) but haven't yet.
So, for example, starting from a generic Windows app, I changed the default About box to host roughly the controls you wanted, then popped it up as a modeless dialog when the application initialized.
// frame.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include "frame.h"
#pragma comment( lib, "Msimg32" ) // load that dll for GradientFill
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_FRAME, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_FRAME));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_FRAME));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_FRAME);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND dialog;
switch (message)
{
case WM_CREATE:
dialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
ShowWindow(dialog, SW_SHOW);
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
inline COLOR16 ToColor16(BYTE byte) { return byte << 8; }
inline COLOR16 RVal16(COLORREF color) { return ToColor16(GetRValue(color)); }
inline COLOR16 GVal16(COLORREF color) { return ToColor16(GetGValue(color)); }
inline COLOR16 BVal16(COLORREF color) { return ToColor16(GetBValue(color)); }
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_ERASEBKGND: {
COLORREF rgbTop(RGB(250, 191, 145));
COLORREF rgbBottom(RGB(191, 191, 191));
RECT RectToFill;
GetClientRect(hDlg, &RectToFill);
GRADIENT_RECT gradRect;
TRIVERTEX TriVert[2];
// references for the verticies
gradRect.UpperLeft = 0; // point to TriVert[0]
gradRect.LowerRight = 1; // point to TriVert[1]
//setup top of gradient attributes
TriVert[0].x = RectToFill.left - 1;
TriVert[0].y = RectToFill.top - 1;
TriVert[0].Red = RVal16(rgbTop);
TriVert[0].Green = GVal16(rgbTop);
TriVert[0].Blue = BVal16(rgbTop);
TriVert[0].Alpha = 0x0000;
//setup bottom of gradient attributes
TriVert[1].x = RectToFill.right;
TriVert[1].y = RectToFill.bottom;
TriVert[1].Red = RVal16(rgbBottom);
TriVert[1].Green = GVal16(rgbBottom);
TriVert[1].Blue = BVal16(rgbBottom);
TriVert[1].Alpha = 0x0000;
HDC dc = GetDC(hDlg);
GradientFill(dc, TriVert, 2, &gradRect, 1, GRADIENT_FILL_RECT_V);
ReleaseDC(hDlg, dc);
return TRUE;
}
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
I didn't really complete the transformation from it being a modal dialog to modeless (e.g., a modeless dialog usually won't have an OK button, or code to handle its being pressed, but it's still enough to get the idea of how it can look:

Why is this call to CreateWindow failing, and how can I fix it?

I'm following a tutorial for directx12 and can't even get over the creation of window D: There is an implemented error window which tells me that there was an error when creating the window i actually want to create.
It's supposed to mean that it was "unsuccessful in getting a window handle"...
I don't have anything as much as a clue of what that would mean but i would GREATLY appreciate some help about that.
#include "stdafx.h"
//Handle to the window
HWND hwnd = NULL;
//Name of the window
LPCTSTR WindowName = L"GameEngineApp";
//Title of the window
LPCTSTR WindowTitle = L"My Game Engine";
//Width and height of the window
int Width = 800;
int Height = 600;
//Toggle for fool screen
bool FullScreen = false;
//Toggle for window creation
bool InitializeWindow(HINSTANCE hInstance,
int ShowWnd, int width, int height, bool fullscreen);
//Main application loop
void mainLoop()
{
//The message var hold any windows message received through the
//PeekMessage function
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
//If there is a message, it is translated
//then dispatched so Windows
//knows the program hasn't stopped working
if (msg.message = WM_QUIT) {
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
//If there is no message the game
//code will run and the loop will continue
}
}
}
}
//Callback function for windows messages
LRESULT CALLBACK WndProc(HWND hWnd,
UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
if (wParam == VK_ESCAPE) {
if (MessageBox(0, L"Are you sure you want to exit?",
L"Really?", MB_YESNO | MB_ICONQUESTION) == IDYES)
DestroyWindow(hwnd);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,
msg, wParam, lParam);
}
//Main Windows function
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
//Toggle window creation
if (!InitializeWindow(hInstance, nShowCmd, Width, Height, FullScreen))
{
MessageBox(0, L"Window Initialization - Failed",
L"Error", MB_OK);
return 0;
}
mainLoop(); //Call main loop to start
return 0;
}
bool InitializeWindow(HINSTANCE hInstance,
int ShowWnd, int width, int height, bool fullscreen)
{
//Check if fullscreen is needed and set to fullscreen if so
if (fullscreen)
{
HMONITOR hmon = MonitorFromWindow(hwnd,
MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(hmon, &mi);
width = mi.rcMonitor.right - mi.rcMonitor.left;
height = mi.rcMonitor.bottom - mi.rcMonitor.top;
}
//Window class structure
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = NULL;
wc.cbWndExtra = NULL;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
wc.lpszMenuName = NULL;
wc.lpszClassName = WindowName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
//Registering the window class
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Error registering class",
L"Error", MB_OK | MB_ICONERROR);
return false;
}
//Create the window with the now registered window class
hwnd = CreateWindowEx(NULL,
WindowName,
WindowTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
NULL,
NULL,
hInstance,
NULL);
//Return error msg if unsuccessful in getting a window handle
if (!hwnd)
{
MessageBox(NULL, L"Error creating window",
L"Error", MB_OK | MB_ICONERROR);
return false;
}
//Removing the style from the window when fullscreen
if (fullscreen)
{
SetWindowLong(hwnd, GWL_STYLE, 0);
}
//Showing and updating the window
ShowWindow(hwnd, ShowWnd);
UpdateWindow(hwnd);
return true;
}
I've tried to change CreateWIndowEx to CreateWindowA and that's really the only thing that seemed to possibly have an effect but i did not see any results.
I've tried printing the error but there is no error.
Creating a window in Windows with the C++ code so i can make a game engine.
Though shalt not abuse global variables.
You're calling DefWndProc in your WndProc with hwnd as the handle argument. But that isn't set until the return of CreateWindowEx, and there are plenty very important messages that are rifled through WndProc during window stand-up. Those messages need the window handle, and you're not passing it along. Instead you're just passing NULL (the startup value of hwnd).
Change all hwnd to hWnd (the parameter name) in your WndProc
The remainder of the problems mentioned in comments I leave for you to address.

Unable to add thumbnail buttons to a window?

I'm trying to add thumbnail buttons to a window, but there is no error and no thumbnail button is shown. I read the following pages for reference:
Your First Windows Program;
ITaskbarList3::ThumbBarAddButtons method;
some code on github.
Environment: win10 64bit, vs2015
// function WindowProc and wWinMain are copied from msdn directly.
#include "stdafx.h"
#include <windows.h>
#include "shobjidl.h"
#include <exception>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT addThumbnailButtons(HWND hwnd) {
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr)) {
ITaskbarList4* ptbl = nullptr;
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&ptbl));
if (SUCCEEDED(hr)) {
// create 2 buttons
THUMBBUTTON thmb[2] = {};
thmb[0].dwMask = THB_TOOLTIP;
thmb[0].iId = 0;
wcscpy_s(thmb[0].szTip, L"Button 1");
thmb[1].dwMask = THB_TOOLTIP;
thmb[1].iId = 1;
wcscpy_s(thmb[1].szTip, L"Button 2");
//ptbl->HrInit();
hr = ptbl->ThumbBarAddButtons(hwnd, ARRAYSIZE(thmb), thmb);
ptbl->Release();
return hr;
}
else {
throw std::exception("createInstance failed");
}
}else{
throw std::exception("coinitialize failed");
}
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
HRESULT hr = addThumbnailButtons(hwnd);
if (FAILED(hr)) {
throw std::exception("addbuttons failed");
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Per the ITaskBarList3 documentation:
When an application displays a window, its taskbar button is created by the system. When the button is in place, the taskbar sends a TaskbarButtonCreated message to the window. Your application should call RegisterWindowMessage(L"TaskbarButtonCreated") and handle that message in its wndproc. That message must be received by your application before it calls any ITaskbarList3 method.
You must wait for that message before calling addThumbnailButtons(), eg:
UINT uMsgTaskbarCreated;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
uMsgTaskbarCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
return 0;
}
default:
if ((uMsg == uMsgTaskbarCreated) && (uMsgTaskbarCreated != 0))
{
HRESULT hr = addThumbnailButtons(hwnd);
if (FAILED(hr)) {
...;
}
}
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Awesomium WebView doesn't display page

I've made two simple classes to use for displaying UIs with Awesomium. However creating the Awesomium WebView and setting the parent window to my Win32 window causes the program to hang and the page is never displayed. The classes are simple and creating a window is simple so there isn't much I can think of that could be going wrong. Perhaps there is something else required than what I've done to display a WebView?
To clarify: Creating the Win32 window without creating the WebView works fine, the window functions including the drag code etc... The hang only happens when you call set_parent_window.
UI.h
#pragma once
#include <Windows.h>
#include <windowsx.h>
#include <Awesomium/WebCore.h>
#include <Awesomium/STLHelpers.h>
using namespace Awesomium;
LRESULT CALLBACK LoginUICallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
class UI
{
public:
//Window Variables
HINSTANCE instance;
HWND window;
BOOL drag_window = false;
SHORT mouse_x, mouse_y, mouse_x_prev, mouse_y_prev;
//Awesomium Variables
WebCore* webcore = 0;
WebView* webview;
static HWND InitWindow(INT width, INT height, WNDPROC callback)
{
HWND hwnd;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = callback;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(0);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MyUI";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
char msg[100];
sprintf(msg, "System Error: %i", GetLastError());
MessageBox(NULL, msg, "ERROR", MB_OK);
return NULL;
}
hwnd = CreateWindow("MyUI",
"",
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
NULL,
NULL,
GetModuleHandle(0),
NULL);
if (!hwnd)
{
char msg[100];
sprintf(msg, "System Error: %i", GetLastError());
MessageBox(NULL, msg, "ERROR", MB_OK);
return NULL;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
SetTimer(hwnd, 0, 15, NULL);
return hwnd;
}
};
class LoginUI : public UI
{
public:
INT width = 600;
INT height = 600;
INT RunUI()
{
this->window = UI::InitWindow(this->width, this->height, ::LoginUICallback);
if (!this->window)
return 0;
WebConfig config;
this->webcore = WebCore::Initialize(config);
this->webview = this->webcore->instance()->CreateWebView(this->width, this->height, 0, kWebViewType_Window);
this->webview->set_parent_window(this->window);
this->webview->LoadURL(WebURL(WSLit("http://www.google.com")));
MSG msg;
while(GetMessage(&msg, this->window, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
WebCore::Shutdown();
return 1;
}
}login_ui;
LRESULT CALLBACK LoginUICallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_TIMER:
break;
case WM_MOUSEMOVE:
{
if (login_ui.drag_window && (wParam & MK_LBUTTON))
{
// code executed when the dialog window is moved around on the screen
RECT win_rect;
GetWindowRect(hWnd, &win_rect);
int x_coord = GET_X_LPARAM(lParam);
int y_coord = GET_Y_LPARAM(lParam);
MoveWindow(hWnd,
win_rect.left + x_coord - login_ui.mouse_x_prev,
win_rect.top + y_coord - login_ui.mouse_y_prev,
win_rect.right - win_rect.left,
win_rect.bottom - win_rect.top,
false
);
}
break;
}
case WM_LBUTTONDOWN:
{
login_ui.mouse_x = GET_X_LPARAM(lParam);
login_ui.mouse_y = GET_Y_LPARAM(lParam);
if (login_ui.mouse_y < 41)
{
login_ui.mouse_x_prev = login_ui.mouse_x;
login_ui.mouse_y_prev = login_ui.mouse_y;
SetCapture(hWnd);
login_ui.drag_window = true;
}
break;
}
case WM_LBUTTONUP:
{
if (login_ui.drag_window)
{
login_ui.drag_window = false;
ReleaseCapture();
}
break;
}
case WM_SIZE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_QUIT:
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Main.Cpp
#include "UI.h"
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, char*, int nCmdShow)
{
login_ui.RunUI();
}
Have not used Awesomium but your GetMessage only pumps messages for the WebCore window. So instead you should pass NULL so your message pump dispatches messages for all windows created on that thread.

Adding child window to Metatrader4's chart via DLL - blinking (not redrawing)

I would like to add a child window to Metatrader4's chart window which always stays on top, without blinking, just statically there all the time upon eveything (in parent window). I am doing this from a DLL (C++).
I call this method from the mql side:
MT4_EXPFUNC int __stdcall testWindow(HWND hwnd) {
prnt_hWnd = hwnd;
CreateThread(0, NULL, ThreadProc, (LPVOID)L"Window Title", NULL, NULL);
return 0;
}
The parent window's (chart) handle is given as a parameter.
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
MSG messages;
/*
... in createWindowClass:
WNDCLASSEX wc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = (LPCWSTR)L"MyClass";
wc.lpszClassName = (LPCWSTR)szClassName;
wc.lpfnWndProc = DLLWindowProc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
...
*/
CreateWindowClass(L"MyClass");
HWND hwnd = CreateWindowEx (0, L"MyClass", NULL, WS_VISIBLE | WS_CHILD , CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, prnt_hWnd, NULL, GetModuleHandle(NULL), NULL );
ShowWindow (hwnd, SW_SHOWNORMAL);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return 1;
}
I handle window's messages this way:
LRESULT CALLBACK DLLWindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint( hwnd, &ps );
EndPaint( hwnd, &ps );
return 0;
}
case WM_COMMAND:
/* */
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
My child window at the begining appears, then after (I guess) the parent window is getting being redrawn, suddenly it disappears, then it is just blinking (fastly appears-disappear).
My goal is to have a child window on that chart statically, so always topmost, without blinking. I could achieve this only without the WS_CHILD property. But then my child window is not ON the parent.
Try adding the WS_CLIPCHILDREN style to the chart window. I would pass the handle on the MQL4 side in init() via some MT4 export function. For example, SetChartWnd( HWND hChartWnd ) and passing WindowHandle( Symbol(), Period() ) as the parameter.
Then inside that function, I would try doing something like the following:
if ( ::IsWindow( hChartWnd ) ) {
DWORD style = GetWindowLong( hChartWnd, GWL_STYLE );
style |= WS_CLIPCHILDREN;
SetWindowLong( hChartWnd, GWL_STYLE, style );
}
}