I have created a standard win32 windows application in Visual Studio 2010. The only addition I have made is a TextOut call in the WM_PAINT handler that displays the alphabet (repeated 4 times for width) at position 0, 0.
My problem is that when I resize the window, expanding to the right, there is some drawing error by the right side border. Black blocks are shown during the resizing/drawing process as if the right hand edge is being stretched. The result is a strange black “smearing” effect as I resize. It only happens during the resize; once I release the mouse, the window looks correct.
I have tried double buffering to a memory DC, but see the same effect. I am not using any windows themes code.
The only way I can remove the effect is to handle WM_NCPAINT (and return 0) – but, of course, this means the border isn’t painted which won’t be an acceptable solution! I mention it in case it helps anybody with an idea.
Thanks for any ideas or help!
#Arx – Sorry, I hadn’t made myself clear. When I say the borders smear, I meant the right hand edge of the displayed text, not the border itself.
It happens if I just add the TextOut call in the WM_PAINT handler. Handling WM_ERASEBKGRND and setting the window class background brush makes no difference.
#David – Apologies. I see the effect after adding only one line to the standard VS 2008 Win32 application created by the new project wizard – so I didn’t see the point in posting 200+ lines of code with only one line of interest :)
I added this line to the WM_PAINT handler:
TextOut (hdc, 0, 0, L"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ", 104);
Here is the full version of the code with double buffering added. The smearing of the text on the right hand side (by the window edge) as the window is expanded still occurs.
// win32_smearing_at_border.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "win32_smearing_at_border.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR 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 _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32_SMEARING_AT_BORDER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32_SMEARING_AT_BORDER));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX 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_WIN32_SMEARING_AT_BORDER));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = 0; //(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32_SMEARING_AT_BORDER);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&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)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
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)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static HDC memory_dc;
static HBITMAP memory_bmp;
static HBITMAP oldbmp;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_ERASEBKGND:
return 1;
case WM_CREATE:
// Create memory DC
{
HDC dc = GetDC (hWnd);
memory_dc = CreateCompatibleDC (dc);
memory_bmp = CreateCompatibleBitmap (dc, 2560, 1440); // arbitary values for testing, set to my current monitor size.
oldbmp = (HBITMAP)SelectObject(memory_dc, memory_bmp);
TextOut (memory_dc, 0, 0, L"ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ",104);
ReleaseDC (hWnd, dc);
}
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right-ps.rcPaint.left, ps.rcPaint.bottom-ps.rcPaint.top, memory_dc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
// Clean up memory DC
SelectObject (memory_dc,oldbmp);
DeleteObject (memory_bmp);
DeleteDC (memory_dc);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// 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_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Hi Arx
Many thanks for trying out the code – I appreciate it. Good to know it’s working for you.
But … I am experiencing some very strange results. I have the “blurring” issue when running on a Windows 7 x64 machine. However, trying it out in a Windows 7 virtual machine (using VMWare on the SAME machine), it works perfectly.
So on the same machine, natively it blurs, but virtually it doesn’t. I even tried a Windows 8 virtual machine, and again it worked fine.
What I have found is that if I select a NON-Aero theme, all works ok (although it’s doesn’t look so good without Aero). And yet on the other machines where it IS working, they DO have Aero themes selected. I really don’t get it.
So that’s not really a solution. I don’t want to have to ask my potential customers to turn Aero off.
I have tried calls to many of the Dwm* functions trying to find a difference between the working and non-working machines but cannot find anything.
If I insert this code:
DWMNCRENDERINGPOLICY policy = DWMNCRP_DISABLED;
DwmSetWindowAttribute(hWnd,
DWMWA_NCRENDERING_POLICY,
(void*)&policy,
sizeof(DWMNCRENDERINGPOLICY));
Just after creating the main window then all works fine again (although, once again, doesn’t look as good without the Aero border).
So am I really at a loss as to how I can move forward. Any ideas gratefully received!
I think I can provide some more insight about where that smearing/blurring is coming from and why you see it more (or differently) in Windows 8/10 Aero.
The fact that your code has:
wcex.style = CS_HREDRAW | CS_VREDRAW;
is the reason why you didn't see the smearing/blurring on Win7. This causes Windows to fill in newly exposed areas of the window that have not yet been drawn by your WM_PAINT with a solid color, which is not perfect but not that distracting.
But under Windows 8/10 Aero, things are different. Apps don't draw directly to the screen, but rather draw to offscreen buffers that are then composited by the evil DWM.exe window manager. It turns out that DWM actually adds another layer of BitBlt-type behavior on top of the existing legacy XP/Vista/7 BitBlt behavior that is affected by CS_HREDRAW | CS_VREDRAW.
And the DWM blit behavior is even more crazy because they don't just copy the client area, but they actually replicate pixels at the edges of your old client area to make the new one.
Unfortunately, making DWM not do its blit is much harder than just passing some extra flags.
I don't have a 100% solution, but please see this Q&A for a sort of timing trick that can be used to greatly reduce the frequency with which DWM messes with your window client area, which will reduce the smearing/blurring:
How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?
Enjoy!
Related
How can I change the code that VS automatically generates for a Win32 Project? Instead of this:
// testproj.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "testproj.h"
#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_TESTPROJ, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTPROJ));
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_TESTPROJ));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_TESTPROJ);
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)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
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;
}
// 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_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
I want it to auto generate some other code. How could I do this?
Edit: Also, how do I get VS to not generate precompiled headers for globally (I know how to change it for every project, but that is annoying). And how do I get it to use the A versions of the Win32 by default and not the W?
You should not want to use the A versions instead of W versions of functions in 2015. Not every code page has every character you'll want to use, you may wind up not using solely English in the future in some major project, and virtually all the data we communicate on the Internet is in some form of Unicode. For Windows programs, you will have to embrace wide strings and UTF-16; Microsoft has yet to invent the time machine that will let us use UTF-8 directly in APIs. (Microsoft's adoption of Unicode predated UTF-8.) The A functions do not work with UTF-8 because UTF-8 is not a valid process code page (it is only valid in the character set conversion functions).
If you really want to avoid using UTF-16 as much as possible, you will need to convert between UTF-8 and UTF-16 at every API call point. Not using either UTF-8 or UTF-16 for text, though, is no longer recommended. In fact, it's a great thing that VS2015, according to your code sample above, dropped the TCHAR madness of prior versions that continues to confuse beginning Windows programmers (especially here on Stack Overflow) to this day.
From https://msdn.microsoft.com/en-us/library/ms185319.aspx :
Locate the .zip file that contains the template. By default, this file is located in
\My Documents\Visual Studio Version\My Exported
Templates\
Extract the .zip file.
Modify or delete the current template files, or add new files to the
template.
Open, modify, and save the .vstemplate XML file to handle updated
behavior or new files. For more information about the .vstemplate
schema, see Visual Studio Template Schema Reference. For more
information about what you can parameterize in the source files, see
Template Parameters
Select the files in your template, right-click, click Send To, and
then click Compressed (zipped) Folder. The files that you selected are
compressed into a .zip file.
Put the new .zip file in the same directory as the old .zip file.
Delete the extracted template files and the old template .zip file.
Start (as administrator) an instance of the Developer Command Prompt
(on the start menu, under Visual Studio 2010 / Visual Studio Tools /
Developer Command Prompt).
Run the following command: devenv /installvstemplates.
The other mentioned things can be changed too.
I am currently working on an OpenGL win32 project converting the standard win32 to C++ classes. During the initial implementation I ran into an issue where when the window is resized the frame freezes and the window changes size very slowly, jumping from one size to the next. When the window is finished resizing there is noticeable hesitation before the window updates the drawing surface.
I am using a WM_TIMER to update the display as frequently as possible. During 'normal' operation the program clears the screen, slowly updating the red component to visually show a change in the surface drawing. Given the extremely simple design of the test I can't imagine that the openGL code is the problem during a resize event. I did test to see if manually resizing the window by catching the mouse button down and calling setwindowpos with adjusted values would cause the same behavior and it did. If I kept the size the same and called SetWindowPos the screen didn't stall though. This leads me to believe that something in the resize handling code is locking the HDC in some way preventing the swapbuffers from performing at speed. Possibly waiting on a multithread lock somewhere in the Win32 resize code.
Below is a small program that exhibits the exact same behavior as the larger program.
Only external lib being used is opengl32.lib.
#include "stdafx.h"
#include "OpenGLTest.h"
#include <gl\GL.h>
#define MAX_LOADSTRING 100
HINSTANCE hInst;
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
ATOM MyRegisterClass(HINSTANCE hInstance,LPCTSTR strClassName,WNDPROC wndProc,HBRUSH brBackground);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND _hWnd;
HDC _hDC;
HGLRC _glRC;
BOOL DrawWindow();
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_OPENGLTEST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance,szWindowClass,WndProc,NULL);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OPENGLTEST));
// Main message loop:
bool bRun=true;
while (bRun)
{
if (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message==WM_QUIT)
{
break;
}
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance,LPCTSTR strClassName,WNDPROC wndProc,HBRUSH brBackground)
{
WNDCLASSEX wcex;
//Register Main Window Class
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW ;
wcex.lpfnWndProc = wndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = brBackground;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = strClassName;
wcex.hIconSm = NULL;
return RegisterClassEx(&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 = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!_hWnd)
{
return FALSE;
}
_hDC=GetDC(_hWnd);
if (_hDC!=nullptr)
{
//Create OpenGL 3.2 context
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette.
32, //Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24, //Number of bits for the depthbuffer
8, //Number of bits for the stencilbuffer
0, //Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int nPixelFormat=ChoosePixelFormat(_hDC,&pfd);
SetPixelFormat(_hDC,nPixelFormat,&pfd);
if ((_glRC=wglCreateContext(_hDC))!=nullptr)
{
//Make Context Current
wglMakeCurrent(_hDC,_glRC);
}
}
ShowWindow(_hWnd, nCmdShow);
UpdateWindow(_hWnd);
SetTimer(_hWnd, 0, 1, NULL);
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)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_TIMER:
DrawWindow();
break;
case WM_ERASEBKGND:
return TRUE;
case WM_PAINT:
BeginPaint(_hWnd,&ps);
EndPaint(_hWnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
float fRed=0.0f;
BOOL DrawWindow()
{
RECT rc;
GetClientRect(_hWnd,&rc);
HDC hDC=GetDC(_hWnd);
if ((hDC!=nullptr)&&(_glRC!=nullptr))
{
//Print Client Data to Window Title for debugging
TCHAR strTitle[MAX_LOADSTRING];
wsprintf(strTitle,L"%d, %d, %d, %d",rc.left,rc.top,rc.right,rc.bottom);
SetWindowText(_hWnd,strTitle);
wglMakeCurrent(hDC,_glRC);
glViewport(rc.left,rc.top,(rc.right-rc.left),(rc.bottom-rc.top));
glClearColor(fRed,1.0f,0.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT);
SwapBuffers(hDC);
fRed+=0.1;
if (fRed>1.0f) fRed=0.0f;
ReleaseDC(_hWnd,hDC);
}
return TRUE;
}
EDIT: The problem is a hardware issue not software. I moved over to another system and the issue is not there. Thank you for your assistance.
I have set the entry point to WinMain but when I run the app it starts and doesn't display, I then have to shut it with task manager. Here's the code upto WinMain() :
#include <Windows.h>
// forward declarations
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// The entry point into a windows program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int windowStyle )
{
....
I'm not experienced in C++, and I don't know what this is doing, except making my exe smaller, which is what I'm trying to achieve.
edit : What I'm trying to do is create a very small window exe to understand how demo coder's work. So I'm thinking of creating a small c++ window app that provides a window handle to which I can attach SlimDX (if i can statically link the final c++ dll to a C# app, but I'm not there yet) I have my BasicWindow.exe down to 6,656 bytes. So I'm experimenting with anything I can find to get that size down to <3k.
[2012.Jan.10] Well I've had some success by rebuilding minicrt (available from http://www.benshoof.org/blog/small-programs/) under VS2010 and adding it as an additional dependency. I couldn't Ignore All Default Libraries as suggested, but I now have a Windowed application with an exe size of 4,096 bytes. I'd say that's some significant success. I'm within striking distance now. Every reduction from here on in, is more room for SlimDX. I'm pretty happy considering the only c++ apps I've ever written are console apps and a basic window :) I've been lucky I know !
A typical application should not mess up with Entry point setting of linker. Entry point should be set on a function included in the standard runtime library (which is wWinMainCRTStartup for unicode application for windows subsystem). This function does stuff like the proper initialization of CRT and creation of global objects. By rerouting entry point to your WinMain you will get undefined behavior unless you know precisely what you are doing and somehow implementing CRT initialization in your own WinMain. In my opinion the resulting size decrease will be negliable and the whole affair is hardly worth the risk.
When you set the entry point to WinMain, Windows doesn't give your program a console window, because WinMain is for programs with GUIs that don't need a console window. Your program is indeed running, though with no GUI you don't see anything happen.
I had the same issue. I wasn't satisfied with the answer marked here. So, I started digging in more and found that WS_VISIBLE was missing from CreateWindowEx function.
WS_OVERLAPPEDWINDOW with WS_VISIBLE makes the code work perfectly.
And regarding the file size, I was able to bring down the size of the code for x64 build to 3,072 bytes 1,600 bytes using Visual Studio Community Edition 2013 running on Windows 7 Ultimate SP1 x64. All this, without using minicrt.lib, you mentioned above.
Here's a screenshot of the executable properties.
For reference, here is the full program :
#include <Windows.h>
// forward declarations
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); // WindowProcedure function
// The entry point into a windows program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int windowStyle )
{
// create and register a local window class > exit on failure
WNDCLASSEX wcx;
HINSTANCE zhInstance = GetModuleHandle(NULL);
wcx.cbSize = sizeof(WNDCLASSEX); // size of structure
wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes
wcx.lpfnWndProc = WndProc; // window procedure
wcx.cbClsExtra = 0; // no extra class memory
wcx.cbWndExtra = 0; // no extra windows memory
wcx.hInstance = zhInstance; // handle to instance (owner)
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); // predefined icon
wcx.hCursor = LoadCursor (NULL, IDC_ARROW); // predefined arrow
wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//(HBRUSH) (COLOR_WINDOW + 1);// white background brush
wcx.lpszMenuName = NULL; // name of menu resource
wcx.lpszClassName = TEXT("BasicWindow"); // name of window class
wcx.hIconSm = (HICON)LoadImage(zhInstance, // small class icon
MAKEINTRESOURCE(5),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR);
if (!RegisterClassEx(&wcx))
{
MessageBoxA(0, "Error registering window class!","Error",MB_ICONSTOP | MB_OK);
DWORD result = GetLastError();
return 0;
}
// create window > exit on failure
HWND hwnd; // the window handle
hwnd = CreateWindowEx(
WS_EX_STATICEDGE,
wcx.lpszClassName,
TEXT("Basic Window"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
320,
240,
NULL,
NULL,
zhInstance,
NULL);
if (hwnd == NULL)
{
MessageBoxA(0,"Error creating window!","Error",MB_ICONSTOP | MB_OK);
return 0;
}
// show window
ShowWindow(hwnd, SW_MAXIMIZE);
// send a WM_PAINT message to the window
UpdateWindow(hwnd);
// enter message loop, break out of loop if there is an error (result = -1)
MSG msg; // for storing the windows messages
int status; // for storing the status of the windows message service where -1 = error, 0 = WM_QUIT, n = any other message)
while ((status = GetMessage(&msg,(HWND) NULL,0,0)) != 0 && status != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
UNREFERENCED_PARAMETER(lpCmdLine);
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
default:
return DefWindowProc(hWnd,message,wParam,lParam);
}
return 0;
}
I've been playing around with the Windows api for uni, but I cant get the window messages to call WM_PAINT after the inital creation. It calls it when the window is created but not after.
All Other messages get called! Just cant get the WM_PAINT to be called.
This is part of a game lib we have to make using the Windows api, (the goal is to learn abit of the windows api, rather than the intricacies of making game libs).
From what I gather the UpdateWindow(handle) command calls inititates the WM_PAINT message, but no matter where I put this command (currently in the game loop) I cant get it to call the message.
There's a lot of code, so I've trimmed it a little.
I know I have multiple WM_PAINT cases, they are a result of trying to make sure its getting through.
Window Creation
HWND hwnd;
hwnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
L"FirstWindowClass",
L"Mootlib",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
m_screenWidth,
m_screenHeight,
NULL,
NULL,
WindowsUtilities::windowInstance(),
NULL);
Register the Window
WNDCLASSEX wcex;
wcex.cbSize = sizeof (wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = windowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = WindowsUtilities::windowInstance();
wcex.hIcon = 0;
wcex.hCursor = LoadCursor (NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"FirstWindowClass";
wcex.hIconSm = 0;
RegisterClassEx (&wcex);
Winproc
LRESULT CALLBACK windowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LONG_PTR lptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
switch(message)
{
case(WM_PAINT):
int f = 3;
}
if (lptr)
{
Window* obj = reinterpret_cast<Window*>(lptr);
return obj->handleWindowsMessages(message, wParam, lParam);
}
else
return DefWindowProc(hwnd, message, wParam, lParam);
}
Internal command
LRESULT Window::handleWindowsMessages(UINT message, WPARAM wParam, LPARAM lParam)
{
std::wstring szHello = L"Hello, world!";
PAINTSTRUCT ps;
HDC hdc;
switch(message)
{
case(WM_PAINT):
hdc = BeginPaint(m_handle, &ps);
TextOut(hdc, 0, 0, L"Hello, Windows!", 15);
EndPaint(m_handle, &ps);
return 0;
case(WM_CLOSE):
quitGame();
return 0;
// Move Me!!!
case(WM_KEYDOWN):
case(WM_LBUTTONDOWN):
case(WM_RBUTTONDOWN):
inputManager().addButtonEvent(reinterpret_cast<int&>(wParam), BUTTON_DOWN);
return 0;
// Move Me!!!
case(WM_KEYUP):
case(WM_LBUTTONUP):
case(WM_RBUTTONUP):
inputManager().addButtonEvent(reinterpret_cast<int&>(wParam), BUTTON_UP);
return 0;
}
return DefWindowProc(handle(), message, wParam, lParam);
}
Game Loop
while(IsWindowVisible(handle()))
{
UpdateWindow(handle());
WindowsUtilities::processMessages();
draw();
update();
inputManager().update();
inputManager().clearButtonUpEvents(); // this should be in the input update()
}
Thanks.
First, I really don't like your game loop as its not at all obvious where the windows message pump is.
Somewhere along the line you need to call PeekMessage() or GetMessage() and TranslateMessage() & DispatchMessage() on any messages retrieved. Lots of people unfamiliar with windows will filter the messages, either in a range, or for a window: don't - always pump all messages for all windows on the current thread.
Then you need to call InvalidateRect to mark the areas of the window you want repainted. Games will want to pass FALSE as getting the background painted is just a waste of time when youre painting the entire scene in WM_PAINT.
RedrawWindow is useful for a game if you just want to mark an entire part of the window dirty and repaint it in one step. The advantage of InvalidateRect is that it just adds the rectangle to a dirty region, so if your game consists of just a few small 'active' sprites, as each sprite animates you can mark just the corresponding rect dirty, and windows will collect the dirty rects and paint them in a batch when next you call UpdateWindow, or let the message loop generate a WM_PAINT message.
Here's a snippet from the canonical Windows code, auto-generated when you create a new Win32 project in Visual Studio:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
Note what's missing in yours: you forgot to call ShowWindow().
If you want WM_PAINT to be called, you can use RedrawWindow or InvalidateRect.
MSDN states:
The UpdateWindow function updates the
client area of the specified window by
sending a WM_PAINT message to the
window if the window's update region
is not empty.
Your issue is that you haven't set an update region.
You could just do:
SendMessage( handle(), WM_PAINT, 0, 0 );
win32 windows application and want to capture full screen and remove the border of window displayed any one tell me how can i do so if this window capture the mouse keyboard controls then it will be ideal?
// MonitorScreen.cpp : Defines the entry point for the application. //
#include "stdafx.h"
#include "MonitorScreen.h
#define MAX_LOADSTRING 100
// Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR 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 _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here. MSG msg; HACCEL hAccelTable;
// Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_MONITORSCREEN, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance);
// Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; }
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MONITORSCREEN));
// Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
return (int) msg.wParam; }
// // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // // COMMENTS: // // This function and its usage are only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this function // so that the application will get 'well formed' small icons associated // with it. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex;
int s =sizeof(WNDCLASSEX); wcex.cbSize =sizeof(WNDCLASSEX);
wcex.style = DESKTOP_HOOKCONTROL ;//CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = NULL;//hInstance; wcex.hIcon = NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MONITORSCREEN)); wcex.hCursor = NULL;//LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(9); wcex.lpszMenuName = NULL;//MAKEINTRESOURCE(IDC_MONITORSCREEN); wcex.lpszClassName = szWindowClass; wcex.hIconSm = NULL;//LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&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) { HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
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) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc;
switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent
= HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
// 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_COMMAND: if (LOWORD(wParam)
== IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; }
I'm going to assume you don't actually want to capture the screen, your question cannot make sense. I'm guessing you simply want to make your window maximized to occupy the full screen. Put the template generated code back the way it was, simply change the ShowWindow call:
ShowWindow(hWnd, SW_MAXIMIZE);
Found this on google: Difficulties with Screen Capture, C/C++...
Try to understand the code and adjust it to you needs.
void CaptureScreen(LPCTSTR lpszFilePathName)
{
BITMAPFILEHEADER bmfHeader;
BITMAPINFO *pbminfo;
HBITMAP hBMP;
CFile oFile;
CDC *pDC = GetWindowDC();
INT nSizeImage = 1024 * 768 * 3;
CHAR *pBuff = new CHAR[sizeof(BITMAPINFOHEADER) + nSizeImage];
pbminfo = (BITMAPINFO *)pBuff;
hBMP = (HBITMAP)pDC->GetCurrentBitmap()->m_hObject;
ZeroMemory(pbminfo, sizeof(BITMAPINFO));
pbminfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(pDC->m_hDC,
hBMP,
0,
1,
NULL,
pbminfo,
DIB_RGB_COLORS);
GetDIBits(pDC->m_hDC,
hBMP,
0,
pbminfo->bmiHeader.biHeight,
pBuff + sizeof(BITMAPINFOHEADER),
pbminfo,
DIB_RGB_COLORS);
ReleaseDC(pDC);
bmfHeader.bfType = 0x4d42; /*"BM"*/
bmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nSizeImage;
bmfHeader.bfReserved1 = 0;
bmfHeader.bfReserved2 = 0;
bmfHeader.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
oFile.Open(lpszFilePathName, CFile::modeWrite | CFile::modeCreate);
oFile.Write(&bmfHeader, sizeof(BITMAPFILEHEADER));
oFile.Write(pBuff, sizeof(BITMAPINFOHEADER) + pbminfo->bmiHeader.biSizeImage);
delete []pBuff;
oFile.Close();
}
I think you want to use OpenGL or DirectX and invoke full-screen mode for your application. There will of course be a few keystrokes you can't intercept, such as the Secure Attention Sequence (usually CTRL+ALT+DEL) but most interaction with the computer will be directed to your program.
first to get the full screen you should type this in:
ShowWindow(hWnd, SW_SHOWMAXIMIZED)
Second to remove the border or witch is called thick frame in the window styles you should type in your CreateWindow function(the place where you put your styles (WS_)):
CreateWindow(your class,
window name,
WS_POPUP | WS_BORDER,
The rest of your params for the create window func.);
Ps:WS_BORDER IS JUST A 1 PX BLACK BORDER so you can know where is the window if it was not minimized and on top of a window woth the same bg color AND YOU CAN REMOVE IT WHENEVER YOU WANT
Also you wont be able to minimize,maximize,close the window with the built in buttons because they wont be there so if you want to close the app just make a button that sends a PostQuitMessage when pressed.
good luck