C++ DrawText And TextOut Displaying Nothing - c++

Where do I use TextOut or DrawText?
TCHAR text[]= "My First Window";
RECT rc;
HDC wdc = GetWindowDC(hWnd);
GetClientRect (hWnd, &rc);
SetTextColor(wdc, 0x00000000);
SetBkMode(wdc,TRANSPARENT);
rc.left=40;
rc.top=10;
TextOut(hdc,rc.left,rc.top,text,ARRAYSIZE(text));
EndPath(hdc);
SelectClipPath(hdc, RGN_AND);
I'm placing this in WM_CREATE:
The result is a blank window. I can provide more code if need be, but it's just a standard Win32 blank window.
This is my first real Win32 application and I've googled and searched for an hour without finding the answer to my question.
Thank you

Windows doesn't work like that. You can't just paint once and expect what you painted to be displayed forever. Your window probably isn't even visible when WM_CREATE is handled.
(as an aside, you are also leaking wdc in the above code, and interchanging wdc with hdc).
You need to handle the WM_PAINT message and do your painting in there. Call BeginPaint() to get an HDC that you can draw on, and call EndPaint() when finished.
You should get a beginner's book in Win32 programming as handling WM_PAINT is pretty basic stuff. Start with the MSDN documentation:
Painting and Drawing

Related

MFC Draw Stuff Outside OnPaint in a Dialog-based App

I'm currently trying to draw something outside OnPaint function. I know there are many duplicate questions on the internet, however, I failed to get any of them to work. This is entirely because of my lack of understanding of MFC.
What works inside OnPaint:
CDC* pDC = GetDC();
HDC hDC = pDC->GetSafeHdc();
CRect lDisplayRect;
GetDlgItem(IDC_DISPLAYPOS)->GetClientRect(&lDisplayRect);
GetDlgItem(IDC_DISPLAYPOS)->ClientToScreen(&lDisplayRect);
ScreenToClient(&lDisplayRect);
pDC->FillSolidRect(&lDisplayRect, GetSysColor(COLOR_3DDKSHADOW));
pDC->TextOutW(300, 300, TEXT("test"));
It fills the area of the button control I have with a defined colour.
And it prints out the "test" string without any issue.
But it won't work outside OnPaint.
I've seen numerous suggestions such as using CmemDC,CPaintDC, etc
But none of them worked outside OnPaint.
For example,
CClientDC dc(this);
dc.rectangle( ....);
does not work.
Please note that this is a temporary test code and what I am eventually trying to do is draw incoming frames from a frame grabber within my display thread (a separate thread from the main UI thread) on the DisplayPos area and my dlg object(the dialog) owns an instance of the DisplayThread class. And I'm passing HWND and displayrect upon creating the member mDisplayThread so I can draw stuff within the display thread and that's the reason why I need to be able to draw to DC outside OnPaint (DisplayThread class does not have OnPaint or inherit any class that has it).
I'm in dire need of help...Please help!
Added: I have overridden PreTranslateMessage(MSG* pMsg) and made it return without calling the default function just in case WM_ERASE msg is erasing everything, but this approach didn't work either.
For example:
void CMFCApplicationDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
HDC hdc = ::GetDC(m_hWnd);
Ellipse(hdc, point.x - 10, point.y - 10, point.x + 10, point.y + 10);
::ReleaseDC(m_hWnd, hdc);
CDialogEx::OnLButtonDown(nFlags, point);
}
Two important suggestions:
Do not draw outside of OnPaint. The content may be erased or painted over at the direction of OS.
Do not draw on the dialog surface. First, it is not designed for that. It may be affected by other controls or by theming, skinning, etc. Just create a window with your own window procedure, so you are in control.
I would store the information needed for drawing in you frame grabber, and cause an immediate window painting by calling RedrawWindow

Capturing invisible window with win32 API

Trying to capture contents of windows using BitBlt. In this particular case, which is probably important, i am speaking of invisible windows/invisible areas on windows - invisible because of z-order, they are visible but covered with other windows. All i get is a black box.
HDC winDC = GetWindowDC(hwnd);
HDC hdc_offscreen = CreateCompatibleDC(winDC);
HBITMAP bmp = CreateCompatibleBitmap(winDC, areaWidth, areaHeight);
HGDIOBJ origHandle = SelectObject(hdc_offscreen, bmp);
BitBlt(hdc_offscreen, rect.left, rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
winDC, copy_from.left, copy_from.top, SRCCOPY);
// at this point i expect pixels to be there, but nah!
ReleaseDC(hwnd, winDC);
SelectObject(hdc_offscreen, origHandle);
DeleteDC(hdc_offscreen);
ReleaseDC(hWnd_main, winDC);
hwnd is the window i am trying to capture. Same things works like a charm with Aero theme enabled. I am using Windows 7 Professional.
Any idea what i am missing?
Your best bet (though it's not guaranteed to work) is to ask the other window to paint itself to your DC by sending it WM_PRINT.
HDC returned by GetWindowDC just doesn't contain a window's image. I can imagine that this HDC refers to the same "bitmap" as other windows. When Aero enabled, they apparently doesn't share the same "bitmap" and that's why you get a good result.
I would rather try to force window to paint to your HDC instead of reading HDC returned by GetWindowDC. To get client area you can try to call BeginPaint with your HDC, but who knows what if a window will check whether it (or it's part) is visible or not?
To get non client area you could pass WM_NCPAINT with your HDC.
Standard controls support HDC passed with WM_PAINT. Other windows may support it, but it's not required. If I remember correctly PrintWindow relies on this behavior.
In general I would say that no a 100% way to get a window's image but BeginPaint and WM_NCPAINT should be a good point of start.

screenshots of covered/minimized windows

I have the following code to take screenshots of a window:
HDC WinDC;
HDC CopyDC;
HBITMAP hBitmap;
RECT rt;
GetClientRect (hwnd, &rt);
WinDC = GetDC (hwnd);
CopyDC = CreateCompatibleDC (WinDC);
hBitmap = CreateCompatibleBitmap (WinDC,
rt.right - rt.left, //width
rt.bottom - rt.top);//height
SelectObject (CopyDC, hBitmap);
//Copy the window DC to the compatible DC
BitBlt (CopyDC, //destination
0,0,
rt.right - rt.left, //width
rt.bottom - rt.top, //height
WinDC, //source
0, 0,
SRCCOPY);
ReleaseDC(hwnd, WinDC);
ReleaseDC(hwnd, CopyDC);
It is someone elses code, slightly modified, as I am not really familiar with DC and how windows draws stuff to screen.
When I have one window slightly covering another, the covering window appears on screenshots of the covered one, which is kind of inconvenient. Also, when the window is minimized, this code produces nothing much interesting.
Is there any way around this? I would imagine that taking screenshots of a minimized application would be quite difficult, but I hope that getting screenshots of covered windows is possible. Perhaps there is a different method of implementing this to get around these problems?
No, a screenshot is exactly what it sounds like. You'll read the pixels out of the video adapter, what you get is what you see. You'll have to restore the window and bring it to the foreground to get the full view. WM_SYSCOMMAND+SC_RESTORE and SetForegroundWindow() respectively. Plus some time to allow the app to repaint its window if necessary.
The WM_PRINT message is available to ask a window to draw itself into a memory context. That could handle the overlapped window problem. But that can only work if is your window. And rarely has the expected result, programmers don't often implement WM_PRINT correctly.

Get Thumbnail of background window

I'm trying to get thumbnail pictures of windows that are not visible.
Here's the code I have so far
BOOL CALLBACK WindowProc(HWND hWnd, LPARAM lParam)
{
RECT WindRect;
GetWindowRect(hWnd, &WindRect)
CurrentScreenShot->Next = new ScreenShotList();
CurrentScreenShot = CurrentScreenShot->Next;
HDC SourceDC = GetDC(hWnd);
HDC TargetDC = CreateCompatibleDC(SourceDC);
CurrentScreenShot->ScreenShot = CreateCompatibleBitmap(SourceDC, WindRect.right - WindRect.left, WindRect.bottom - WindRect.top);
BitBlt(TargetDC, 0, 0, WindRect.right - WindRect.left, WindRect.bottom - WindRect.top, SourceDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd, SourceDC);
g_iWindows++;
return TRUE;
}
For now, WindowProc is being called directly using FindWindow to get a handle, though, I eventually want to use EnumWindows to loop through all of the windows to get their thumbnails and store them in a linked list.
WindowProc(FindWindow(NULL, L"File Explorer"), 0);
This code is in a DLL, which is called from a C# Forms application. For now the C# application just takes the bitmap and saves it to a file.
The problem is that unless I use FindWindow to get the visible window (which also happens to be the C# application), the picture ends up being a black box.
Is it possible to get an picture of a background window?
EDIT: This is a Windows Mobile application
There is no redrawing going on for invisible Windows, thats why you cannot get their content from the DC. Try sending a WM_PRINT message to the target window to request that it draws its content to your DC.
Edit:
Sorry, i did not notice this was for Windows Mobile. Other than WM_PRINT, i don't know a way to get the content of an invisible window. Of course you can still show the window (and make sure it is on top / not covered by other windows) and then run the code you have, but thats probably a bit messy.

How to draw in the nonclient area?

I'd like to be able to do some drawing to the right of the menu bar, in the nonclient area of a window.
Is this possible, using C++ / MFC?
Charlie hit on the answer with WM_NCPAINT. If you're using MFC, the code would look something like this:
// in the message map
ON_WM_NCPAINT()
// ...
void CMainFrame::OnNcPaint()
{
// still want the menu to be drawn, so trigger default handler first
Default();
// get menu bar bounds
MENUBARINFO menuInfo = {sizeof(MENUBARINFO)};
if ( GetMenuBarInfo(OBJID_MENU, 0, &menuInfo) )
{
CRect windowBounds;
GetWindowRect(&windowBounds);
CRect menuBounds(menuInfo.rcBar);
menuBounds.OffsetRect(-windowBounds.TopLeft());
// horrible, horrible icon-drawing code. Don't use this. Seriously.
CWindowDC dc(this);
HICON appIcon = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
::DrawIconEx(dc, menuBounds.right-18, menuBounds.top+2, appIcon, 0,0, 0, NULL, DI_NORMAL);
::DestroyIcon(appIcon);
}
}
In order to draw in the non-client area, you need to get the "window" DC (rather than "client" DC), and draw in the "window" DC.
You should try handling WM_NCPAINT. This is similar to a normal WM_PAINT message, but deals with the entire window, rather than just the client area. The MSDN documents on WM_NCPAINT provide the following sample code:
case WM_NCPAINT:
{
HDC hdc;
hdc = GetDCEx(hwnd, (HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN);
// Paint into this DC
ReleaseDC(hwnd, hdc);
}
This code is intended to be used in the message loop of your applicaton, which is canonically organized using a large 'switch' statement.
As noted in the MFC example from Shog, make sure to call the default version, which in this example would mean a call to DefWindowProc.
If you just want something in the menu bar, maybe it is easier/cleaner to add it as a right-aligned menu item. This way it'll also work with different Windows themes, etc.