Draw formatted rich text - mfc

Given a custom control CCustomWnd which has its own OnPaint method, what's the simplest way that CCustomWnd::OnPaint can render the contents of a CRichEditCtrl, with the same formatting?
To clarify, elsewhere in my dialog/window is a CRichEditCtrl. I have my custom control which does a bunch of custom-drawing, including drawing the contents of the edit control. Currently it doesn't preserve the formatting, now it needs to (not everything, but color/decoration).
The custom control can't be replaced or substantially rewritten. So essentially given a CDC and a CRichEditCtrl, how do I render the formatted text from the latter using the former?

Rich edit controls do support a couple of messages (EM_FORMATRANGE and EM_DISPLAYBAND) intended primarily for printing. I've never tried it, but offhand I can't think of any real reason they'd require that the DC refer to a printer instead of a window on screen. That being the case, you should be able to send the messages to the existing rich edit control, telling it to render the correct portion of its content to the selected rectangle in your custom control.

Can't you make a 'screenshot' (GetDC(), BitBlt() to memory DC) of the rich edit control and display that elsewhere?

Related

Add drop shadow to ListView (Icon mode)?

If you look at the thumbnail images in Windows Explorer you'll notice that they have a drop shadow, is this effect associated with the ListView control or does Windows Explorer does some extra coding to accomplish this effect?
Edit:
So it turned out that Windows uses another control. So my question now is how can I add a drop shadow to the "normal" ListView.
For a standard list view, you may want to use a technique called custom draw (https://msdn.microsoft.com/en-us/library/windows/desktop/ff919569(v=vs.85).aspx).
Basically, you ask your list view not to draw its items, but instead send you some window messages for you to draw them yourself. This is a very flexible but also troublesome technique, because you need to handle many things (like whether an item is selected/disabled, font, color etc.)
The drop shadow you see in Windows Explorer is not publicly available for you to use. So you will have to custom-draw the items (NM_CUSTOMDRAW) by yourself.
Not sure if such effect is available in GDI/GDI+, but Direct2D does have one: https://learn.microsoft.com/en-us/windows/win32/direct2d/drop-shadow

How should one retrieve the word under cursor, of current active window?

How could I retrieve the word under the cursor, on the currently active window? My thought was to use GetCursorPos() and WindowFromPoint() to get the handle, and do something, but how?
Imagine a dictionary app, which reads the text under the cursor, and give an explanation of its meaning.
EDIT
I end up use the dll from stardict, with its API hooks on text drawing.
You have to know the API needed for this; it's not obvious. You're looking for MSAA, Microsoft Active Accessibility
In short, you'll write an MSAA client. By calling AccessibleObjectFromPoint you get an IAccessible pointer. This pointer gives access to the properties of the object at the specified point.
What you are asking for is not trivial to implement.
Once you have determined which window is under the cursor (don't forget that you also need to use ChildWindowFromPoint() to drill down through nested windows), you can use GetClassName() to figure out what type of window it is.
For a standard RICHEDIT window, you can translate the screen-absolute cursor coordinates into client-relative coordinates within the window using MapWindowPoints() and then use the EM_FINDWORDBREAK, EM_EXSETSEL, and EM_GETSELTEXT messages to locate, highlight, and copy the word at the cursor coordinates.
For a standard EDIT window, once you have translated the coordinates, you can use the EM_CHARFROMPOS message to locate the character offset nearest the cursor coordinates, then use the EM_GETTEXT message for a single-line window, or the EM_LINEFROMCHAR and EM_GETLINE messages for a multi-line window (use GetWindowLong(GWL_STYLE) to test for the ES_MULTILINE style), to retreive the window's text, and then you would have to manually parse the text surrounding the character offset.
For other types of windows, especially custom controls, you have to do a lot more work, if it is even possible to get access to the window's text at all. Some windows respond to WM_GETTEXT messages and/or GetWidnowText(), while others do not.

CEditBox or CListBox which one is better for big amout of logging data

This always was a big question for me that for a very big amount of logs (like 100,000 line log) which one is better in performance, scrolling,... also consider formatting the text with color is a must.
Under the circumstances, I'd probably use a listbox.
You can create a virtual listbox to support lots of items relatively well.
Neither supports color1 but owner-drawn listboxes are easier.
Edit controls are "flow" oriented, not line oriented.
1Other than one foreground and one background color.
I've always used a read-only richedit edit control for this sort of thing because:
You can offer the ability to copy lines to the clipboard.
It is easy to add text formatting (colour, bold, italic, etc.)
Writing the data to a file is simple (you can get the text using a GetWindowText call.)

How to draw text on the desktop in Windows?

How Would I go about placing text on the windows desktop? I've been told that GetDesktopWindow() is what I need but I need an example.
I'm assuming your ultimate goal is displaying some sort of status information on the desktop.
You will have to do either:
Inject a DLL into Explorer's process and subclass the desktop window (the SysListView32 at the bottom of the Progman window's hierarchy) to paint your text directly onto it.
Create a nonactivatable window whose background is painted using PaintDesktop and paint your text on it.
First solution is the most intrusive, and quite hard to code, so I would not recommend it.
Second solution allows the most flexibility. No "undocumented" or reliance on a specific implementation of Explorer, or even of just having Explorer as a shell.
In order to prevent a window from being brought to the top when clicked, you can use the extended window style WS_EX_NOACTIVATE on Windows 2000 and up. On downlevel systems, you can handle the WM_MOUSEACTIVATE message and return MA_NOACTIVATE.
You can get away with the PaintDesktop call if you need true transparency by using layered windows, but the concept stays the same. I wrote another answer detailing how to properly do layered windows with alpha using GDI+.
Why not just draw the text in the desktop wallpaper image file?
This solution would be feasible if you don't have to update the information too often and if you have a wallpaper image.
One can easily use CImage class to load the wallpaper image, CImage::GetDC() to obtain a device context to draw into, then save the new image, and finally update the desktop wallpaper to the new image.
i haven't tried but i assume you could do the following:
use GetDesktopWindow to retrieve the handle of the desktop window
use SetWindowLong to point the windows message handler to your own procedure
in your proc, process the WM_PAINT message (or whatever) and draw what you need.
in your proc, call the original message handler (as returned by SetWindowLong).
not 100% sure it will work, but seems like it should as this is the normal way to subclass a window.
-don
If your intent is to produce something like the Sidebar, you probably just want to create one or more layered windows. That will also allow you to process mouse clicks and other normal sources of input, and if you supply the alpha channel information, Windows will make sure that your window is drawn properly at all times. If you don't want the window to be interactive, use appropriate styles (such as WS_EX_NOACTIVATE) like Koro suggests.

Simplest way to change listview and treeview colours

I'm trying to find a simple way to change the colour of the text and background in listview and treeview controls in WTL or plain Win32 code.
I really don't want to have to implement full owner drawing for these controls, simply change the colours used.
I want to make sure that the images are still drawn with proper transparency.
Any suggestions?
Have a look at the following macros:
ListView_SetBkColor
ListView_SetTextColor
TreeView_SetBkColor
TreeView_SetTextColor
There are also appropriate methods of the CListViewCtrl and CTreeViewCtrl wrapper classes:
GetBkColor
SetBkColor
You may also want to take a look at WTL's CCustomDraw::OnItemPrePaint (that's if you need to control the drawing of individual items)
A good article that describes this process is here
It's been a while since I've use the win32 API directly, but I believe that if you handle the WM_ERASEBACKGROUND message for your control, you can use FillRect() in your handler to paint the background using whatever color you like.