I am trying to draw my own tooltip. But I cant get rid of the standard shadow.
Its a standard WinForm application, with lots of forms. So therefore is
Application.EnableVisualStyles();
called, and needed, when the application starts. If I comment out this line, it works. I made a minimal WinForm app below. If EnableVisualStyles is commented out, it draws a red rectangle only. When I uncomment it, it draws a red rectangle with a shadow.
Does anyone know ho to solve this? How to have Application.EnableVisualStyles(), and have a tooltip 100% OwnerDrawn, without any standard shadows?
Minimal WinForm app is here:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ToolTipExample
{
public class MainForm : Form
{
[STAThread]
static void Main()
{
// Comment out below line and it works.
Application.EnableVisualStyles();
Application.Run(new MainForm());
}
private ToolTip toolTip;
private Button button;
public MainForm()
{
toolTip = new ToolTip();
toolTip.OwnerDraw = true;
toolTip.Draw += new DrawToolTipEventHandler(toolTip1_Draw);
toolTip.Popup += new PopupEventHandler(toolTip1_Popup);
button = new Button();
button.Location = new Point(25, 25);
button.Text = "Button";
toolTip.SetToolTip(button, "Button tip text");
Controls.AddRange(new Control[] { button });
}
private void toolTip1_Popup(object sender, PopupEventArgs e)
{
e.ToolTipSize = new Size(100, 100);
}
private void toolTip1_Draw(System.Object sender, DrawToolTipEventArgs e)
{
e.Graphics.FillRectangle(new SolidBrush(Color.Red), e.Bounds);
}
}
}
You can get the class style of the ToolTip using GetClassLong and then remove CS_DROPSHADOW style from it and set the class style for the ToolTip again:
//using System.Runtime.InteropServices;
public const int GCL_STYLE = -26;
public const int CS_DROPSHADOW = 0x20000;
[DllImport("user32.dll", EntryPoint = "GetClassLong")]
public static extern int GetClassLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetClassLong")]
public static extern int SetClassLong(IntPtr hWnd, int nIndex, int dwNewLong);
private void toolTip1_Popup(object sender, PopupEventArgs e)
{
e.ToolTipSize = new Size(100, 100);
var hwnd = (IntPtr)typeof(ToolTip).GetProperty("Handle",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance).GetValue(toolTip);
var cs = GetClassLong(hwnd, GCL_STYLE);
if ((cs & CS_DROPSHADOW) == CS_DROPSHADOW)
{
cs = cs & ~CS_DROPSHADOW;
SetClassLong(hwnd, GCL_STYLE, cs);
}
}
Related
When working on an application i decide to add my first user control for that project. I make it just fine, however when i drag it in to my main form from the toolbox it pops up with an error message:
No matter what i do it doesn't seem to fix it. I have tried adding it through code however it simply wouldn't show up at all.
Looking in to the problem online I was not able to find a working solution, or at least no solution that I could follow and understand.
Help would really be appreciated, and if any more information is needed I would be glad to add it. However currently I don't know what I could add that could be of any use.
The code is for a simple prank virus (Have to inspire myself to keep learning to code :) ) Here is the code (Please don't launch the file, it is a prank virus after all, the only way to exit is alt+f4):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Simple_virus_V2
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
internal static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public Form1()
{
InitializeComponent();
timer1.Start();
timer2.Start();
Thread newthread = new Thread(progress);
newthread.Start();
}
Random rnd = new Random();
int noticewidth = 0;
bool changecursor = false;
private void progress() {
Thread.Sleep(1000);
changecursor = true;
Thread.Sleep(1000);
timer3.Start();
Thread.Sleep(5000);
noticewidth = Width;
}
int mouseflash = 0;
private void timer1_Tick(object sender, EventArgs e)
{
if (changecursor) {
if (mouseflash < 1000)
{
Bitmap cursor = new Bitmap(new Bitmap(pictureBox1.Image), 24, 24);
Cursor = new Cursor(cursor.GetHicon());
} else if (mouseflash < 1700) {
Bitmap cursor = new Bitmap(new Bitmap(pictureBox2.Image), 30, 30);
Cursor = new Cursor(cursor.GetHicon());
}
else {
mouseflash = 0;
}
mouseflash = mouseflash + rnd.Next(3,10);
}
header.Left = MousePosition.X - (header.Width / 2);
label2.Left = MousePosition.X - (label2.Width / 2);
label3.Left = label2.Left + 25;
panel1.Width = noticewidth;
this.Location = new Point(0,0);
panel1.Location = new Point(0, MousePosition.Y - 40);
this.WindowState = FormWindowState.Maximized;
TopMost = true;
Process currentProcess = Process.GetCurrentProcess();
IntPtr hWnd = currentProcess.MainWindowHandle;
if (hWnd != IntPtr.Zero)
{
SetForegroundWindow(hWnd);
ShowWindow(hWnd, int.Parse("9"));
}
Focus();
this.Width = Screen.PrimaryScreen.Bounds.Width * 3;
this.Height = Screen.PrimaryScreen.Bounds.Height * 2;
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
/*
using (Form1 frm = new Form1()) {
if (frm.ShowDialog() == DialogResult.OK) {
}
}
*/
}
private void timer2_Tick(object sender, EventArgs e)
{
PictureBox pic = new PictureBox();
pic.Width = 1;
pic.Height = 1;
pic.BackColor = Color.Black;
pic.Location = new Point(rnd.Next(0, this.Width), rnd.Next(0, this.Height));
this.Controls.Add(pic);
}
private void timer3_Tick(object sender, EventArgs e)
{
/*
bartry bars = new bartry();
bars.Location = new Point(0, rnd.Next(0, 500));
Controls.Add(bars);
timer3.Interval = rnd.Next(100, 5000);
*/
}
}
}
Thanks
After ages of trying out the answers on the other post none of them ended up working. I did find the solution after opening a new project and experimenting around with my code.
The solution: Make sure that the user control and the main forms have the same "using" references!
Sorry if this was self explanatory, but i didn't know that you had to do that.
Just debug the project then try to add the User control form
I want to color the BackColor property of a PictureBox when the mouse enters it.
I turn the BackColor into Yellow when then MouseEnter event fires, and I reset to transparent in MouseLeave.
Then when I click on a PictureBox, I change its position, so I also have a Move event which resets it in transparent.
The problem is, once I moved it, I need to enter the PictureBox twice with the mouse to fire the MouseEnter event!
It's a very graphical problem, so I uploaded a little video to show you what's happening, it surely will explain my problem better than I do.
I tried another way, changing the color not in MouseEnter but in MouseHover. In this case, it works well, except that I have a 500ms delay before firing the Move event, which is obviously not what I want.
I have no viable solution right now.
For the code, it's very simple, for the moment I have :
private void pictureBoxMouseUp(object sender, MouseEventArgs e)
{
// I move the PictureBox here
}
private void pictureBoxMove(object sender, EventArgs e)
{
(sender as PictureBox).BackColor = Color.Transparent;
}
private void pictureBoxMouseEnter(object sender, MouseEventArgs e)
{
(sender as PictureBox).BackColor = Color.LightYellow;
}
private void pictureBoxMouseLeave(object sender, MouseEventArgs e)
{
(sender as PictureBox).BackColor = Color.Transparent;
}
In the Designer.cs, my events for each PictureBox are like :
this.pictureBox2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBoxMouseDown);
this.pictureBox2.MouseEnter += new System.EventHandler(this.pictureBoxMouseEnter);
this.pictureBox2.MouseLeave += new System.EventHandler(this.pictureBoxMouseLeave);
this.pictureBox2.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pictureBoxMouseUp);
this.pictureBox2.Move += new System.EventHandler(this.pictureBoxMove);
EDIT : To answer my question, this is the code I use now : (comments are in french)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Diagnostics;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using EmoTEDTherapeute;
namespace ControlSceneImage {
public class SceneImage : PictureBox {
public static readonly int defaultWidth = 100;
public static readonly int defaultHeight = 100;
static readonly int activePbPosY; // Position en Y des scènes actives
static readonly Dictionary<string, Point> scenesPos = null; // Invariant, stocke la position initiale des PictureBox
static readonly List<Point>[] activeScenesPos = null; // Invariant, stocke les positions des PictureBox en fonction du nombre de scènes actives
static List<SceneImage> activeScenes = null;
const int maxActiveScenes = 5;
const int ecart = 80;
const int decalage = 15;
const int panelScenesWidth = 909;
const int panelScenesHeight = 154;
const int panelScenesLocationX = 35;
const int panelScenesLocationY = 36;
bool isActive;
static SceneImage() {
// Constructeur initialisant tous les membres statiques, n'est appelé qu'une seule fois, avant tout le reste
activePbPosY = (panelScenesLocationY + panelScenesHeight - (int)(0.6 * defaultHeight)) / 2;
scenesPos = new Dictionary<string, Point>();
activeScenesPos = new List<Point>[maxActiveScenes];
for (int i = 0; i < maxActiveScenes; i++) {
activeScenesPos[i] = CalcActiveScenesPos(i+1);
}
activeScenes = new List<SceneImage>();
}
public SceneImage() {
MouseEnter += new EventHandler(OnMouseEnter);
MouseDown += new MouseEventHandler(OnMouseDown);
MouseUp += new MouseEventHandler(OnMouseUp);
MouseLeave += new EventHandler(OnMouseLeave);
BorderStyle = BorderStyle.FixedSingle;
Size = new Size(defaultWidth, defaultHeight);
SizeMode = PictureBoxSizeMode.Zoom;
isActive = false;
}
private static List<Point> CalcActiveScenesPos(int nbActiveScenes) {
List<Point> ret = new List<Point>();
for (int i = 0; i < nbActiveScenes; i++) {
ret.Add(new Point((panelScenesLocationX + panelScenesWidth + ecart) / 2 + (int)((ecart + defaultWidth) * (i - nbActiveScenes / 2.0)) + decalage, activePbPosY));
}
return ret;
}
private void UpdateScenesPos() {
for(int i = 0; i < activeScenes.Count; i++) {
activeScenes[i].Location = activeScenesPos[activeScenes.Count - 1][i];
}
}
private void OnMouseEnter(object sender, EventArgs e) {
BackColor = Color.LightYellow;
Cursor = Cursors.Hand;
}
private void OnMouseDown(object sender, MouseEventArgs e) {
BorderStyle = BorderStyle.Fixed3D;
}
private void OnMouseUp(object sender, MouseEventArgs e) {
if (!scenesPos.ContainsKey(Name)) {
// Si ce n'est pas déjà fait, on stocke la position initiale de notre PictureBox
scenesPos.Add(Name, Location);
// Et on crée un Panel vide sous elle
Panel panel = new Panel();
panel.Location = Location;
panel.Size = Size;
panel.BorderStyle = BorderStyle.Fixed3D;
// On ajoute notre panel à notre form
Form1.AddInSeance(panel);
}
if (!isActive) {
activeScenes.Add(this);
} else {
Location = scenesPos[Name];
activeScenes.Remove(this);
}
isActive = !isActive;
UpdateScenesPos();
}
private void OnMouseLeave(object sender, EventArgs e) {
BorderStyle = BorderStyle.FixedSingle;
BackColor = Color.Transparent;
}
}
}
I use the same method as before, and for an unknown reason, now it works.
Thanks to all of you for helping me :)
The problem is that when you relocate the PictureBox, it will not receive the mouse leave event. Maybe you have already noticed that, that's why you set the BackColor in the Move event, too.
After you moved the control, it will not receive a second MouseEnter when you hover it again, only after you moved the mouse off and on again.
Try to send a mouse leave event manually (I haven't tested it):
private const int WM_MOUSELEAVE = 0x02A3;
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
private void pictureBoxMouseUp(object sender, MouseEventArgs e)
{
// move the PictureBox...
SendMessage(((PictureBox)sender).Handle, WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero);
}
I will avoid to move the PictureBox. Clearly your bug come from that.
When you move the component, the mouse is no more in it but it status is not updated.
You can swim deep in the windows form reference code or you can just says you have N small preview (the pictures on the bottom line) and one big preview (the upper one).
Create N+1 picture box and don't change it. Just change their image property.
When a small preview is clicked, switch it's image property with the big preview.
Also, a good MVC pattern is recommended.
I am trying to paint the split line that appears when you drag a splitter control:
As you can see from this image, the default splitter is a checkerboard.
...this doesn't work:
public partial class MockForm : Form
{
public MockForm()
{
InitializeComponent();
this.splitter1.Paint += splitter1_Paint;
}
private void splitter1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.Red);
}
}
this just paints the background of the control but not the splitter when it's dragged.
Any ideas?
The answer posted by LarsTech is really good, But the handler flickers are somehow annoying. Instead of showing the control in Form, if you show a Form as splitter handler and show it above the Container of splitter, the flickers will be gone.
HighLight f = new HighLight() { BackColor = Color.Red };
private void splitter1_SplitterMoving(object sender, SplitterEventArgs e)
{
this.splitter1.Parent.Refresh();
f.Location = this.splitter1.Parent.PointToScreen(new Point(e.SplitX, e.SplitY));
f.Size = this.splitter1.Size;
if (!f.Visible)
f.ShowInactiveTopmost();
}
private void splitter1_SplitterMoved(object sender, SplitterEventArgs e)
{
f.Hide();
}
Here is the form which I used as highlight:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class HighLight : Form
{
public HighLight()
{
Opacity = 0;
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
StartPosition = FormStartPosition.Manual;
}
protected override void OnDeactivate(EventArgs e)
{
base.OnDeactivate(e);
this.Hide();
}
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(int hWnd, int hWndInsertAfter,
int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public void ShowInactiveTopmost()
{
ShowWindow(this.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(this.Handle.ToInt32(), HWND_TOPMOST,
this.Left, this.Top, this.Width, this.Height,
SWP_NOACTIVATE);
this.Opacity = 1;
}
}
To see a custom splitter which supports transparent handler take a look at this related post. In the other post I created a new splitter control using source codes of original splitter, but changed rendering the highlight:
Change Splitter Highlighting/Resize Line
The old Splitter control uses a private painting method to produce that checkerboard effect, so there isn't any thing you can override to replace that.
You can fake it by dragging your own control in the space of the checkerboard control you see on the screen. This may produce some flicker:
Control draggingControl = new Control { BackColor = Color.Green, Visible = false };
public MockForm() {
InitializeComponent();
this.Controls.Add(draggingControl);
splitter1.SplitterMoving += splitter1_SplitterMoving;
splitter1.SplitterMoved += splitter1_SplitterMoved;
}
void splitter1_SplitterMoving(object sender, SplitterEventArgs e) {
draggingControl.Bounds = new Rectangle(new Point(e.X - (e.X - e.SplitX), 0),
splitter1.Size);
if (!draggingControl.Visible) {
draggingControl.Visible = true;
draggingControl.BringToFront();
}
this.Refresh();
}
void splitter1_SplitterMoved(object sender, SplitterEventArgs e) {
draggingControl.Visible = false;
this.Refresh();
}
The Splitter control was deprecated in favor of the SplitContainer control.
This code automatically sizes a RichTextBox according to it's contents. I'm having issues, especially with tables. \t may be ignored. I tried a managed solution, now I'm trying platform invoke. Current Output:
[DllImport("gdi32.dll")]
static extern bool GetTextExtentPoint32(IntPtr hdc, string lpString, int cbString, out SIZE lpSize);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetDC(IntPtr hWnd);
[StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SIZE
{
public int cx;
public int cy;
public SIZE(int cx, int cy)
{
this.cx = cx;
this.cy = cy;
}
}
public static void Main()
{
Form form = new Form();
RichTextBox rtfBox = new RichTextBox();
rtfBox.Rtf = #"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil Arial;}}\viewkind4\uc1\trowd\trgaph100\cellx1000\cellx2000\pard\intbl\lang1033\f0\fs20 hi\cell bye\cell\row\intbl one\cell two\cell\row\pard\par}";
rtfBox.ScrollBars = RichTextBoxScrollBars.None;
string sInput = "hi\t bye\t\n";// one\t two\t\n";
SIZE CharSize;
form.Controls.Add(rtfBox);
IntPtr hdc = GetDC(IntPtr.Zero);//Context for entire screen
GetTextExtentPoint32(hdc, sInput, sInput.Length, out CharSize);
rtfBox.Width = CharSize.cx;
rtfBox.Height = CharSize.cy;
form.Visible = false;
form.ShowDialog();
}
(Note, for simplicity this is a console application with a reference to System.Windows.Forms.dll)
Have you looked at the ContentsResized event? Add the following method to be called when the event fires:
private void richTextBox_ContentsResized(object sender, ContentsResizedEventArgs e)
{
var richTextBox = (RichTextBox) sender;
richTextBox.Width = e.NewRectangle.Width;
richTextBox.Height = e.NewRectangle.Height;
}
When the RTF content is changed (using Rtf), the RichTextBox should be resized to match its contents. Make sure you also set the WordWrap property to false.
I've tried it with your table example and it does appear to work (albeit with a little offset, which you could possibly solve by adding a few pixels of width to the adjusted size - not sure why that happens):
P.Brian.Mackey EDIT
This answer worked for me. To clarify, here's the final code including border fix:
public static void Main()
{
string sInput = "hi\t bye\t\n";// one\t two\t\n";
SIZE CharSize;
Form form = new Form();
RichTextBox rtfBox = new RichTextBox();
rtfBox.ContentsResized += (object sender, ContentsResizedEventArgs e) =>
{
var richTextBox = (RichTextBox)sender;
richTextBox.Width = e.NewRectangle.Width;
richTextBox.Height = e.NewRectangle.Height;
rtfBox.Width += rtfBox.Margin.Horizontal + SystemInformation.HorizontalResizeBorderThickness;
};
rtfBox.WordWrap = false;
rtfBox.ScrollBars = RichTextBoxScrollBars.None;
rtfBox.Rtf = #"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil Arial;}}\viewkind4\uc1\trowd\trgaph100\cellx1000\cellx2000\pard\intbl\lang1033\f0\fs20 hi\cell bye\cell\row\intbl one\cell two\cell\row\pard\par}";
form.Controls.Add(rtfBox);
form.ShowDialog();
}
It's much easier to use GetPreferredSize, as described in this answer. Then you don't need to wait for a ContentsResized event,
What about the Height ?
I added
richTextBox.Height += richTextBox.Margin.Vertical +
SystemInformation.VerticalResizeBorderThickness;
at the end.
It also looks like a good candidate for an extension method :
static public class RichTextBoxResizer {
static public void ResizeToContents(this RichTextBox richTextBox, ContentsResizedEventArgs e) {
richTextBox.Width = e.NewRectangle.Width;
richTextBox.Height = e.NewRectangle.Height;
richTextBox.Width += richTextBox.Margin.Horizontal +
SystemInformation.HorizontalResizeBorderThickness +
SystemInformation.HorizontalScrollBarThumbWidth;
richTextBox.Height += richTextBox.Margin.Vertical +
SystemInformation.VerticalResizeBorderThickness;
}
static public void ResizeToContentsHorizontally(this RichTextBox richTextBox, ContentsResizedEventArgs e) {
richTextBox.Width = e.NewRectangle.Width;
richTextBox.Width += richTextBox.Margin.Horizontal +
SystemInformation.HorizontalResizeBorderThickness +
SystemInformation.HorizontalScrollBarThumbWidth;
}
static public void ResizeToContentsVertically(this RichTextBox richTextBox, ContentsResizedEventArgs e) {
richTextBox.Height = e.NewRectangle.Height;
richTextBox.Height += richTextBox.Margin.Vertical +
SystemInformation.VerticalResizeBorderThickness;
}
}
So the event sink looks like :
private void rtfBox_ContentsResized(object sender, ContentsResizedEventArgs e) {
RichTextBox rtb = (RichTextBox)sender;
rtb.ResizeToContents(e);
}
My C# application consists of a taskbar icon (NotifyIcon) and an overhead window initially hidden. I want the user to be able to toggle the window visibility by clicking on the NotifyIcon (left, single click). Also the window is being hidden when loosing focus.
This is what I have so far, a subclassed System.Windows.Forms.Form:
Initialization:
this.ControlBox = false;
this.ShowIcon = false;
this.ShowInTaskbar = false;
// Instance variables: bool allowVisible;
// System.Windows.Forms.NotifyIcon notifyIcon;
this.allowVisible = false;
this.notifyIcon = new NotifyIcon();
this.notifyIcon.MouseUp += new MouseEventHandler(NotifyIconClicked);
this.Deactivate += new EventHandler(HideOnEvent);
Instance methods:
private void NotifyIconClicked(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
if (this.Visible)
this.Hide();
else
this.Show();
}
}
new public void Show()
{
this.allowVisible = true;
this.Visible = true;
this.Activate();
}
new public void Hide()
{
this.allowVisible = false;
this.Visible = false;
}
private void HideOnEvent(object sender, EventArgs e)
{
this.Hide();
}
protected override void SetVisibleCore(bool visible)
{
base.SetVisibleCore(this.allowVisible ? visible : this.allowVisible);
}
Clicking the icon reveals the window like it should. But clicking it again hides it for as long as the mouse is being pressed, then resets it to visible.
My guess is that the mouse down event steals the focus from the window so it disappears. Then the mouse up event is triggered, showing the window as it is hidden.
My next idea was to read the window visibility at mouse down event, so I tested three events and logged the UNIX time as they are called:
notifyIcon.MouseDown
notifyIcon.MouseUp
this.LostFocus
The result is pretty weird: Let's say the window is visible. This happens when I click the icon: Focus lost is called immediately. Mouse down is called as soon as I release the mouse, right before the mouse up event.
1312372231 focus lost
1312372235 mouse down
1312372235 mouse up
Why is the mouse down event delayed?
How can I toggle the window?
I think this may work for you.
I found an expert exchange post which contains a class which provides a method for checking whether the cursor is currently over the tray.
NotifyIcon - Detect MouseOut
Using this class I modified your HideOnEvent method like so:
private void HideOnEvent(object sender, EventArgs e)
{
if (!WinAPI.GetTrayRectangle().Contains(Cursor.Position))
{
this.Hide();
}
}
Which seems to do what you need.
I have included the class below:
using System.Runtime.InteropServices;
using System.Drawing;
public class WinAPI
{
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
public override string ToString()
{
return "(" + left + ", " + top + ") --> (" + right + ", " + bottom + ")";
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string strClassName, string strWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
public static IntPtr GetTrayHandle()
{
IntPtr taskBarHandle = WinAPI.FindWindow("Shell_TrayWnd", null);
if (!taskBarHandle.Equals(IntPtr.Zero))
{
return WinAPI.FindWindowEx(taskBarHandle, IntPtr.Zero, "TrayNotifyWnd", IntPtr.Zero);
}
return IntPtr.Zero;
}
public static Rectangle GetTrayRectangle()
{
WinAPI.RECT rect;
WinAPI.GetWindowRect(WinAPI.GetTrayHandle(), out rect);
return new Rectangle(new Point(rect.left, rect.top), new Size((rect.right - rect.left) + 1, (rect.bottom - rect.top) + 1));
}
}
It is not a perfect solution but I hope this helps.