• Welcome to Valhalla Legends Archive.
 

Clearing a Device context of output in GDI

Started by Dyndrilliac, September 29, 2008, 04:16 AM

Previous topic - Next topic

Dyndrilliac

Recently I have been trying to print the mouse cursor's coordinates just below and to the right of the cursor and have it update in real time, regardless of what windows have focus. I am using GDI to draw the text on screen, and a Mouse Hook to get the coordinates.

This code seems to work, save for one minor glitch:#define VC_EXTRALEAN

#include <windows.h>
#include <stdio.h>

void MyInit();
void MyCleanUp();
void DrawCoords(const long X, const long Y);

static char    Buffer[256];
static HDC     MyHDC;

void MyInit() {

MyHDC = GetDC(NULL);

}

void MyCleanUp() {

ReleaseDC(NULL, MyHDC);

}

void DrawCoords(const long X, const long Y) {

ZeroMemory(Buffer,sizeof(Buffer));
SetBkColor(MyHDC,RGB(0,0,0));
SetTextColor(MyHDC,RGB(255,0,0));
sprintf_s<256>(Buffer,"[X: %i, Y: %i]",X,Y);
TextOutA(MyHDC,(X+10),(Y-10),Buffer,strlen(Buffer));

}
The glitch is that the old text strings aren't being removed automatically, and as you move the cursor eventually the screen gets covered in output. I have tried getting the device context just before drawing and releasing it right after, but it didn't work. Here is how/where I am calling the Drawing fxn:LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {

MOUSEHOOKSTRUCT MyMHS = *(MOUSEHOOKSTRUCT*)lParam;

DrawCoords(MyMHS.pt.x,MyMHS.pt.y);

return (CallNextHookEx(hMseHook,nCode,wParam,lParam));

}
I need a way to clear away old ouput prior to drawing new ouput. Any suggestions?
Quote from: Edsger W. DijkstraIt is practically impossible to teach good programming to students that have had a prior exposure to BASIC; as potential programmers they are mentally mutilated beyond hope of regeneration.

Ringo

#1
I'm pretty sure you need to use the RedrawWindow() api.

Add the static RECT structure, and try the following:

static RECT rt;

void DrawCoords(const long X, const long Y) {

    ZeroMemory(Buffer,sizeof(Buffer));
    SetBkColor(MyHDC,RGB(0,0,0));
    SetTextColor(MyHDC,RGB(255,0,0));
    sprintf_s<256>(Buffer,"[X: %i, Y: %i]",X,Y);
    RedrawWindow(0,rt,0,(int)0x81);
    sleep(0);
    rt.left=X+10;
    rt.top=Y-10;
    rt.right=rt.left+50;
    rt.bottom=rt.top+20;
    TextOutA(MyHDC,rt.left,rt.top,Buffer,strlen(Buffer));

}

im not sure vb6's "doevents" in c++, so I just put a sleep(0) there.
I would think it's a good idea to pause a tiny bit, to allow the screen to update, before drawing text -- otherwise RedrawWindow() might draw over you're newly drawn text.
hope this helps

Yegg

AFAIK, sleep(0) won't do anything. There is no need for a DoEvents equivalent.

brew

#3
In my experience, RedrawWindow() won't redraw overdrawn regions of the screen unless you specify RDW_INVALIDATE, which would set the rect of the window as invalidated. For your situation I would instead recommend using InvalidateRect() which has the same effect, but only for the specified rect.

@Yegg: Specifying 0 milliseconds in a call to Sleep() would just force the scheduler to move onto the next thread, equivalent in function to SwitchToThread(). Go figure..

EDIT*

I just looked in my WinUser.h, and it seems that Ringo is indeed calling RedrawWindow with flags of RDW_INVALIDATE | RDW_ALLCHILDREN.

...
/*
* RedrawWindow() flags
*/
#define RDW_INVALIDATE          0x0001
#define RDW_INTERNALPAINT       0x0002
#define RDW_ERASE               0x0004

#define RDW_VALIDATE            0x0008
#define RDW_NOINTERNALPAINT     0x0010
#define RDW_NOERASE             0x0020

#define RDW_NOCHILDREN          0x0040
#define RDW_ALLCHILDREN         0x0080
...
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

Dyndrilliac

#4
Ok this code works absolutely perfectly, except there is some god awful flickering going on.void DrawCoords(const long X, const long Y) {

ZeroMemory(Buffer,sizeof(Buffer));
HDC MyHDC = GetDC(NULL);
RECT MyRect;
MyRect.top = Y-5;
MyRect.left = X+5;
MyRect.bottom = Y-40;
MyRect.right = X+40;
InvalidateRect(NULL, &MyRect,false);
SetBkColor(MyHDC,RGB(0,0,0));
SetTextColor(MyHDC,RGB(255,0,0));
sprintf_s<256>(Buffer,"{X: %i,Y: %i}",X,Y);
TextOutA(MyHDC,(X+10),(Y-10),Buffer,strlen(Buffer));
ReleaseDC(NULL, MyHDC);

}

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {

if (nCode == HC_ACTION) {
MOUSEHOOKSTRUCT MyMHS = *(MOUSEHOOKSTRUCT*)lParam;
DrawCoords(MyMHS.pt.x,MyMHS.pt.y);
}

return (CallNextHookEx(hMseHook,nCode,wParam,lParam));

}
Keep in mind im using global mouse hook. Is there any way to get the window thread id of the parent hwnd for the process with only the process handle or process id?
Quote from: Edsger W. DijkstraIt is practically impossible to teach good programming to students that have had a prior exposure to BASIC; as potential programmers they are mentally mutilated beyond hope of regeneration.

Ringo

Quote from: brew on September 29, 2008, 02:11 PM
For your situation I would instead recommend using InvalidateRect() which has the same effect, but only for the specified rect.

RedrawWindow() can also redraw a given rect, if given one -- leaving the handle to the window as null, will redraw the screen by defalt. If you don't supply a rect, or a handle to the area of the screen/window you want redrawn, then it will redraw the whole screen/window.


Quote from: Dyndrilliac on September 29, 2008, 10:48 PM
Ok this code works absolutely perfectly, except there is some god awful flickering going on.
Try useing sleep(0) right after you redraw the screen -- that should stop it.
When I tested it with VB6, RedrawWindow worked fine for me, but if I didn't make a call to doevents() it would flicker/redraw over the text.
Try sleep(0).

You could also draw the cords on a loop useing the GetCursorPos() api, which is what I did when I tested this.
Just be sure to compare the result of GetCursorPos() with the cords of the last redraw  -- if they are not the same, then draw, other wise don't.

Somthing like:
GetCursorPos(pos)
If(lpos.x==pos.x && lpos.y==pos.y) return;
lpos=pos
setbackcolor
settextcolor
redrawwindow
sleep(0)
textoutA

Win32

Quote
im not sure vb6's "doevents" in c++, so I just put a sleep(0) there.
LOL. Doesn't get any more clueless than that.

Ringo

Quote from: Win32 on October 23, 2008, 07:01 PM
LOL. Doesn't get any more clueless than that.
Doesn't get any less constructive than that.
I hope you're aware, the vb6 rtcDoEvents function is not like that of the C++ equivalent DoEvents.
The one in the vb6 runtime dll make's a call to sleep, where as C++ does not.
Since the idea is, to allow the system to redraw an area of the screen before you draw over it, rather than having it redraw the screen after you have drawn the text, sleep(0) seemed like a reassionable option.

Go check MSDN:
Quote from: DoEvents@msdn
Unlike Visual Basic 6.0, the DoEvents method does not call the Sleep method.
Quote from: Sleep@msdn
Specify zero (0) to indicate that this thread should be suspended to allow other waiting threads to execute.

brew

Quote from: Win32 on October 23, 2008, 07:01 PM
Quote
im not sure vb6's "doevents" in c++, so I just put a sleep(0) there.
LOL. Doesn't get any more clueless than that.
...

rtcDoEvents:

.text:73447EDF                 push    esi
.text:73447EE0                 push    edi
.text:73447EE1                 call    _HostDoEvents@0 ; HostDoEvents()
.text:73447EE6                 mov     esi, eax
.text:73447EE8                 xor     edi, edi
.text:73447EEA
.text:73447EEA loc_73447EEA:                           ; CODE XREF: rtcDoEvents()+1B038
.text:73447EEA                 cmp     esi, 0FFFFFFFFh
.text:73447EED                 jz      loc_73462F1C
.text:73447EF3                 cmp     dword_73531340, edi
.text:73447EF9                 jnz     loc_73462F10
.text:73447EFF
.text:73447EFF loc_73447EFF:                           ; CODE XREF: rtcDoEvents()+1B043
.text:73447EFF                 mov     eax, hMem
.text:73447F04                 cmp     eax, edi
.text:73447F06                 jnz     loc_73462F2D
.text:73447F0C
.text:73447F0C loc_73447F0C:                           ; CODE XREF: rtcDoEvents()+1B049
.text:73447F0C                                         ; rtcDoEvents()+1B073
.text:73447F0C                 push    edi             ; dwMilliseconds
.text:73447F0D                 call    ds:__imp__Sleep@4 ; Sleep(x)
.text:73447F13                 mov     ax, si
.text:73447F16                 pop     edi
.text:73447F17                 pop     esi
.text:73447F18                 retn
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P