how to clear dialog picture control type=frame - winapi

I have a dialog picture control of type = frame that I've used as a parent for something else.
When the child window is destroyed, the remnants are left in the control. What can I do to either clear the control or cause the demise of the child window to clear the control?
winapi c++

I thought there might be a simpler method but the following does the trick and allows you to color it however you like.
int s;
HDC dc;
RECT R;
z = GetDlgItem (hDlg, IDC_PS_AREA); // clear the containing control
dc = GetWindowDC (z);
s = GetClientRect (z,&R);
FillRect (dc, &R, (HBRUSH) GetStockObject (LTGRAY_BRUSH));
ReleaseDC (z, dc);
And even better
int s;
HDC dc;
RECT R;
HBRUSH hB;
z = GetDlgItem (hDlg, IDC_PS_AREA); // clear the parent containing control
dc = GetWindowDC (z);
s = GetClientRect (z,&R);
hB = GetSysColorBrush (COLOR_3DFACE);
FillRect (dc, &R, hB);
ReleaseDC (z, dc);

Related

WinApi, disabling all controls in a rect area

Is there an api to disable all controls in a rect area?
I am trying to write something like that:
GetClientRect(hWnd, rect);
DisableControls(rect);
GetClientRect gets the client area (left and top are always 0), you need to use GetWindowRect to figure out where a child window is.
All child controls are in the client area and you can just disable the parent window and all children will also stop accepting input.
It does seem a little contrived to disable based on a rectangle instead of a list of known controls but I suppose it might be useful in some cases.
static BOOL CALLBACK DisableChildrenInRectProc(HWND hWnd, LPARAM Param)
{
RECT *pParentRect = (RECT*) Param, r, ir;
if (GetWindowRect(hWnd, &r) && IntersectRect(&ir, &r, pParentRect))
{
EnableWindow(hWnd, FALSE);
}
return TRUE;
}
HWND hWnd = ...
RECT r;
GetWindowRect(hWnd, &r);
r.bottom = r.top + (r.bottom - r.top) / 2; // In this example, only disable controls in the top half.
EnumChildWindows(hWnd, DisableChildrenInRectProc, (LPARAM) &r);
I don't believe there is one. Use EnumChildWindows, GetWindowRect and some coordinate mapping via ScreenToClient. For overlap testing you could use IntersectRect.

Handling Window Movement after setting GWL_STYLE to 0

i want to have a border and title less window so i do SetWindowLongPtrW( window_handle, GWL_STYLE, 0 );
After that i can't move my Window so in my WndProc i do
if( message == WM_NCHITTEST ) {
RECT rc;
GetClientRect( hwnd, &rc );
MapWindowPoints( hwnd, GetParent( hwnd ), (LPPOINT)&rc, 2 );
int mouseX = LOWORD( lParam ) - rc.left;
int mouseY = HIWORD( lParam ) - rc.top;
POINT p;
p.x = mouseX;
p.y = mouseY;
return PtInRect( &rc, p ) ? HTCAPTION : DefWindowProc( hwnd, message, wParam, lParam );
}
It works, the first time i move the window. After i once stop clicking with the mouse it won't move again :/
SetWindowLongPtrW( window_handle, GWL_STYLE, 0 ); will hide the window, assuming it doesn't cause more serious problems. Use GetWindowLongPtr and combine that with valid window styles, or hide the window using ShowWindow
The error you have described is unrelated. You are attempting to find the screen coordinates of the window using GetClientRect and MapWindowPoints. The result will not be exact because the window may have borders and title bar.
Use GetWindowRect instead. This will give you screen coordinates of the window.
You can compare that with the mouse position LOWORD(lParam) and HIWORD(lParam). This is already screen coordinates. This code will move the screen every where the mouse lands in window:
RECT rc;
GetWindowRect(hwnd, &rc);
int mouseX = LOWORD(lparam);
int mouseY = HIWORD(lparam);
Don't subtract rc.left and rc.top from mouse position. That would convert the coordinates in client coordinates (roughly). Your code may work when window is on top-left corner of the screen, but it won't work later when window is moved.
Use ScreenToClient if you wish to work in client window coordinates.

Drawing peformance with Win32

I am getting a very poor peformance drawing with Win32. It takes too much time and needs improving. Please advise.
Here is what I do.
HDC dc = GetDC(wnd);
HDC memoryDc = CreateCompatibleDC(dc);
HBITMAP memoryMapBitmap = CreateCompatibleBitmap(dc, 400, 400);
HGDIOBJ originalBitmap = SelectObject(memoryDc, memoryMapBitmap);
Then, I draw in a for-loop as follows.
HBRUSH brush = (HBRUSH)GetStockObject(DC_BRUSH);
SetDCBrushColor(memoryDc, colorRef);
FillRect(memoryDc, &rect, brush);
And finally, I do a cleanup
SelectObject(memoryDc, originalBitmap);
DeleteDC(memoryDc);
ReleaseDC(wnd, dc);
Drawing takes a lot of time (several seconds). Is there a way to draw faster with Win32?
Thanks in advance!
It looks like I have solved it. Below is the solution with some comments.
I have a dialog defined in RC-file. There is a control to display a bitmap image in the dialog.
CONTROL "", IDC_MEMORY_MAP, WC_STATIC, SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN, 9, 21, 271, 338, WS_EX_LEFT
In the run-time I need to create, draw and display a bitmap:
HWND map = GetDlgItem(dlg, IDC_MEMORY_MAP);
HBITMAP bitmap = createMemoryMapBitmap(map);
bitmap = (HBITMAP)SendMessage(map, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bitmap);
DeleteObject(bitmap); // (!) this is a very important line, otherwise old bitmap leaks
Code that finds out the size of the bitmap to create:
HBITMAP createMemoryMapBitmap(HWND map) {
RECT rect = {0, 0, 0, 0};
GetClientRect(map, &rect);
SIZE size = {rect.right - rect.left, rect.bottom - rect.top};
HDC dc = GetDC(map);
HBITMAP bitmap = doCreateMemoryMapBitmap(dc, &size);
ReleaseDC(map, dc);
return bitmap;
}
Finally, we actually create the bitmap and draw on it:
HBITMAP doCreateMemoryMapBitmap(HDC dc, LPSIZE bitmapSize) {
// create 24bpp bitmap in memory in order to draw fast
BITMAPINFO info;
memset(&info, 0, sizeof(info));
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth = bitmapSize->cx;
info.bmiHeader.biHeight = bitmapSize->cy;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 24;
info.bmiHeader.biCompression = BI_RGB;
void *pixels = NULL;
HBITMAP memoryBitmap = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &pixels, NULL, 0);
HDC memoryDc = CreateCompatibleDC(dc); // (!) memoryDc is attached to current thread
HGDIOBJ originalDcBitmap = SelectObject(memoryDc, memoryBitmap);
// drawing code here
// perform windows gdi cleanup
SelectObject(memoryDc, originalDcBitmap); // restore original bitmap in memoryDC (optional step)
DeleteDC(memoryDc); // this releases memoryBitmap from memoryDC
return memoryBitmap;
}
The idea above is to create a 24bpp bitmap in the memory and draw on it. This way drawing is fast, as #IInspectable pointed out.
If display is in the indexed color mode, e.g. 16 or 256 colors, it seems Windows native control is smart enough to convert the color depth automatically displaying the bitmap.

how to use ScreenToClient in win32, not MFC?

As MSDN said
BOOL ScreenToClient(
_In_ HWND hWnd,
LPPOINT lpPoint
);
the ScreenToClient's second para is a pointer to POINT,
and PINT said by MSDN is
typedef struct tagPOINT {
LONG x;
LONG y;
} POINT, *PPOINT;
it has only x and y. It's NOT like MFC ScreenToClient function, the para is a rect, and rect has width and height.
I am confused how to use win32 ScreenToClient function.
You can use MapWindowPoints() to convert a RECT in a single operation:
RECT r = ...;
MapWindowPoints(NULL, hWnd, (LPPOINT)&r, 2);
MFC actually has two methods, they're overloaded. One accepts a POINT structure, just like the Win32 function, the other accepts a RECT structure, both work the same way: it maps each point from screen-to-client.
If you have a RECT that you want to get client coordinates of without using MFC then just do it manually, like so:
RECT rect = GetMyRect();
POINT rectTL;
rectTL.x = rect.left;
rectTL.y = rect.top;
ScreenToClient( hWnd, &rectTL );
POINT rectBR;
rectBR.x = rect.right
rectBR.y = rect.bottom;
ScreenToClient( hWnd, &rectBR );
rect.left = rectTL.x;
rect.top = rectTL.y;
rect.right = rectBR.x;
rect.bottom = rectBR.y;
Note that RECT is
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
and looks like two consecutive POINTs in memory. Therefore you can do what the MFC source code does, which is approx. the following (don't have the MFC source in front of me right now):
::ScreenToClient(hWnd, (POINT*)&rect->left);
::ScreenToClient(hWnd, (POINT*)&rect->right);
which is not the cleanest thing from a C point of view, but those structures are bound to remain binary compatible.

Capture screen shot with mouse cursor

I have used the following code to get screen shot on Windows.
hdcMem = CreateCompatibleDC (hdc) ;
int cx = GetDeviceCaps (hdc, HORZRES);
int cy = GetDeviceCaps (hdc, VERTRES);
HBITMAP hBitmap(NULL);
hBitmap = CreateCompatibleBitmap (hdc, cx, cy) ;
SelectObject (hdcMem, hBitmap) ;
BitBlt(hdcMem, 0, 0, cx, cy, hdc, 0, 0, SRCCOPY);
However, the mouse cursor doesn't show up.
How could I get the cursor? or Is there a library can do that?
Thanks in advance.
After your BitBlt and before you select the bitmap back out of hdcMem, you can do this:
CURSORINFO cursor = { sizeof(cursor) };
::GetCursorInfo(&cursor);
if (cursor.flags == CURSOR_SHOWING) {
RECT rcWnd;
::GetWindowRect(hwnd, &rcWnd);
ICONINFOEXW info = { sizeof(info) };
::GetIconInfoExW(cursor.hCursor, &info);
const int x = cursor.ptScreenPos.x - rcWnd.left - rc.left - info.xHotspot;
const int y = cursor.ptScreenPos.y - rcWnd.top - rc.top - info.yHotspot;
BITMAP bmpCursor = {0};
::GetObject(info.hbmColor, sizeof(bmpCursor), &bmpCursor);
::DrawIconEx(hdcMem, x, y, cursor.hCursor, bmpCursor.bmWidth, bmpCursor.bmHeight,
0, NULL, DI_NORMAL);
}
The code above figures out if the cursor is showing, using the global cursor state since you're probably taking a screenshot of a window (or windows) in another process. It then gets the target window coordinates for adjusting from screen. It gets specific info about the cursor, including its hotspot. It computes the drawing position of the icon. Finally, it gets the actual size of the cursor icon so that it can draw it without any stretching.
The only limitations to this approach that I know of are:
You don't get cursor shadows if you have them enabled.
If it's an animated cursor, this just shows the first frame. As far as I know, there's no way to determine the current frame.

Resources