I added a feature to one of my programs recently and noticed something very odd. The feature required me to add a new tab to the tab control I am using. This then pushed the tabs past what could be displayed on the form with default sizes requiring the arrows to navigate the tabs on the tab control.
The problem I discovered is that if these arrows on the tab control exist, the tabControl1_DrawItem event was firing every few milliseconds causing the program to become sluggish and use about 15% to 20% CPU when just sitting there doing nothing after the form load event.
Once I increased the form size so the arrows didn't exist, the event only fired when the form was moved or a different tab was selected.
I searched all day for this and debugged and found the answer or I guess you can say workaround, but not here. So I guess I have two questions. Why does the event fire constantly if the arrows exist, and is there anything possible to prevent it from doing this since I am not able to prevent users of the application from resizing the form and make this happen?
This is the code I have under the event.
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Platform.Log(LogLevel.Debug, "DrawItem event is being called.");
//Draw the tabs on the tab conrol
e.DrawBackground();
using (Brush br = new SolidBrush(TabColors[tabControl1.TabPages[e.Index]]))
{
e.Graphics.FillRectangle(br, e.Bounds);
SizeF sz = e.Graphics.MeasureString(tabControl1.TabPages[e.Index].Text, e.Font);
e.Graphics.DrawString(tabControl1.TabPages[e.Index].Text, e.Font, DGVBrushForeColor, e.Bounds.Left + (e.Bounds.Width - sz.Width) / 2, e.Bounds.Top + (e.Bounds.Height - sz.Height) / 2 + 1);
Rectangle rect = e.Bounds;
rect.Offset(0, 1);
rect.Inflate(0, -1);
e.Graphics.DrawRectangle(DGVPenBackColor, rect);
e.DrawFocusRectangle();
}
//To Fill the blank portion of the end of the tab control
SolidBrush fillbrush = new SolidBrush(BACK_COLOR);
//draw rectangle behind the tabs
Rectangle lasttabrect = tabControl1.GetTabRect(tabControl1.TabPages.Count - 1);
Rectangle background = new Rectangle();
background.Location = new Point(lasttabrect.Right, 0);
//pad the rectangle to cover the 1 pixel line between the top of the tabpage and the start of the tabs
background.Size = new Size(tabControl1.Right - background.Left, lasttabrect.Height + 1);
e.Graphics.FillRectangle(fillbrush, background);
}
The answer was found thanks to Hans Passant's help. I implemented this code found here on stackoverflow in my application.
public Form1()
{
InitializeComponent();
int style = NativeWinAPI.GetWindowLong(this.Handle, NativeWinAPI.GWL_EXSTYLE);
style |= NativeWinAPI.WS_EX_COMPOSITED;
NativeWinAPI.SetWindowLong(this.Handle, NativeWinAPI.GWL_EXSTYLE, style);
}
internal static class NativeWinAPI
{
internal static readonly int GWL_EXSTYLE = -20;
internal static readonly int WS_EX_COMPOSITED = 0x02000000;
[DllImport("user32")]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32")]
internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
}
This is what caused the problem with the draw event firing constantly when the tab navigation arrows where present. To solve the problem I set the Multiline property of the tab control to true. This prevents the navigation arrows from showing up and it is acceptable to have multiple rows of tabs for me.
I also want to note that without this code the problem does not happen, but the tabs flicker constantly and crazy without the "WS_EX_COMPOSITED hack" as Hans called it. With double buffering everything using this hack, it makes everything work well so it is staying in there for now in this application.
Related
I have a problem that is really confusing me. Let me lay some background. I am trying to develop my own Editor Control. I wish to have a blinking caret, I know I can do this using CreateCaret, ShowCaret ect but this is not how I wish to do it, I wish to implement this myself. My caret does not blink and I cant understand why.
The way I'm trying to implement this is by caching the area below the caret and then display the caret. Then half a second later I repaint the cached data back to the Editor Control therefore effecting a flashing caret. I have tried using just a Graphics Object and a Bitmap for the cache neither worked but I think I know why. So I decided to experiment. I set up one Panel on the Form itself through the Designer and one is handed coded into the Caret class itself. The Panel on the Form works but the Panel encapsulated within the class doesn't and I don't know why. My question is why?
Below is the Code. The BlinkTimer_Tick method just causes the Blink. Paint just Paints the caret, none of this should be hard to understand.
BackupBackground copies the area below the Caret to the cache, while RestoreBackground copies the cache to the Control. Now the problem is if you comment out the lines commented with "Works if this line is commented out" in both methods it all works but when these are not commented it doesn't work the caret does not blink. Both these Panels are set up the same.
private void BlinkTimer_Tick(object sender, EventArgs e)
{
Paint();
_BlinkTimer.Start();
}
private void BackupBackground(Graphics SrcGraph)
{
Form TF = _Parent.FindForm() as Form;
Panel P = TF.Controls["_TestPanel"] as Panel;
P = _Buffer; // Works if this line is Commentted out
Graphics DestGraph = P.CreateGraphics();
IntPtr SrcHDC = SrcGraph.GetHdc();
IntPtr DestHDC = DestGraph.GetHdc();
BitBlt(DestHDC, 0, 0, _Size.Width, _Size.Height,
SrcHDC, _Location.X, _Location.Y, TernaryRasterOperations.SRCCOPY);
DestGraph.ReleaseHdc(DestHDC);
SrcGraph.ReleaseHdc(SrcHDC);
}
private void RestoreBackground(Graphics DestGraph)
{
Form TF = _Parent.FindForm() as Form;
Panel P = TF.Controls["_TestPanel"] as Panel;
P = _Buffer; // Works if this line is Commentted out
Graphics SrcGraph = P.CreateGraphics();
IntPtr SrcHDC = SrcGraph.GetHdc();
IntPtr DestHDC = DestGraph.GetHdc();
BitBlt(DestHDC, _Location.X, _Location.Y, _Size.Width, _Size.Height,
SrcHDC, 0, 0, TernaryRasterOperations.SRCCOPY);
DestGraph.ReleaseHdc(DestHDC);
SrcGraph.ReleaseHdc(SrcHDC);
}
internal void Paint()
{
Graphics Graph = _Parent.CreateGraphics();
if (!_BlinkOn)
{
// Restore Graphics from Backup
RestoreBackground(Graph);
_BlinkOn = true;
}
else
{
// Backup Graphics
Graph.Flush();
BackupBackground(Graph);
// Draw Caret
using (SolidBrush P = new SolidBrush(Color.Black))
{
Graph.FillRectangle(P, new Rectangle(_Location, _Size));
}
_BlinkOn = false;
}
}
The Caret should flash in both circumstances as I change nothing really but it only flashes when I use the Panel on the Form.
Note: I do not intend to use a Panel for the cache I was just experimenting and found this behavior and its weird, so I need to know.
Thanks Danny.
I am using Microsoft Visual Studio Community 2017 version 15.7.2, and .NET Framework version 4.7.03056.
I am using the Winforms TreeView and am modifying its default behavior to make it a little bit more like the Windows Explorer tree view. I set the following properties:
LineHeight` 22
DrawMode OwnerDrawAll
I am using the following for the DrawNode event. This code uses right and down bracket bitmaps (which are 16x16) to show expanded or unexpanded nodes, and uses custom colors for select/focus highlighting. Nothing exotic.
private void treeDir_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
const int indent = 12;
const int markerSpacing = 20;
int leftPos = e.Bounds.Left + e.Node.Level * indent;
Brush selectBrush;
Pen pen;
Graphics g = e.Graphics;
e.DrawDefault = false;
if (e.Node.IsSelected)
{
if (e.Node.TreeView.Focused)
{
selectBrush = new SolidBrush(FocusedBackgroundColor);
pen = new Pen(new SolidBrush(FocusedPenColor));
}
else
{
selectBrush = new SolidBrush(UnfocusedBackgroundColor);
pen = new Pen(new SolidBrush(UnfocusedPenColor));
}
g.FillRectangle(selectBrush, e.Bounds);
g.DrawRectangle(pen, e.Bounds);
}
if (e.Node.Nodes.Count > 0)
{
if (e.Node.IsExpanded)
{
g.DrawImage(Properties.Resources.Expanded, leftPos+2, e.Bounds.Top+2);
}
else
{
g.DrawImage(Properties.Resources.Unexpanded, leftPos+2, e.Bounds.Top+2);
}
}
g.DrawString(
e.Node.Text, CommonFont, new SolidBrush(Color.Black), leftPos + markerSpacing, e.Bounds.Top+2);
}
What's happening is that when the form is first shown, if I expand a node that is not the first node, it also overwrites (transparently overlays) the first node text. Here's the sequence.
On start up of the form:
Then I double click Node 4:
If I double click the first node, the problem clears up:
From this point forward, if I double click Node 4, the problem no longer occurs. Double clicking the first node clears up the problem and avoids it for the life of the form after that point for Node 4. However, if I double click another expandable node further down, it happens again.
Is this a bug in TreeView or am I doing something incorrect in my owner draw?
The DrawNode event is called rather too often when doubleclicking and one set of calls has a bounds rectangle that is Empty.
(Maybe the reasoning was: If all drawing is happening only in the empty rectangle nothing will show. Hm..)
So as a workaround you can shortcut the DrawNode event for all the wrong calls at the beginning of the event:
if (e.Bounds.Height < 1 || e.Bounds.Width < 1) return;
I also recommend text rendering like this..:
TextRenderer.DrawText(g, e.Node.Text, CommonFont,
new Point( leftPos + markerSpacing, e.Bounds.Top+2), Color.Black);
TextRenderer is always recommended over Graphics.DrawString for forms as it improves on several shortcomings.
I have created a custom ListView control to suit my needs and I'm having an issue that causes the ListView not to show any contents (not drawing anything, just white) when the form first loads.
If I resize the form or click on my control (anything that forces a repaint on the ListView) then it shows up as expected.
As a side note, it used to work just fine until I made a small change today and rebuilt the control. I removed all the changes I made and rebuilt again but the issue still happens. Any ideas as to why it will not show up (paint) when the form is first loaded?
This is what I use to do the custom drawing on my custom ListView control...
protected override void OnDrawItem(DrawListViewItemEventArgs e)
{
Image image = e.Item.ImageList.Images[e.Item.ImageIndex];
Size textSize = new Size((int)e.Graphics.MeasureString(e.Item.Text, e.Item.Font).Width, (int)e.Graphics.MeasureString(e.Item.Text, e.Item.Font).Height);
//Get the area of the item to be painted
Rectangle bounds = e.Bounds;
bounds.X = 0;
bounds.Width = this.Width;
//Set the spacing on the list view items
int hPadding = 0;
int vPadding = 0;
IntPtr padding = (IntPtr)(int)(((ushort)(hPadding + bounds.Width)) | (uint)((vPadding + bounds.Height) << 16));
SendMessage(this.Handle, (uint)ListViewMessage.LVM_SETICONSPACING, IntPtr.Zero, padding);
//Set the positions of the image and text
int imageLeft = (bounds.Width / 2) - (image.Width / 2);
int imageTop = bounds.Top + 3;
int textLeft = (bounds.Width / 2) - (textSize.Width / 2);
int textTop = imageTop + image.Height;
Point imagePosition = new Point(imageLeft, imageTop);
Point textPosition = new Point(textLeft, textTop);
//Draw background
using (Brush brush = new SolidBrush(e.Item.BackColor))
e.Graphics.FillRectangle(brush, bounds);
//Draw selected
if (e.Item.Selected)
{
using (Brush brush = new SolidBrush(m_SelectedColor))
e.Graphics.FillRectangle(brush, bounds);
}
//Draw image
e.Graphics.DrawImage(image, imagePosition);
//Draw text
e.Graphics.DrawString(e.Item.Text, e.Item.Font, new SolidBrush(e.Item.ForeColor), textPosition);
}
I also set the following things in the Constructor of my custom control...
public MyListView()
{
this.DoubleBuffered = true;
this.OwnerDraw = true;
this.View = View.LargeIcon;
this.Cursor = Cursors.Hand;
this.Scrollable = false;
}
I also inherit the ListView class...
public class MyListView : ListView
{
//All my source
}
You need to set the set the control to redraw itself when resized. So add this code in constructor of your control:
this.ResizeRedraw = true;
My apologies:
Doing the below reset my event handlers and the problem went away. However, once I hooked them up, I found the Resize event handler that I used to set the ColumnWidth was causing the issue. Why setting the ColumnWidth is causing this, I do not know.
Arvo Bowen's comment on this answer fixed it for me also (.NET 4.8 Framework, VS2022). To be clear, not requiring this.ResizeRedraw = true; from the answer.
So after much headache and time I found that I had absolutely nothing wrong with my control. It was your answer that made me create another control just like my existing one and test it. To my surprise it worked great. I simply copied my existing non-working control and pasted it on the form and then new one worked! Sometimes VS just does weird things... Somehow I managed to muck up the control's creation object or something..
After failing to use the control.drawtobitmap in c#, my second option was to take screenshots of the desktop and crop out the desired sections.
My hiccup shows up once i switch user accounts, although the program does not crash, once the user is switched the program generates pure black images only.
I used this code as a reference:
WebBrowser.DrawToBitmap() or other methods?
I guess logically this makes sense as this would help windows save resources.
What options/ solutions do i have in my situation?
Edit 1
made a modification to the code for testing:
int c = 0;
while (true)
{
try
{
c++;
Rectangle formBounds = this.Bounds;
Bitmap bmp = new Bitmap(formBounds.Width, formBounds.Height);
using (Graphics g = Graphics.FromImage(bmp))
g.CopyFromScreen(formBounds.Location, Point.Empty, formBounds.Size);
bmp.Save("picture" + c.ToString() + ".jpg");
Thread.Sleep(5000);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
this works perfectly while on the user account, but as soon as i switch users, it returns the exception: The handle is invalid.
Any ideas?
Edit 2:
The bug in DrawToBitmap is not exactly random...
if i used the code you supplied:
Bitmap bmp = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
this.DrawToBitmap(bmp, this.ClientRectangle);
bmp.Save(".\\picture.jpg");
it works perfectly, example: http://oi61.tinypic.com/1z23ynp.jpg
However, the moment i right-click on the web-browser control, DrawToBitmap will return a blank image.
example: http://oi60.tinypic.com/9ay0yc.jpg
So i can easily overcome this bug by adding
((Control)webbrowser1).Enabled = false;
this makes any clicking impossible on the web-browser, but unfortunately to deactivate it would render my project useless as its main function is to emulate mouse clicks on a web-browser control.
although this might also be a problem if the window is hidden.
currently im looking at this post, where code is supplied to give you a window handle.
Simulate click into a hidden window
it seems it might be of some value... do have a look.
What were the problems you had with DrawToBitmap?
It works fine here, (W8.1, VS2013) even with a Webcontrol and also after switching users. (But see the edit at the end for the conditions!)
Bitmap bmp = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
this.DrawToBitmap(bmp, this.ClientRectangle);
// Clipboard.SetImage(bmp); for testing only
bmp.Dispose();
Here is code to take a screenshot of your window:
Rectangle formBounds = this.Bounds;
Bitmap bmp = new Bitmap(formBounds.Width, formBounds.Height );
using (Graphics g = Graphics.FromImage(bmp))
g.CopyFromScreen(formBounds.Location, Point.Empty, formBounds.Size);
//Clipboard.SetImage(bmp); for testing only
bmp.Dispose();
I can switch users like I want, the program keeps working.
BTW, the link you posted is really old, many things may have improved.
Edit:
With the updated question things are a lot clearer.
So you want to continuously get a screenshot of your program even when the user has changed, right?
and you want to display a WebControl, right?
A user can have three types of desktop: the logon/logoff screen, the screensaver screen and one or more normal desktop screen(s). But while the user is logged off he has no desktop screen at all.
Therefore the screenshot method will not work if the user has no active desktop, neither as g.CopyFromScreen, which will cause a GDI-error nor using a window handle like in the various solutions on the web, including the ones your link leads to. All these will, at best, show a blank or black screen.
So the DrawToBitmap method is the only one that works.
You wrote that it has random errors. That's not what I see.
The problems come in predictably when the user interacts with the WebBrowser in any way. This includes scrolling or clicking with or without navigation. After these interactions the WebBrowser will draw itself as an empty box until its URL is reloaded - not only refreshed - but really reloaded by webBrowser1.Uri = new Uri(uriPath). This can be done, see my other post
The WebBrowser also has another issue when doing a DrawToBitmap: It will fail (with the said empty box) for any pages that include an <input type="text" element. I'm not sure what's the best way to workaround this, let alone why it happends in the first place.. A screenshot method doesn't have that specific problem.
Edit 2:
The code the OP has dug up code which, using a call to PrintWindow, seems to solve all problems we had: It works while being logged off, works with Refeshing even after clicking in the WebBrowser and scrapes all pages, including those with textual input fields. Hoorah!
After cutting down the slack here is a version that can create a copy of the Form or just the WebBroser (or any other Control) with or without borders:
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
public Bitmap CaptureWindow(Control ctl)
{
//Bitmap bmp = new Bitmap(ctl.Width, ctl.Height); // includes borders
Bitmap bmp = new Bitmap(ctl.ClientRectangle.Width, ctl.ClientRectangle.Height); // content only
using (Graphics graphics = Graphics.FromImage(bmp))
{
IntPtr hDC = graphics.GetHdc();
try { PrintWindow(ctl.Handle, hDC, (uint)0); }
finally { graphics.ReleaseHdc(hDC); }
}
return bmp;
}
Finally this code seems to work even when i have switched users.
Code to take screen shot of any unsaved Notepad process ("Untitled - Notepad")
private void Form1_Load(object sender, EventArgs e)
{
//loop for debugging
int c = 0;
while(true)
{
c++;
System.Drawing.Bitmap image = CaptureWindow(FindWindow(null, "Untitled - Notepad"));
image.Save(".\\picture"+c.ToString()+".jpg");
Thread.Sleep(5000);
}
}
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public System.Drawing.Bitmap CaptureWindow(IntPtr hWnd)
{
System.Drawing.Rectangle rctForm = System.Drawing.Rectangle.Empty;
using (System.Drawing.Graphics grfx = System.Drawing.Graphics.FromHdc(GetWindowDC(hWnd)))
{
rctForm = System.Drawing.Rectangle.Round(grfx.VisibleClipBounds);
}
System.Drawing.Bitmap pImage = new System.Drawing.Bitmap(rctForm.Width, rctForm.Height);
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(pImage);
IntPtr hDC = graphics.GetHdc();
try
{
PrintWindow(hWnd, hDC, (uint)0);
}
finally
{
graphics.ReleaseHdc(hDC);
}
return pImage;
}
Note that the window may be hidden but it must still be maximized on the user account to get a complete screen shot.
Digital Rights Management may be stopping this, because Windows adds protection for digital media.
If, for example, you are attempting to create a screen capture of something in Media Player or Media Center using Microsoft's rendering of Graphics - yes, Microsoft is going to "protect you from any potential lawsuit."
Try this: Click "Print Screen" on your keyboard and then go into Microsoft Paint and try pasting your screen capture into it. Is anything there?
I faced with the same problem and I couldn't use CopyFromScreen method because my form with WebBrowser could be hidded. PrintWindow method also didn't work well generating images with black areas, especially when my MDI form partially covered by MDI parent form.
Finally I used OleDraw method as in this topic on SO, but integrated it in a class derived from WebBrowser. Basically, it just overrides standard control reaction to WM_PRINT message. This allows to do normal Control.DrawToBitmap not only for the WebBrowser, but for a form with WebBrowser in it as well. This also works if the form is hidden (covered by another form, including MDI parent form) and should work when user has locked session with Win+L (I haven't tested it).
public class WebBrowserEx : WebBrowser
{
private const uint DVASPECT_CONTENT = 1;
[DllImport("ole32.dll", PreserveSig = false)]
private static extern void OleDraw([MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwAspect,
IntPtr hdcDraw,
[In] ref System.Drawing.Rectangle lprcBounds
);
protected override void WndProc(ref Message m)
{
const int WM_PRINT = 0x0317;
switch (m.Msg)
{
case WM_PRINT:
Rectangle browserRect = new Rectangle(0, 0, this.Width, this.Height);
// Don't know why, but drawing with OleDraw directly on HDC from m.WParam.
// results in badly scaled (stretched) image of the browser.
// So, drawing to an intermediate bitmap first.
using (Bitmap browserBitmap = new Bitmap(browserRect.Width, browserRect.Height))
{
using (var graphics = Graphics.FromImage(browserBitmap))
{
var hdc = graphics.GetHdc();
OleDraw(this.ActiveXInstance, DVASPECT_CONTENT, hdc, ref browserRect);
graphics.ReleaseHdc(hdc);
}
using (var graphics = Graphics.FromHdc(m.WParam))
{
graphics.DrawImage(browserBitmap, Point.Empty);
}
}
// ignore default WndProc
return;
}
base.WndProc(ref m);
}
}
I'm customizing the appearance of a WinForms ToolTip control by responding to the Draw event. I just want some of the ToolTip's corners to be rounded. I've got everything working such that the first time the ToolTip is displayed, everything looks perfect. On subsequent displays, however, the unfilled areas of my rounded rectangle continue to have what was in the background the first time the ToolTip was displayed.
Screen shot of problem (I don't have rights to put inline apparently):
http://tinypic.com/r/30xa3w9/3
In the picture, you can see the left-over artifacts in the upper-left corner where I would like it to just be transparent (showing the gray background), like this:
tinypic.com/r/mvn8eo/3 (nor rights to add more than one link)
Here is the drawing code:
private void ToolTip_Draw(object sender, DrawToolTipEventArgs args)
{
args.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
var rect = new RectangleF(0, 0, args.Bounds.Width, args.Bounds.Height);
using (var backBrush = new LinearGradientBrush(rect, Color.Silver, this.BackColor, 90))
{
using (var path = GetRoundedRectangle(rect, 10, 4, 4, 1))
{
args.Graphics.FillPath(backBrush, path);
args.DrawText();
}
}
}
The GetRoundedRectangle function (not included) just calculates the appropriate GraphicsPath for the rounded geometry that I want.
I tried adding a call to args.DrawBackground after setting the BackColor to Color.Transparent, but that just filled in the area with the dark gray of the form's background rather than actually being transparent, which I think is the typical "simulated" transparency of WinForms.
As a side note, an non-customized ToolTip with IsBalloon set to true is non-rectangular with correct transparency.
Can anyone suggest a fix for this problem?
Control.Region is what you are looking for. You need to tell the window manager the shape of the tooltip, so background is properly redrawn.
Here is a solution, though imperfect. It uses Graphics.CopyFromScreen to copy the area under the tooltip into the background. Of course, getting the location of the tooltip isn't simple -- hence the reflection and PInvoke call to GetWindowRect.
A remaining glitch is that the background might be wrong while the the tooltip fades out. For example, if you have a button that is colored when the mouse is over it, the tooltip will still have that colored background when you move the mouse off while it fades away. Setting ToolTip.UseFading to false seems to change the frequency of background paints such that it is worse than the fading problem. If the user has disabled eye candy at the OS level, that might also trigger the same paint glitches as having UseFading set to false.
private void ToolTip_Draw2(object sender, DrawToolTipEventArgs args)
{
var graphics = args.Graphics;
var bounds = args.Bounds;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
var windowRect = GetWindowRect();
graphics.CopyFromScreen(windowRect.Left, windowRect.Top, 0, 0, new Size(bounds.Width, bounds.Height));
using (var backBrush = new LinearGradientBrush(bounds, C.Color_LogitechGray2, this.BackColor, 90))
{
using (var path = GetRoundedRectangle(bounds, 10, 4, 4, 1))
{
args.Graphics.FillPath(backBrush, path);
args.DrawText();
}
}
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
private Rectangle GetWindowRect()
{
RECT rect = new RECT();
var window = typeof(ToolTip).GetField("window", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this) as NativeWindow;
GetWindowRect(window.Handle, ref rect);
return rect;
}