943,097 Members | Top Members by Rank

Ad:
  • C++ Discussion Thread
  • Unsolved
  • Views: 3590
  • C++ RSS
You are currently viewing page 1 of this multi-page discussion thread
Feb 1st, 2010
0

Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)

Expand Post »
Hello, I'm trying to get from the screen, the region, or rectangle (the coordinated) of the part that is being painted. For example when I move some window or I have some action on the screen I want to get only that part of the screen image that is being painted (because it changed).
I try calling it inside WM_PAINT event before BeginPaint().

C++ Syntax (Toggle Plain Text)
  1. LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
  2. {
  3. switch(Message)
  4. {
  5. [...]
  6. case WM_PAINT:{
  7.  
  8. RECT rectUpd;
  9.  
  10. if(hwnd!=NULL){
  11. char s[100]="";
  12.  
  13.  
  14. //hDesktop is desktop windown handler - GetDC(GetDesktopWindow());
  15. GetUpdateRect (hDesktop, &rectUpd, FALSE);
  16. c++;
  17.  
  18. sprintf(s,"Top:%d Left:%d Right:%d Bottom:%d",
  19. rectUpd.top,
  20. rectUpd.left,
  21. rectUpd.right,
  22. rectUpd.bottom);
  23. //I set the window title with the values of the rectangle
  24. SetWindowText(hwnd,s);
  25.  
  26.  
  27.  
  28. }
  29. BeginPaint(hwnd,NULL);//hwnd is application window handler
  30.  
  31. }break;
  32. [...]
  33. }
  34. }

I obtained only "-858993460" value for rectangle coordinates... Can somebody help me out how to detect the coordonates of the region painted on the screen?
Similar Threads
Reputation Points: 11
Solved Threads: 7
Posting Whiz in Training
Clawsy is offline Offline
225 posts
since Feb 2008
Feb 1st, 2010
0
Re: Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)
The invalid region is contained within the RECT member (.rcPaint) of the PAINTSTRUCT you used as an output parameter in the BeginPaint() call. It can be easily retrieved from there.

I wrote the above without looking at your code. All your code is totally bad. You are using BeginPaint() incorrectly. You need to declare a PAINTSTRUCT variable in your WM_PAINT handler. Its address should be the 2nd parameter of BeginPaint(). When BeginPaint() returns, you'll not only have the HDC you need, but also the coordinates of the invalid rectangle that needs painted. Its up to you what you do with this information. Passing a NULL as the 2nd parameter of BeginPaint() is something I've never seen done. Your BeginPaint() call would certainly have failed.

Also, I'd be ashamed posting code with such poor formatting.
Last edited by Frederick2; Feb 1st, 2010 at 12:06 pm.
Reputation Points: 244
Solved Threads: 31
Posting Whiz
Frederick2 is offline Offline
330 posts
since Jul 2008
Feb 1st, 2010
0
Re: Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)
Hmmm... I'm glad you pointed out how noob I am in Windows API, even if I never pointed out such thing about persons of this forums at java or c# who don't even know to declare an array... Yes, I admit I have a lot to learn.. for example how API messages work and hooking and thanks for the hint. I thinks a don't really have this in order... here is the code.
C++ Syntax (Toggle Plain Text)
  1. LPPAINTSTRUCT lp;
  2. HDC hdcInvRect;
  3. char s[100]="";
  4.  
  5. LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
  6. {
  7. switch(Message)
  8. {
  9. case WM_PAINT:{
  10.  
  11.  
  12. hdcInvRect = BeginPaint(hwnd,&lp);
  13.  
  14.  
  15. sprintf(s,"Top:%d Left:%d Right:%d Bottom:%d",
  16. lp->rcPaint.top,
  17. lp->rcPaint.left,
  18. lp->rcPaint.right,
  19. lp->rcPaint.bottom);
  20.  
  21. SetWindowText(hwnd,s);
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28. }break;
  29. }
  30. }
I guess it's poor code again... I don't need to use GetUpdateRect()? I knew it should be called before BeginPaint().
When I compile it throws an unhandled exception at sprintf line. Sorry... I must understand API and make some huge mistakes, then learn from that. Can you help me please?
Reputation Points: 11
Solved Threads: 7
Posting Whiz in Training
Clawsy is offline Offline
225 posts
since Feb 2008
Feb 1st, 2010
0

Finding Invalid Regions

Usually in my WM_PAINT handlers I just declare a...

PAINTSTRUCT ps;

...instead of a LPPAINTSTRUCT. However, that might be just me. When you do declare a LPPAINTSTRUCT though, this...

hDC=BeginPaint(hwnd,&lpPS);

won't work. I'd just do this...

PAINTSTRUCT ps;
HDC hDC;

hDC=BeginPaint(hwnd,&ps);

Here's a little program that demonstrates invalid regions by opening a text file in whatever directory you are running the program from, and outputs invalid regions as you move another window on top of the client window. Experiment by opening Notepad and resizing it to pretty small. Then move Notepad just barely over your client window, then close out and inspect your Output.txt file.

C++ Syntax (Toggle Plain Text)
  1. //Form1.h
  2.  
  3. typedef struct WindowsEventArguments
  4. {
  5. HWND hWnd;
  6. WPARAM wParam;
  7. LPARAM lParam;
  8. HINSTANCE hIns;
  9. }WndEventArgs, *lpWndEventArgs;
  10.  
  11.  
  12. struct EVENTHANDLER
  13. {
  14. unsigned int Code;
  15. long (*fnPtr)(lpWndEventArgs);
  16. };

C++ Syntax (Toggle Plain Text)
  1. //Main.cpp
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include "Form1.h"
  5. EVENTHANDLER EventHandler[3];
  6. FILE* fp;
  7.  
  8.  
  9. long fnWndProc_OnCreate(lpWndEventArgs Wea)
  10. {
  11. fp=fopen("Output.txt","w");
  12. fprintf(fp,"Entering fnWndProc_OnCreate()\n");
  13. fprintf(fp," Output.txt Opened In fnWndProc_OnCreate()\n");
  14. fprintf(fp,"Leaving fnWndProc_OnCreate()\n\n");
  15.  
  16. return 0;
  17. }
  18.  
  19. long fnWndProc_OnPaint(lpWndEventArgs Wea)
  20. {
  21. PAINTSTRUCT ps;
  22. HDC hDC;
  23.  
  24. fprintf(fp,"Entering fnWndProc_OnPaint()\n");
  25. hDC=BeginPaint(Wea->hWnd,&ps);
  26. fprintf(fp," ps.rcPaint.left = %u\n",(unsigned)ps.rcPaint.left);
  27. fprintf(fp," ps.rcPaint.top = %u\n",(unsigned)ps.rcPaint.top);
  28. fprintf(fp," ps.rcPaint.right = %u\n",(unsigned)ps.rcPaint.right);
  29. fprintf(fp," ps.rcPaint.bottom = %u\n",(unsigned)ps.rcPaint.bottom);
  30. EndPaint(Wea->hWnd,&ps);
  31. fprintf(fp,"Leaving fnWndProc_OnPaint()\n\n");
  32.  
  33. return 0;
  34. }
  35.  
  36.  
  37. long fnWndProc_OnClose(lpWndEventArgs Wea)
  38. {
  39. fprintf(fp,"Entering fnWndProc_OnClose()\n");
  40. DestroyWindow(Wea->hWnd);
  41. PostQuitMessage(0);
  42. fprintf(fp," Output.txt Closed In fnWndProc_OnClose()\n");
  43. fprintf(fp,"Leaving fnWndProc_OnClose()\n\n");
  44. fclose(fp);
  45.  
  46. return 0;
  47. }
  48.  
  49.  
  50. void AttachEventHandlers(void) //This procedure maps windows messages to the
  51. { //procedure which handles them.
  52. EventHandler[0].Code=WM_CREATE, EventHandler[0].fnPtr=fnWndProc_OnCreate;
  53. EventHandler[1].Code=WM_PAINT, EventHandler[1].fnPtr=fnWndProc_OnPaint;
  54. EventHandler[2].Code=WM_CLOSE, EventHandler[2].fnPtr=fnWndProc_OnClose;
  55. }
  56.  
  57.  
  58. long __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
  59. {
  60. WndEventArgs Wea; //This procedure loops through the EVENTHANDER array
  61. //of structs to try to make a match with the msg parameter
  62. for(unsigned int i=0; i<3; i++) //of the WndProc. If a match is made the event handling
  63. { //procedure is called through a function pointer -
  64. if(EventHandler[i].Code==msg) //(EventHandler[i].fnPtr). If no match is found the
  65. { //msg is passed onto DefWindowProc().
  66. Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
  67. return (*EventHandler[i].fnPtr)(&Wea);
  68. }
  69. }
  70.  
  71. return (DefWindowProc(hwnd, msg, wParam, lParam));
  72. }
  73.  
  74.  
  75. int __stdcall WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
  76. {
  77. char szClassName[]="Form1";
  78. WNDCLASSEX wc;
  79. MSG messages;
  80. HWND hWnd;
  81.  
  82. AttachEventHandlers();
  83. wc.lpszClassName=szClassName; wc.lpfnWndProc=fnWndProc;
  84. wc.cbSize=sizeof (WNDCLASSEX); wc.style=CS_VREDRAW|CS_HREDRAW;
  85. wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hInstance=hIns;
  86. wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW);
  87. wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wc.cbWndExtra=0;
  88. wc.lpszMenuName=NULL; wc.cbClsExtra=0;
  89. RegisterClassEx(&wc);
  90. hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,100,100,350,300,HWND_DESKTOP,0,hIns,0);
  91. ShowWindow(hWnd,iShow);
  92. while(GetMessage(&messages,NULL,0,0))
  93. {
  94. TranslateMessage(&messages);
  95. DispatchMessage(&messages);
  96. }
  97.  
  98. return messages.wParam;
  99. }

Sorry about the comment about the badly formatted code. Mine doesn't come through too good either.
Reputation Points: 244
Solved Threads: 31
Posting Whiz
Frederick2 is offline Offline
330 posts
since Jul 2008
Feb 1st, 2010
0
Re: Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)
Nice program... (MFC isn't it?). Thats nice . But I must get the painted region from the screen... and that's tricky cause the handler of the desktop from GetDesktopWindow() doesn't really work because it's hidden by all other top windows. Now I try to use GetDCEx(). If you have an idea I would be glad to help me...

C++ Syntax (Toggle Plain Text)
  1. hDesktop = GetDCEx(GetDesktopWindow(),CreateRectRgn(0, 0, 1280,1024),1000);
  2. hwndDesk = WindowFromDC(hDesktop);
I tried to use hwndDesk in the OnPaint event but I obtain only 0 values...
Thanks.
Reputation Points: 11
Solved Threads: 7
Posting Whiz in Training
Clawsy is offline Offline
225 posts
since Feb 2008
Feb 1st, 2010
0
Re: Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)
No, that's my own style Win32 program. I don't use MFC.

I've no experience with what you are trying to do, but I can say for absolute certainty that you can't use the WM_PAINT message of one window to draw into another. Just recently there was a post about this in the PowerBASIC forums. While I realize you are doing C++, discussions of this nature about how the Windows Api work are rather language agnostic, as the Api can be used from any number of different languages. Here is the link...

http://www.powerbasic.com/support/pb...ad.php?t=42470
Reputation Points: 244
Solved Threads: 31
Posting Whiz
Frederick2 is offline Offline
330 posts
since Jul 2008
Feb 1st, 2010
0
Re: Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)
Well, I'm not trying to paint on the screen; I'm trying to detect if something, anything new changed on the screen, anything that was painted. I wanted to do this in C# but I should understand winAPI first, in C++. For example the clock just changed. So I should get the rectangle coordonated of that part of the screen that was painted at that moment of time.
So I want to get it, not to draw it. Thx.
Reputation Points: 11
Solved Threads: 7
Posting Whiz in Training
Clawsy is offline Offline
225 posts
since Feb 2008
Feb 1st, 2010
0
Re: Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)
I've never tried it with the desktop window, but what I'm going to say might work with the desktop window, unless its some special case and is disallowed there. If you can get the hwnd of any window (and you can get the hwnd of the desktop), you can 'hook' the internal window procedure of the window by setting an address of a WNDPROC you've created in your app in the chain of window procedures windows calls when a message is destined for that window. The technique is known as subclassing, and while it sounds complicated; it isn't. You use SetWindowLong() with the GWL_WNDPROC in the 2nd parameter. In that way you might be able to retrieve the update regions from the desktop. To me, it seems pretty bizarre and I don't do stuff like that (trying to mess around with Windows Desktop), but you might look into it. Search on Window Subclassing and SetWindowLong(). If you are interested I'll dig up an example.
Reputation Points: 244
Solved Threads: 31
Posting Whiz
Frederick2 is offline Offline
330 posts
since Jul 2008
Feb 1st, 2010
0
Re: Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)
Sure I'm interested, that's what I search for a long time. On some forums others wanted to do something similar like me but it was said that Desktop Window is hidden behind everything (top windows). I actually don't even care about desktop... what I need is to detect the coordonates of "what changed in the image that I see on the screen". However none came with the idea of subclassing... I'm new to it but I will search about it and an example from you would be great. Thanks a lot!
Last edited by Clawsy; Feb 1st, 2010 at 6:04 pm.
Reputation Points: 11
Solved Threads: 7
Posting Whiz in Training
Clawsy is offline Offline
225 posts
since Feb 2008
Feb 1st, 2010
0
Re: Get the update (painted) rectangle using GetUpdateRect() in WM_PAINT (win32 api)
Well, I took a shot at it and failed. However, I'll post the code I got. What seems to be happening is that Windows isn't allowing me to subclass the desktop window. When I call GetLastError() after the call to SetWindowLong() that would set the subclass proc - here MyDesktopHook(), I'm getting the error #5 which is "ACCESS DENIED".

So my subclass isn't working. Perhaps I've a dumb error; was coding pretty fast. Anyway here's the code and I've a tutorial on subclassing here...

http://www.jose.it-berater.org/smffo...p?topic=3392.0

Check Out ProgEx40f

C++ Syntax (Toggle Plain Text)
  1. //Form1.h
  2.  
  3. typedef struct WindowsEventArguments
  4. {
  5. HWND hWnd;
  6. WPARAM wParam;
  7. LPARAM lParam;
  8. HINSTANCE hIns;
  9. }WndEventArgs, *lpWndEventArgs;
  10.  
  11.  
  12. struct EVENTHANDLER
  13. {
  14. unsigned int Code;
  15. long (*fnPtr)(lpWndEventArgs);
  16. };

C++ Syntax (Toggle Plain Text)
  1. //Main.cpp
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include "Form1.h"
  5. EVENTHANDLER EventHandler[3];
  6. WNDPROC fnDesktopProc=0;
  7. FILE* fp;
  8.  
  9. long __stdcall fnMyDesktopHook(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
  10. {
  11. if(msg==WM_PAINT)
  12. fprintf(fp,"Got WM_PAINT Message For Desktop Window!\n");
  13. else
  14. fprintf(fp,"Got Something Else!\n");
  15.  
  16. return CallWindowProc(fnDesktopProc,hwnd,msg,wParam,lParam);
  17. }
  18.  
  19.  
  20.  
  21. long fnWndProc_OnCreate(lpWndEventArgs Wea)
  22. {
  23. HWND hDesktop;
  24.  
  25. fp=fopen("Output.txt","w");
  26. fprintf(fp,"Entering fnWndProc_OnCreate()\n");
  27. fprintf(fp," Output.txt Opened In fnWndProc_OnCreate()\n");
  28. hDesktop=GetDesktopWindow();
  29. fprintf(fp," hDesktop = %u\n",hDesktop);
  30. if(hDesktop)
  31. {
  32. fnDesktopProc=(WNDPROC)SetWindowLong(hDesktop,GWL_WNDPROC,(long)fnMyDesktopHook);
  33. fprintf(fp," GetLastError() = %u\n",GetLastError());
  34. fprintf(fp," fnDesktopProc = %u\n",(unsigned)fnDesktopProc);
  35. }
  36. fprintf(fp,"Leaving fnWndProc_OnCreate()\n\n");
  37.  
  38. return 0;
  39. }
  40.  
  41. long fnWndProc_OnLButtonDown(lpWndEventArgs Wea)
  42. {
  43. RedrawWindow(NULL,NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
  44. return 0;
  45. }
  46.  
  47.  
  48. long fnWndProc_OnClose(lpWndEventArgs Wea)
  49. {
  50. HWND hDesktop;
  51. fprintf(fp,"Entering fnWndProc_OnClose()\n");
  52. hDesktop=GetDesktopWindow();
  53. if(fnDesktopProc)
  54. SetWindowLong(hDesktop,GWL_WNDPROC,(long)fnDesktopProc);
  55. DestroyWindow(Wea->hWnd);
  56. PostQuitMessage(0);
  57. fprintf(fp," Output.txt Closed In fnWndProc_OnClose()\n");
  58. fprintf(fp,"Leaving fnWndProc_OnClose()\n\n");
  59. fclose(fp);
  60.  
  61. return 0;
  62. }
  63.  
  64.  
  65. void AttachEventHandlers(void) //This procedure maps windows messages to the
  66. { //procedure which handles them.
  67. EventHandler[0].Code=WM_CREATE, EventHandler[0].fnPtr=fnWndProc_OnCreate;
  68. EventHandler[1].Code=WM_LBUTTONDOWN, EventHandler[1].fnPtr=fnWndProc_OnLButtonDown;
  69. EventHandler[2].Code=WM_CLOSE, EventHandler[2].fnPtr=fnWndProc_OnClose;
  70. }
  71.  
  72.  
  73. long __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
  74. {
  75. WndEventArgs Wea; //This procedure loops through the EVENTHANDER array
  76. //of structs to try to make a match with the msg parameter
  77. for(unsigned int i=0; i<3; i++) //of the WndProc. If a match is made the event handling
  78. { //procedure is called through a function pointer -
  79. if(EventHandler[i].Code==msg) //(EventHandler[i].fnPtr). If no match is found the
  80. { //msg is passed onto DefWindowProc().
  81. Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
  82. return (*EventHandler[i].fnPtr)(&Wea);
  83. }
  84. }
  85.  
  86. return (DefWindowProc(hwnd, msg, wParam, lParam));
  87. }
  88.  
  89.  
  90. int __stdcall WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
  91. {
  92. char szClassName[]="Form1";
  93. WNDCLASSEX wc;
  94. MSG messages;
  95. HWND hWnd;
  96.  
  97. AttachEventHandlers();
  98. wc.lpszClassName=szClassName; wc.lpfnWndProc=fnWndProc;
  99. wc.cbSize=sizeof (WNDCLASSEX); wc.style=CS_VREDRAW|CS_HREDRAW;
  100. wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hInstance=hIns;
  101. wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW);
  102. wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wc.cbWndExtra=0;
  103. wc.lpszMenuName=NULL; wc.cbClsExtra=0;
  104. RegisterClassEx(&wc);
  105. hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,100,100,350,300,HWND_DESKTOP,0,hIns,0);
  106. ShowWindow(hWnd,iShow);
  107. while(GetMessage(&messages,NULL,0,0))
  108. {
  109. TranslateMessage(&messages);
  110. DispatchMessage(&messages);
  111. }
  112.  
  113. return messages.wParam;
  114. }

I added a WM_LBUTTONDOWN handler that causes the desktop to redraw and that is working because you can see the screen flicker. However, I'm not picking anything up in the subclass proc because the call to set it is failing (Windows won't let me do it).

Unless I've got some dumb error I missed that is causing my subclass of the desktop to fail, my guess is that Windows won't allow it. However, if you are just using the desktop as an example and really have some other user created (as opposed to Windows system window) window in mind, the technique might work. However, the best you could hope for I guess would be the update region.
Last edited by Frederick2; Feb 1st, 2010 at 7:16 pm.
Reputation Points: 244
Solved Threads: 31
Posting Whiz
Frederick2 is offline Offline
330 posts
since Jul 2008

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in C++ Forum Timeline: Im having trouble with class association
Next Thread in C++ Forum Timeline: BigInteger addition





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC