Drawing a Line Outside of WM_PAINT - c++

Usually, to draw a line we draw it in WM_PAINT
LRESULT CALLBACK Display::DisplayWindowProc(HWND hWnd,UINT msg,WPARAM wParamm,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch(msg)
{
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps);
MoveToEx(hdc,0,0,0);
LineTo(hdc,100,100);
EndPaint(hWnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hWnd, msg, wParamm, lParam);
}
But , i want to draw line whenever i want, simple example:
int WINAPI WinMain
(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR cmdLine,
int showCmd
)
{
//Do Other Things
Display dislpay;
display.DrawLine();
//Do Other Things
}
My Program is Object Oriented and i display things in Display class and i was wondering if i can do a draw line in a function like DrawLine() in Display Class.

You can create an off-screen DC, and select an appropriately sized bitmap, and use that to draw whenever you want. Then on WM_PAINT you blit from the off-screen DC into the windows DC.

Related

GetDC() for HWND before LRESULT function

I am trying to build software with 3d rendering capabilities without using external libraries. I'm a little confused with GetDC() and ReleaseDC(). If I write the following code after my LRESULT() loop, the program runs for several seconds and then freezes. (I have created two dc's for double buffering with BitBlt())
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
HDC hdc = GetDC(hWnd);
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membmp = CreateCompatibleBitmap(hdc, width, height);
SelectObject(memdc, membmp);
...
switch (message) {
...
}
}
However, according to this linkabout SetPixel() crashing after a time, I should move GetDC() outside of the loop. However, I must be doing it wrong, because if I do that...
HDC hdc = GetDC(hWnd);
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membmp = CreateCompatibleBitmap(hdc, width, height);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
TCHAR greeting[] = _T("program_name");
PAINTSTRUCT ps;
SelectObject(memdc, membmp);
...
}
... I realize that I cannot SelectObject() outside of the LRESULT loop. In fact, visual studio isn't even going to live with GetDC(hWnd) before the LRESULT loop, I expect because it is created in the first line of the loop. So, woefully, my only option seems to be to replace hWnd with NULL.
HDC hdc = GetDC(NULL);
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membmp = CreateCompatibleBitmap(hdc, width, height);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
TCHAR greeting[] = _T("program_name");
PAINTSTRUCT ps;
SelectObject(memdc, membmp);
...
}
Now I can no longer clear the window, as that relies on InvalidateRect(hWnd, NULL, TRUE). So it runs indefinitely, yet draws outside of the window and cannot erase.
I am new to programming and if anyone can point me in a direction or let me know what's going on, I would appreciate it. :)
If you're new to programming and c++ you should first learn the basics of the language and not start with using the WinAPI.
Also your "LRESULT() loop" is not a loop but rather a callback function called by your message loop.
Concerning your question: Your application should draw its windows content when it receives a WM_PAINT-message.
Your code is setup all wrong. Try this instead:
HDC hmemdc = NULL;
HBITMAP membmp = NULL;
HBITMAP oldbmp = NULL;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CREATE: {
HDC hdc = GetDC(hWnd);
membmp = CreateCompatibleBitmap(hdc, width, height);
memdc = CreateCompatibleDC(hdc);
oldbmp = (HBITMAP) SelectObject(memdc, membmp);
ReleaseDC(hWnd, hdc);
break;
}
case WM_DESTROY: {
SelectObject(memdc, oldbmp);
DeleteDC(memdc); memdc = NULL;
DeleteObject(membmp); membmp = NULL;
break;
}
case WM_ERASEBKGND: {
return 1;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
BitBlt(hdc, 0, 0, width, height, memdc, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
break;
}
...
}
return DefWindowProcc(hWnd, message, wParam, lParam);
}
Then, you can simply draw your 3D images into hmemdc/membmp as needed, and call InvalidateRect() whenever you want to signal to the OS that the window needs to be redrawn with the latest bitmap.
Though, if you are going to use a memory bitmap for your window, you might consider using UpdateLayeredWindow() instead, and get rid of the WM_PAINT/WM_ERASEBKGND handlers completely.

I want to make a clock(GUI program) via windows api, but the text on the clock doesn't change?

I want the text change as time changes like a clock, however, it doesn't change. I found that the text will change when I minimize or maximize the window.
I guess I should redraw the window, but I am new to windows api, anyone good advice?
This is the main.cpp codeļ¼š
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
//....
}
void Paint(HWND hwnd, LPCTSTR txt)
{
UpdateWindow(hwnd);
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawText(hdc, txt, -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
}
// Thread function
DWORD WINAPI ThreadFun(LPVOID lpParameter)
{
HWND hwnd = (HWND)lpParameter;
while (1)
{
string dateStr = Ticker::GetCurrentTimeStr();
Paint(hwnd, dateStr.c_str());
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
CreateThread(NULL, 0, ThreadFun, hwnd, 0, NULL);
}
return 0;
case WM_PAINT:
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
You need to call InvalidateRect to tell the system the drawing area has changed.
Edit
Instead of creating a new thread, you can create a timer with SetTimer (see example) and respond to WM_TIMER message. Call InvalidateRect in response to WM_TIMER, to repaint the window every second.
Do all of the painting in response to WM_PAINT.
Use BeginPaint/EndPaint only in response to WM_PAINT, don't use BeginPaint/EndPaint elsewhere.

DLL and drawing function disappearing

main.cpp (dll) http://pastebin.com/Z811YSz7
Funkcje.h http://pastebin.com/siZrUBh0
When i injected this dll to a game then i dont see letters.
When i maked drawing function in a while(1) then the letters are appearing and disappearing.
How to make the drawing function to be on the top of this game all the time.
#include <windows.h>
#include <vector>
#include "Funkcje.h"
#include <cstdio>
#include <string>
BOOL WINAPI DllMain(
HINSTANCE hinstDLL,
DWORD fdwreason,
LPVOID lpReversed)
{
switch (fdwreason)
{
case DLL_PROCESS_ATTACH:
PAINTSTRUCT ps;
HDC hdc;
for (size_t i = 0; i < getToplevelWindows().size(); i++){
hdc = GetDC(getToplevelWindows()[i]);
TextOut(hdc, 150, 150, L"TEST", 4);
ReleaseDC(getToplevelWindows()[i], hdc);
}
break;
}
return TRUE;
}
DllMain is only called once, when the DLL is loaded. This is not where you should be putting your code.
In order to properly "inject" code into a process (via DLL or any other mean) you must first determine what function or event in that process you want to hook.
In this case, I suppose you want to hook the window event WM_PAINT, a callback from the system sent to the window's procedure telling it that it should repaint its content for whatever reason. (This may not be always correct though, because a program can use other methods of updating a window content.)
So what you are going to do is find the window handle you want to hook, and replace its callback procedure with your own:
WNDPROC originalProc = SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)myHookProc);
But of course, not before having myHookProc defined and doing its job of hooking WM_PAINT:
LRESULT CALLBACK myHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT originalResult = originalProc(hWnd, uMsg, wParam, lParam); // call original first
if (uMsg == WM_PAINT)
{
PAINTSTRUCT ps;
HDC hdc = GetDC(hWnd);
TextOut(hdc, 150, 150, L"TEST", 4);
ReleaseDC(hWnd, hdc);
}
return originalResult;
}
If you are dealing with multiple windows, you may want to use a std::unordered_map<HWND, WNDPROC> to keep relation between each window handle and its original procedure.

Loading and painting bmp win32api c++

i am trying to show a bmp in the screen using this code: (this code is from a book but i cant show the windows when i compile only appear the white window)
#include "resource2.h"
#include <vector>
#include <windows.h>
using namespace std;
HWND window1;
HWND window2;
HINSTANCE happ;
HDC handledevice;
PAINTSTRUCT ps;
HBITMAP hbitmap;
BITMAP bitmap;
HDC bmhdc;
HBITMAP oldbm;
LRESULT CALLBACK WindTyp1(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
switch (msg)
{
case WM_KEYDOWN:
if (wparam==VK_ESCAPE)
{
DestroyWindow(window1);
}
return 0;
case WM_PAINT:
handledevice=BeginPaint(hwnd,&ps);
BitBlt(handledevice,0,0,bitmap.bmWidth,bitmap.bmHeight,bmhdc,0,0,SRCCOPY);
EndPaint(hwnd,&ps);
return 0;
}
return DefWindowProc(hwnd,msg,wparam,lparam);
}
LRESULT CALLBACK WindTyp2(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
switch (msg)
{
case WM_KEYDOWN:
if (wparam==VK_F1)
{
DestroyWindow(window1);
}
if (wparam==VK_F2)
{
DestroyWindow(window2);
}
if (wparam==VK_ESCAPE)
{
DestroyWindow(window1);
DestroyWindow(window2);
}
}
return DefWindowProc(hwnd,msg,wparam,lparam);
}
int WINAPI WinMain(HINSTANCE histance,HINSTANCE hprevinstance,PSTR cmdline,int showcmd)
{
happ=histance;
MSG msg;
hbitmap=LoadBitmap(happ,MAKEINTRESOURCE(happ,IDB_BITMAP1));
GetObject(hbitmap,sizeof(BITMAP),&bitmap);
bmhdc=CreateCompatibleDC(handledevice);
SelectObject(bmhdc,&bitmap);
//clase 1
WNDCLASS windowstyle1,windowstyle2;
windowstyle1.cbClsExtra=0;
windowstyle1.cbWndExtra=0;
windowstyle1.hbrBackground=(HBRUSH) ::GetStockObject(WHITE_BRUSH);
windowstyle1.hCursor=::LoadCursor(0,IDC_ARROW);
windowstyle1.hIcon=::LoadIcon(0,IDI_APPLICATION);
windowstyle1.hInstance=histance;
windowstyle1.lpfnWndProc=WindTyp1;
windowstyle1.lpszClassName="Class 1";
windowstyle1.lpszMenuName=0;
windowstyle1.style= CS_HREDRAW | CS_VREDRAW;
//clase 2
windowstyle2.cbClsExtra=0;
windowstyle2.cbWndExtra=0;
windowstyle2.hbrBackground=(HBRUSH) ::GetStockObject(BLACK_BRUSH);
windowstyle2.hCursor=::LoadCursor(0,IDC_ARROW);
windowstyle2.hIcon=::LoadIcon(0,IDI_APPLICATION);
windowstyle2.hInstance=histance;
windowstyle2.lpfnWndProc=WindTyp2;
windowstyle2.lpszClassName="Class 2";
windowstyle2.lpszMenuName=0;
windowstyle2.style= CS_HREDRAW | CS_VREDRAW;
//registrar ambas clases
RegisterClass(&windowstyle1);
RegisterClass(&windowstyle2);
//crear ventanas
window1=::CreateWindow("Class 1","Ventana Blanca",WS_OVERLAPPEDWINDOW,0,0,1400,1000,0,0,happ,0);
if (window1==0)
::MessageBox(0,"error failed to create window","error",0);
//Show & Update
ShowWindow(window1,true);
UpdateWindow(window1);
//Message Loop
ZeroMemory(&msg,sizeof(MSG));
while (GetMessage(&msg,0,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Have a look at this example here
http://www.functionx.com/win32/Lesson13.htm
bmhdc=CreateCompatibleDC(handledevice);
IN WinMain you're using handledevice - which isn't yet initialised, so selecting the bitmap would cause problems, but it's probably 0, so it would use the desktop DC. Usually I wouldn't do this in WinMain but in paint like in the example in the url.
hth
You are making life harder for yourself than necessary. The way you are expected to do this is with a STATIC window with the SS_BITMAP style.
I realise this is not an indirect answer to your question but I offer it since it will make your task much simpler - let the system do the heavy lifting for you!

c++ win32 output a text

im using visual studio c++ 2008 i created project that contents the full window code. i don't know how to output text to window. i mean i have full functional window with menu bar and under the menu bar there is the body im trying to ouput the text in the body but how?
This page has a sample on how to do it in Win32:
http://www.rohitab.com/discuss/index.php?showtopic=11454
The code below is the Window Procedure for the window, if you note the WM_PAINT (That is the message that tells the window to paint itself) the code is simply drawing the text to the Device Context, which is the client area of the window.
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
HDC hdc;
PAINTSTRUCT ps;
LPSTR szMessage = "darkblue 0wNz j00!";
switch(Message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 70, 50, szMessage, strlen(szMessage));
EndPaint(hwnd, &ps);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
As an out of topic note, I suggest you to try some 3rd party library instead, as it can be much more convenient. Take a look at wxWidgets for instance.