Why the following code is not working? - c++

I have Created a static control using following styles...
picBoxDisp = CreateWindow("STATIC", "image box",
WS_VISIBLE |WS_CHILD | SS_BITMAP |WS_TABSTOP | WS_BORDER,
50, 50, 250, 300,
hwnd , (HMENU)10000, NULL, NULL);
SetWindowLongPtr(picBoxDisp,GWLP_WNDPROC,(LONG) dispWndProc);
from someplace in my program I have the following code..
SendMessage(picBoxDisp,STM_SETIMAGE, (WPARAM) IMAGE_BITMAP,(LPARAM) hBitmap);
now inside the dispWndProc I have the following code..
LRESULT CALLBACK dispWndProc(HWND hwnd,UINT msg, WPARAM wParam, LPARAM lParam)
{
static HDC hdc;
static PAINTSTRUCT paintSt;
static RECT aRect;
switch(msg)
{
case WM_PAINT:
{
hdc = BeginPaint(hwnd,&paintSt);
GetClientRect(hwnd,&aRect);
// the code for painting
EndPaint(hwnd,&paintSt);
}
break;
case STM_SETIMAGE:
{
//painting code;
HBITMAP img = (HBITMAP)lParam;
BITMAP bmp;
GetObject(img,sizeof(bmp),&bmp);
HDC imgDC = GetDC((HWND)img);
HDC memDC = CreateCompatibleDC(imgDC);
SelectObject(memDC,img);
if((img==NULL))// ||(imgDC==NULL)||(memDC==NULL))
{
MessageBox(NULL,"img is NULL","Bad Programming!!! Error",MB_OK);
}
else
{
StretchBlt(hdc,0,0,aRect.right,aRect.bottom,
memDC,0,0,bmp.bmWidth,bmp.bmHeight,
SRCCOPY);
}
}
break;
default:
return DefWindowProc(hwnd,msg,wParam,lParam);
}
return 0;
}
can anyone tell why the lParam doesnt typecast back to HBITMAP.... why img is NULL ?
thanks in advance,

It's possible that some other code is also sending STM_SETIMAGE to your window. Count the number of times you call SendMessage(STM_SETIMAGE) and the number of times you reach case STM_SETIMAGE.
Also, HDC imgDC = GetDC((HWND)img); is never going to work. An HBITMAP is not an HWND.

There are multiple issues with this code.
You cannot use BeginPaint / EndPaint anywhere except for handling WM_PAINT. Fix that before even considering other problems.
Next, it's not clear that you're correctly subclassing the window; make sure you call CallWindowProc on the old window proc.
It's tricky to guarantee that what you are seeing is really what you think you are seeing. For example as Ben Voigt says, maybe you are not the one that sent it. Maybe a switch case block above fell through. Maybe you passed in NULL to begin with.
Start with these things, and you will get closer to being on track.

Related

While loop on popup window not responding

I've a popup window that displays a picture. Each time it displays a picture, the content is changed by another code to make it look like a motion picture.
Without using a while loop, it just displays the picture and the window doesn't hang, it responds perfectly well.
But I'm unable to achieve what I want without a while loop. when I use the while loop to create the motion picture. It works, but after a while the window stops responding.
Here's an example of the window procedure:
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
HDC hdc;
PAINTSTRUCT ps;
switch(msg){
case WM_PAINT:{
hdc = BeginPaint(hWnd, &ps);
Gdiplus::Graphics graph(hdc);
while(true){
Sleep(100);
Image img(L"Test.png");
graph.DrawImage(&img, 0, 0, 1000, 700);
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd,msg,wp,lp);
}
}
As #RetiredNinja said in comments, this code really needs a timer, not a while loop. If you block the window procedure, the window will stop responding to messages. You must return flow to the thread's message loop after each message is processed.
At startup, load your initial image, start the timer, and invalidate the window. Done.
Whenever the timer fires, update the image as needed and invalidate the window to trigger a repaint. Done.
Every time the window procedure receives a WM_PAINT message, draw the current image as-is onto the window. Done.
That is all you need to do. No threads are needed. And the app remains responsive at all times, because no single message is blocked for more than a few milliseconds.
Try something more like this instead:
Image *img = nullptr;
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
switch(msg){
case WM_CREATE:
img = Image::fromFile(L"Test.png", FALSE);
SetTimer(hWnd, 1, 100, NULL);
break;
case WM_DESTROY:
KillTimer(hWnd, 1);
delete img;
PostQuitMessage(0);
break;
case WM_TIMER:{
// update img as needed...
InvalidateRect(hWnd, NULL, TRUE);
break;
}
case WM_PAINT:{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Gdiplus::Graphics graph(hdc);
graph.DrawImage(img, 0, 0, 1000, 700);
EndPaint(hWnd, &ps);
break;
}
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
return 0;
}

Windows API: How to Draw Text to Child Window? [duplicate]

This question already has answers here:
How can I change the background color of a button WinAPI C++
(4 answers)
Closed 7 years ago.
I have recently started learning windows API and would like to make more interactive GUI applications. All code is written in C++.
What I have done is made a custom button window, not using the built in button class. I want each button to have different text and would like to set this in the parent window.
So I create the button and save the handle:
hNavBtnNews = CreateWindow(szUW_NAV_BTN, "News", WS_CHILD | WS_VISIBLE, 540, 0, 100, HEADER_HEIGHT, header, NULL, NULL, NULL);
Then to make sure this hasn't failed I check the handle and attempt drawing text:
if(hNavBtnNews == NULL){
printf("\nFailed to Create Window Nav Button \n");
}else{
printf("\nCreated Window Nav Button");
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
hdc = BeginPaint(hNavBtnNews, &ps);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, BG_TXT_COLOR);
GetClientRect(hNavBtnNews, &rect);
DrawText(hdc, "News", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hNavBtnNews, &ps);
}
This is all done in the WM_CREATE case of the parent window procedure (which itself works just fine). The text is a light grey color and the background of the button is a dark blue. Except the text is not being drawn. There are no compiler warnings or errors either. Perhaps subclassing built in controls would be better for this, though I don't know how. Any help in solving this issue would be greatly appreciated.
Consider the following brief snippet as an example of how simple sub-classing can be:
LRESULT CALLBACK myDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_PAINT:
onBtnPaint(hWnd, wParam, lParam);
return TRUE;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
BOOL CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
HWND button = GetDlgItem(hwndDlg, IDC_BUTTON_TO_SUBCLASS);
SetWindowSubclass(button, myDrawButtonProc, 0, 0);
}
return TRUE;
...
...
...

multiple dialog processes to controls? winapi / C++

I've just created multiple edit boxes (11x11 controls) based on this article:
https://msdn.microsoft.com/en-us/library/windows/desktop/hh298433%28v=vs.85%29.aspx
Well, not exactly same, but I used the code in case WM_CREATE: block to create huge number of controls.
I use this dialog process on the parent window:
INT_PTR CALLBACK StartupDialogProc(HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg){
case WM_INITDIALOG:
Init_Startup(dialog);
return 1;
/*
case EN_CHANGE:
case WM_CTLCOLOREDIT:
{
HDC hdC = (HDC)wParam;
COLORREF crColorBackground = RGB(255,0,0);
if (crColorBackground)
SetBkColor(hdC, crColorBackground);
SetTextColor( hdC, RGB(12,112,212) );
SetBkMode( hdC, TRANSPARENT );
RECT rect;
GetClientRect( (HWND)lParam, &rect );
HBRUSH hBrush = CreateSolidBrush( RGB(209,209,209) );
//FrameRect( hdC, &rect, hBrush );
Rectangle( hdC, (int)rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom );
DeleteObject( hBrush );
LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = RGB(249,249,249);
lb.lbHatch = 0;
CreateBrushIndirect(&lb); // LRESULT
// GetStockObject(NULL_BRUSH);
return 1;
}
break;
*/
case WM_DESTROY:
setts.options.page = GetDlgItemInt(dialog, IDC_O_STARTUP_PAGE, NULL, FALSE);
setts.options.recent = GetDlgItemInt(dialog, IDC_O_STARTUP_RECENT, NULL, FALSE);
break;
case WM_CLOSE:
EndDialog(dialog, FALSE);
break;
case WM_COMMAND:
if (wParam == IDOK) {
EndDialog(dialog, TRUE);
return 0;
}
}
return 0;
}
There is few things unclear to me:
1) if I would like to change color of border for all edit controls from id 5001 to id 5121, how to do that? To me, the commented code does not work (when would it be uncommented). It looks like I have this in incorrect place.
2) how correctly create the dialog processes to all the controls? Because there is big number and could be yet few times higher, should I just call a loop from 5001 to id 5121 and call the function:
INT_PTR CALLBACK EditDlgProc(HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam) - that won't work, because every function would need to have different name.
To change the border color of edit control, you have to subclass the edit control and override WM_NCPAINT. That's a little advanced, and you don't really need it. You can just use WS_EX_CLIENTEDGE flag:
CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT" ...
Also make sure project manifest is setup so you get modern window's look.
This would be an error if it had not been commented out:
case EN_CHANGE:
case WM_CTLCOLOREDIT:
Each case should end in break; or return 0;
Moreover, WM_CTLCOLOREDIT should return a brush which was created on heap. It should not return 1. See documentation :
There are also other errors in that section, you should just get rid of that. See this example for painting.

C++ WinApi Fillrect() crashes (multiple rects)

i am trying to get used to WinApi and decided to make a GUI for a sudoku-generator i programmed.
It should adjust dynamicly to the windowsize the user chooses.
So far everything works as inteded, but if the WM_PAINT-msg is sent too often in a short window of time (eg changing the size of the window) the program crashes.
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
stringstream ss; //not used
RECT rect;
int w;
int h;
HBRUSH coluns=CreateSolidBrush(RGB(50,120,180));
HBRUSH colsel=CreateSolidBrush(RGB(80,150,220));
HBRUSH colmso=CreateSolidBrush(RGB(50,70,190));
switch (message)
{
case WM_SIZE: //
{
GetWindowRect(hwnd,&rect);
menu.wndw=rect.right-rect.left; //menu is a class to store important information
menu.wndh=rect.bottom-rect.top;
h=menu.wndh;
w=menu.wndw;
for(int i=1;i<10;i++)
{
for(int j=1;j<10;j++)
{
menu.feld[i][j].SetSpace((w/4)+((i-1)*(w/20))+i+(2*((i-1)/3)),(h/4)+((j-1)*(h/20))+j+(2*((j-1)/3)),(w/4)+((i)*(w/20))+i+(2*((i-1)/3)),(h/4)+((j)*(h/20))+j+(2*((j-1)/3)));
}
} //feld is a class wich exists in a 10x10 array with the 0s not being used
InvalidateRect(hwnd,NULL, TRUE);
}
break;
case WM_PAINT:
{
RECT re;
w=menu.wndw;
h=menu.wndh;
hdc = BeginPaint(hwnd,&ps);
re.left=(w/4)-4;
re.top=(h/4)-4;
re.right=(w/4)+9*(w/20)+18;
re.bottom=(h/4)+9*(h/20)+18;
FillRect(hdc,&re,CreateSolidBrush(RGB(0,0,0)));
for(int i=1;i<10;i++)
{
for(int j=1;j<10;j++)
{
re=menu.feld[i][j].GetSpace();
if(menu.feld[i][j].GetSelect()==uns)
if(FillRect(hdc,&re,coluns)==0)
MessageBox(hwnd, "fail","fail",0);
if(menu.feld[i][j].GetSelect()==mso)
if(FillRect(hdc,&re,colmso)==0)
MessageBox(hwnd, "fail","fail",0);
if(menu.feld[i][j].GetSelect()==sel)
if(FillRect(hdc,&re,colsel)==0)
MessageBox(hwnd, "fail","fail",0);
}
}
EndPaint(hwnd, &ps);
}
break;
http://www.pic-upload.de/view-22113118/Unbenannt.png.html
here is a picture of what the executed program looks like.
Now as described earlier the program will crash if u change the windowsize in a lot of small steps. After calling the MW_PAINT msg for ~10 times the window will just freeze with 1 of the rects being white instead of the desired color (random one, different every time).
my assumption is that i need to release some kind of resources because mby a stack will overflow or smth, but i have really no idea where i could have a leak in my program.
i would be very grateful if anyone could help me.
You create three brush handles every single time your window procedure executes. These handles are never tidied up. And then inside the WM_PAINT handler, you create a brush which you pass to FillRect and so can never destroy it.
So you leak three handles every time the window procedure executes (which happens a lot), and one more every time it handles WM_PAINT. Simply put, your program leaks like a sieve!
You should consider creating these brushes when the window is created, and destroying them when the window is destroyed. Or perhaps creating them inside the WM_PAINT handler, and destroying them as soon as you have finished using them. But since they have constant colors it is probably best to create 4 brushes up front, once and for all.
You are leaking GDI resources as member David Heffernan said.
Here is the example of how to properly use brushes in your application-pay attention to WM_COMMAND handler in that example.
If you do not use stock GDI objects you must delete them after you are done working with them.
Here is the simple example that fills window with red brush in WM_PAINT handler:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPain( hdc, &ps );
HBRUSH hbrRedBrush = CreateSolidBrush( RGB( 255, 0, 0 ) );
RECT r;
GetClientRect( hWnd, &r );
FillRect( hdc, &r, hbrRedBrush );
DeleteObject( hbrRedBrush ); //you must delete GDI object!
EndPaint( hWnd, &ps );
}
return 0L;
In your case, I would make 4 static brushes and rework my code a little, adding the proper cleanup in WM_CLOSE handler. Below are the suggested changes:
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
// add static before HBRUSH
static HBRUSH coluns=CreateSolidBrush(RGB(50,120,180));
static HBRUSH colsel=CreateSolidBrush(RGB(80,150,220));
static HBRUSH colmso=CreateSolidBrush(RGB(50,70,190));
static HBRUSH BlackBrush = CreateSolidBrush(RGB(0,0,0));
switch (message)
{
// this is the problematic handler
case WM_PAINT:
{
//the changed part
FillRect( hdc, &re, BlackBrush );
}
break;
case WM_CLOSE:
{
DeleteObject( BlackBrush );
DeleteObject( coluns );
DeleteObject( colsel );
DeleteObject( colmso );
// other clean up code
}
break;
IMPORTANT NOTE:
This time you used FillRect API, but next time you might load bitmaps and other stuff that require from you to restore HDC into original state after you are done with drawing.
You do that like this:
HBITMAP bmpOld = (HBITMAP)SelectObject( hdc, myBitmap );
// bmpOld stores the original state of the device context
// you do something with myBitmap
// then you return device context into original state
// by selecting the original value, bmpOld, back into device context
SelectObject( hdc, oldBmp );
DeleteObject( myBitmap );
Again, pay attention to WM_COMMAND handler in the above MSDN example to see how they did it.
Here is the link to a great Win32 API tutorial for beginners-give it a go.
In the end I recommend you this tool for detecting GDI leaks.
If you have further questions leave a comment and I will reply as soon as possible.
Best regards and good luck!

How to draw Text with Timer?

I used DrawText function within WM_TIMER, but it dont work. How to fix this? Thank you!
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd,23, 1000,NULL);
break;
//case WM_TIMER: ***** dont work *****
case WM_PAINT: // ***** work, but used 25% CPU *****
{
RECT rect;
HFONT hFont;
hdc = BeginPaint(hwnd, &ps);
hFont = CreateFontA(16,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, VARIABLE_PITCH,TEXT("Arial"));
SelectObject(hdc,hFont);
SetRect(&rect, 3, 3, 90, 50);
SetTextColor(hdc, RGB(0,0,255));
time_t rawtime;
struct tm * timeinfo;
char buffer [80];
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime (buffer,80,"%I:%M:%S %p\n%m/%d/%Y",timeinfo);
wchar_t wtext[30];
mbstowcs(wtext, buffer, strlen(buffer)+1);//Plus null
LPWSTR ptr = wtext;
DrawTextW(hdc, ptr, -1,&rect, DT_NOCLIP | DT_CENTER);
DeleteObject(hFont);
InvalidateRect(hwnd, &rect, TRUE);
UpdateWindow(hwnd);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wparam, lparam);
}
return 0;
}
Do not call InvalidateRect() or UpdateWindow() from WM_PAINT, or you will create an infinite loop of repaints.
Do not paint from the WM_TIMER. It can be done (with GetWindowDC() instead of BeginPaint() but it isn't such a good idea.
Instead put the InvalidateRect() in the WM_TIMER and leave the drawing code in WM_PAINT. You can optimize, as #typ1232 said in the comments, by creating the font only once, but that's not strictly necessary.
The UpdateWindow() call should not generally be necessary, unless you are in a tight CPU loop and need to show the window just now: if the invalidation is done in a timer and the timeout is not too short you won't need it. But if your timeout is very short you can force the redraw calling UpdateWindow() just after InvalidateRect().
Your WM_TIMER code should prepare the string to be drawn, save it and then call InvalidateRect. The WM_TIMER code can not draw directly, and one reason is that BeginPaint will not work properly during a WM_TIMER message. BeginPaint is only defined during a WM_PAINT message. So WM_TIMER can prepare the data to be drawn, but then use InvalidateRect to request that a WM_PAINT be generated.
You must also remove the InvalidateRect and UpdateWindow calls from the WM_PAINT code. They will cause an infinite loop of painting.