locked
How to get screen coordinates of NotifyIcon RRS feed

  • Question

  • My app uses a NotifyIcon component in the system tray.  I'd like to get the screen coordinates of it, at any time.  Any valid x,y within it's bounding rectangle, preferrably the center of it.  Is there a way to do this?  I can get it if I catch mouse events and use GetCursorPos() api, etc.  However, i'd like to get it at other times, when NotifyIcon may not be firing  any events.
    Saturday, July 7, 2007 4:09 PM

Answers

  • Peter thank you for your insight.  I have done alot of research on this and have created a solution(however, very lengthy) below.  Because of the delicate nature of this code and my lack of good PInvoke knowledge, I would really appreciate any advice on how to code this better to make maybe more efficient, avoid any pitfalls others might encounter, avoid access violations, etc.  I have tested this on Windows Vista Ultimate with UAC on and off and it works perfect.

     

     

     

     

    class Class1

    {

    const uint WM_USER = 1024;

    const uint TB_HIDEBUTTON = (WM_USER + 4);

    const uint TB_BUTTONCOUNT = (WM_USER + 24);

    const uint TB_GETBUTTON = (WM_USER + 23);

    const uint TB_GETITEMRECT = (WM_USER + 29);

    const uint TBSTATE_HIDDEN = 0x08;

    const uint PROCESS_ALL_ACCESS = 0x1F0FFF;

    const uint MEM_COMMIT = 0x1000;

    const uint MEM_RELEASE = 0x8000;

    const uint PAGE_READWRITE = 0x04;

     

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]

    struct TBBUTTON

    {

    public int iBitmap;

    public int idCommand;

    public byte fsState;

    public byte fsStyle;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]

    public byte[] bReserved;

    public UInt32 dwData;

    public Int32 iString;

    }

    [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

    internal struct RECT

    {

    public int Left;

    public int Top;

    public int Right;

    public int Bottom;

    public RECT(int left, int top, int right, int bottom)

    {

    Left = left;

    Top = top;

    Right = right;

    Bottom = bottom;

    }

    public int Height { get { return Bottom - Top; } }

    public int Width { get { return Right - Left; } }

    public Size Size { get { return new Size(Width, Height); } }

    }

     

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 lpdwProcessId);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, ref RECT lpPoints, UInt32 cPoints);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern IntPtr OpenProcess(uint dwDesiredAccess, Int32 bInheritHandle, Int32 dwProcessId);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern Int32 VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, uint dwFreeType);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern Int32 CloseHandle(IntPtr hObject);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] lpBuffer, Int32 nSize, out Int32 lpNumberOfBytesRead);

     

    public bool GetNotifyIconScreenRect()

    {

    // NotifyIcon hidden window handle from reflection, IntPtr.Zero if failure

    IntPtr hWndNotifyIconHandle = (IntPtr)4002;//GetNotifyIconHandle(); THIS IS ONLY A TEST VALUE

     

    //NotifyIcon Icon ID from reflection, -1 if failure

    int intNotifyIconID = 1;// GetNotifyIconID(); THIS IS ONLY A TEST VALUE

     

    if (hWndNotifyIconHandle == IntPtr.Zero || intNotifyIconID == -1) { return false; }

    // Static value for test, HWND of "Notification Area" ToolbarWindow32 window  THIS IS ONLY A TEST VALUE

    IntPtr hWndTray = (IntPtr)0x0001005A;

     

    Int32 dwTrayProcessID = -1;

    GetWindowThreadProcessId(hWndTray, out dwTrayProcessID);

    if (dwTrayProcessID <= 0) { return false; }

     

    IntPtr hTrayProc = OpenProcess(PROCESS_ALL_ACCESS, 0, dwTrayProcessID);

    if (hTrayProc == IntPtr.Zero) { return false; }

     

    int intTrayButtonCount = (int)SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0);

    if (intTrayButtonCount <= 0) { return false; }

     

    TBBUTTON tbButtonData = new TBBUTTON();

    IntPtr lpData = VirtualAllocEx(hTrayProc, IntPtr.Zero,

    Marshal.SizeOf(tbButtonData.GetType()), MEM_COMMIT, PAGE_READWRITE);

    if (lpData == IntPtr.Zero) { CloseHandle(hTrayProc); return false; }

     

    bool bIconFound = false;

    for (int intButton = 0; intButton < intTrayButtonCount; intButton++)

    {

    // Get button data

    Int32 dwBytesRead = -1;

    byte[] byteBuffer = new byte[Marshal.SizeOf(tbButtonData.GetType())];

     

    SendMessage(hWndTray, TB_GETBUTTON, intButton, lpData);

    ReadProcessMemory(hTrayProc, lpData, byteBuffer, Marshal.SizeOf(tbButtonData.GetType()),

    out dwBytesRead);

    if (dwBytesRead < Marshal.SizeOf(tbButtonData.GetType())) { continue; }

     

    IntPtr ptrOut = Marshal.AllocHGlobal(Marshal.SizeOf(tbButtonData.GetType()));

    Marshal.Copy(byteBuffer, 0, ptrOut, byteBuffer.Length);

    tbButtonData = (TBBUTTON)Marshal.PtrToStructure(ptrOut, typeof(TBBUTTON));

     

     

    // Get extra button data from .dwData base address

    dwBytesRead = -1;

    Int32[] dwExtraData = new Int32[2] { 0, 0 };

    byte[] byteBuffer2 = new byte[Marshal.SizeOf(dwExtraData[0].GetType()) * dwExtraData.Length];

     

    int intRetval2 = ReadProcessMemory(hTrayProc, (IntPtr)tbButtonData.dwData, byteBuffer2,

    (Marshal.SizeOf(dwExtraData[0].GetType()) * dwExtraData.Length), out dwBytesRead);

    if (dwBytesRead < (Marshal.SizeOf(dwExtraData[0]) * dwExtraData.Length)) { continue; }

     

    dwExtraData[1] = BitConverter.ToInt32(byteBuffer2, (byteBuffer2.Length / 2));

    Array.Resize(ref byteBuffer2, (byteBuffer2.Length / 2));

    dwExtraData[0] = BitConverter.ToInt32(byteBuffer2, 0);

     

    IntPtr hWndCurrentIconHandle = (IntPtr)dwExtraData[0];

    int intCurrentIconID = (int)dwExtraData[1];

    // Spin if this is not the target tray icon

    if (hWndCurrentIconHandle != hWndNotifyIconHandle || intCurrentIconID != intNotifyIconID)

    continue;

    // Show tray icon if hidden

    if ((tbButtonData.fsState & (byte)TBSTATE_HIDDEN) == (byte)TBSTATE_HIDDEN)

    SendMessage(hWndTray, TB_HIDEBUTTON, intButton, 1);

    // Get rectangle of tray icon

    dwBytesRead = -1;

    RECT rectNotifyIcon = new RECT(0, 0, 0, 0);

    byte[] byteBuffer3 = new byte[Marshal.SizeOf(rectNotifyIcon.GetType())];

     

    SendMessage(hWndTray, TB_GETITEMRECT, intButton, lpData);

    ReadProcessMemory(hTrayProc, lpData, byteBuffer3, Marshal.SizeOf(rectNotifyIcon.GetType()),

    out dwBytesRead);

    if (dwBytesRead < Marshal.SizeOf(rectNotifyIcon.GetType())) { continue; }

     

    IntPtr ptrOut2 = Marshal.AllocHGlobal(Marshal.SizeOf(rectNotifyIcon.GetType()));

    Marshal.Copy(byteBuffer3, 0, ptrOut2, byteBuffer3.Length);

    rectNotifyIcon = (RECT)Marshal.PtrToStructure(ptrOut2, typeof(RECT));

    MapWindowPoints(hWndTray, IntPtr.Zero, ref rectNotifyIcon, 2);

     

    // Display coordinates

    System.Diagnostics.Debug.Print("ICONS COORDINATES ARE: Top: {0}, Left: {1}, Bottom: {2}, Right: {3}",

    rectNotifyIcon.Top, rectNotifyIcon.Left, rectNotifyIcon.Bottom, rectNotifyIcon.Right);

    bIconFound = true;

    break;

    }

     

    // Free memory in parent process for system tray and close handle

    VirtualFreeEx(hTrayProc, lpData, 0, MEM_RELEASE);

    CloseHandle(hTrayProc);

     

    // return result to caller

    return bIconFound;

    }

    }

    Thursday, July 12, 2007 4:19 AM

All replies

  • There's no documented or supported way of doing that.  Why do you want to do that?  Maybe there's an alternative...
    Saturday, July 7, 2007 4:45 PM
  • I have been building a custom class wrapper for NotifyIcon which has a new interface method, ShowFormTip().  It will mimick what ShowBalloonTip() does basically, except show a reference to a form you provide, in my case form's that are doctored to look like tooltips.  Worst case, eventually at some point, a user will have to mouse over the Icon for the component and I can capture and store the output of GetCursorPos(), however i'd prefer not doing that.
    Saturday, July 7, 2007 4:49 PM
  • The position of an icon in the notification tray is not constant.  The "Hide inactive icons" feature of XP basically means the position of the NotifyIcons can change constantly.  As other applications exit they may remove their icons and that will affect the position of all other icons.  Of course, you won't know if the system changed the position of your icon after you first got the coordinates of the mouse, and it won't tell you if other icons have left the notification tray.

     

    I think you'll have to go the same route as other applications that don't find the balloon tips sufficient by simply displaying a toaster form that doesn't associate to a particular icon in the notification tray.  Like Outlook, or RSS Bandit, for example.

    Saturday, July 7, 2007 7:08 PM
  • I understand everything your saying.   Another would be redocking the taskbar to a different edge.  I'll go ahead and forget that mouse capture idea.   Could this be achieved by setting a native C hook in an external dll and responding to messages on the taskbar?  That seems like the only route to take at this point if I want that tray icon's location.
    Saturday, July 7, 2007 8:39 PM
  • Well, the icon area of the notification area is implemented as a ToolbarWindow32-class window--which is wrapped by the ToolBar class.  But, because the notification tray is in another process you can't use the ToolBar class to manipulate/query it.  A ToolbarWindow32-class window has a set of messages that it supports; but you run into the same problem as the ToolBar class; because it is in a different process you don't have access to that process's memory and it doesn't have access to yours.  (so sending it a message with a pointer to memory like a TBBUTTONINFO structure will result in an access violation in a system process, like explorer.exe).

     

    I believe in Vista there's new restrictions on whether applications can send messages like that to other applications.

    Saturday, July 7, 2007 8:55 PM
  • Peter thank you for your insight.  I have done alot of research on this and have created a solution(however, very lengthy) below.  Because of the delicate nature of this code and my lack of good PInvoke knowledge, I would really appreciate any advice on how to code this better to make maybe more efficient, avoid any pitfalls others might encounter, avoid access violations, etc.  I have tested this on Windows Vista Ultimate with UAC on and off and it works perfect.

     

     

     

     

    class Class1

    {

    const uint WM_USER = 1024;

    const uint TB_HIDEBUTTON = (WM_USER + 4);

    const uint TB_BUTTONCOUNT = (WM_USER + 24);

    const uint TB_GETBUTTON = (WM_USER + 23);

    const uint TB_GETITEMRECT = (WM_USER + 29);

    const uint TBSTATE_HIDDEN = 0x08;

    const uint PROCESS_ALL_ACCESS = 0x1F0FFF;

    const uint MEM_COMMIT = 0x1000;

    const uint MEM_RELEASE = 0x8000;

    const uint PAGE_READWRITE = 0x04;

     

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]

    struct TBBUTTON

    {

    public int iBitmap;

    public int idCommand;

    public byte fsState;

    public byte fsStyle;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]

    public byte[] bReserved;

    public UInt32 dwData;

    public Int32 iString;

    }

    [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

    internal struct RECT

    {

    public int Left;

    public int Top;

    public int Right;

    public int Bottom;

    public RECT(int left, int top, int right, int bottom)

    {

    Left = left;

    Top = top;

    Right = right;

    Bottom = bottom;

    }

    public int Height { get { return Bottom - Top; } }

    public int Width { get { return Right - Left; } }

    public Size Size { get { return new Size(Width, Height); } }

    }

     

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 lpdwProcessId);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, ref RECT lpPoints, UInt32 cPoints);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern IntPtr OpenProcess(uint dwDesiredAccess, Int32 bInheritHandle, Int32 dwProcessId);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern Int32 VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, uint dwFreeType);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern Int32 CloseHandle(IntPtr hObject);

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]

    static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] lpBuffer, Int32 nSize, out Int32 lpNumberOfBytesRead);

     

    public bool GetNotifyIconScreenRect()

    {

    // NotifyIcon hidden window handle from reflection, IntPtr.Zero if failure

    IntPtr hWndNotifyIconHandle = (IntPtr)4002;//GetNotifyIconHandle(); THIS IS ONLY A TEST VALUE

     

    //NotifyIcon Icon ID from reflection, -1 if failure

    int intNotifyIconID = 1;// GetNotifyIconID(); THIS IS ONLY A TEST VALUE

     

    if (hWndNotifyIconHandle == IntPtr.Zero || intNotifyIconID == -1) { return false; }

    // Static value for test, HWND of "Notification Area" ToolbarWindow32 window  THIS IS ONLY A TEST VALUE

    IntPtr hWndTray = (IntPtr)0x0001005A;

     

    Int32 dwTrayProcessID = -1;

    GetWindowThreadProcessId(hWndTray, out dwTrayProcessID);

    if (dwTrayProcessID <= 0) { return false; }

     

    IntPtr hTrayProc = OpenProcess(PROCESS_ALL_ACCESS, 0, dwTrayProcessID);

    if (hTrayProc == IntPtr.Zero) { return false; }

     

    int intTrayButtonCount = (int)SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0);

    if (intTrayButtonCount <= 0) { return false; }

     

    TBBUTTON tbButtonData = new TBBUTTON();

    IntPtr lpData = VirtualAllocEx(hTrayProc, IntPtr.Zero,

    Marshal.SizeOf(tbButtonData.GetType()), MEM_COMMIT, PAGE_READWRITE);

    if (lpData == IntPtr.Zero) { CloseHandle(hTrayProc); return false; }

     

    bool bIconFound = false;

    for (int intButton = 0; intButton < intTrayButtonCount; intButton++)

    {

    // Get button data

    Int32 dwBytesRead = -1;

    byte[] byteBuffer = new byte[Marshal.SizeOf(tbButtonData.GetType())];

     

    SendMessage(hWndTray, TB_GETBUTTON, intButton, lpData);

    ReadProcessMemory(hTrayProc, lpData, byteBuffer, Marshal.SizeOf(tbButtonData.GetType()),

    out dwBytesRead);

    if (dwBytesRead < Marshal.SizeOf(tbButtonData.GetType())) { continue; }

     

    IntPtr ptrOut = Marshal.AllocHGlobal(Marshal.SizeOf(tbButtonData.GetType()));

    Marshal.Copy(byteBuffer, 0, ptrOut, byteBuffer.Length);

    tbButtonData = (TBBUTTON)Marshal.PtrToStructure(ptrOut, typeof(TBBUTTON));

     

     

    // Get extra button data from .dwData base address

    dwBytesRead = -1;

    Int32[] dwExtraData = new Int32[2] { 0, 0 };

    byte[] byteBuffer2 = new byte[Marshal.SizeOf(dwExtraData[0].GetType()) * dwExtraData.Length];

     

    int intRetval2 = ReadProcessMemory(hTrayProc, (IntPtr)tbButtonData.dwData, byteBuffer2,

    (Marshal.SizeOf(dwExtraData[0].GetType()) * dwExtraData.Length), out dwBytesRead);

    if (dwBytesRead < (Marshal.SizeOf(dwExtraData[0]) * dwExtraData.Length)) { continue; }

     

    dwExtraData[1] = BitConverter.ToInt32(byteBuffer2, (byteBuffer2.Length / 2));

    Array.Resize(ref byteBuffer2, (byteBuffer2.Length / 2));

    dwExtraData[0] = BitConverter.ToInt32(byteBuffer2, 0);

     

    IntPtr hWndCurrentIconHandle = (IntPtr)dwExtraData[0];

    int intCurrentIconID = (int)dwExtraData[1];

    // Spin if this is not the target tray icon

    if (hWndCurrentIconHandle != hWndNotifyIconHandle || intCurrentIconID != intNotifyIconID)

    continue;

    // Show tray icon if hidden

    if ((tbButtonData.fsState & (byte)TBSTATE_HIDDEN) == (byte)TBSTATE_HIDDEN)

    SendMessage(hWndTray, TB_HIDEBUTTON, intButton, 1);

    // Get rectangle of tray icon

    dwBytesRead = -1;

    RECT rectNotifyIcon = new RECT(0, 0, 0, 0);

    byte[] byteBuffer3 = new byte[Marshal.SizeOf(rectNotifyIcon.GetType())];

     

    SendMessage(hWndTray, TB_GETITEMRECT, intButton, lpData);

    ReadProcessMemory(hTrayProc, lpData, byteBuffer3, Marshal.SizeOf(rectNotifyIcon.GetType()),

    out dwBytesRead);

    if (dwBytesRead < Marshal.SizeOf(rectNotifyIcon.GetType())) { continue; }

     

    IntPtr ptrOut2 = Marshal.AllocHGlobal(Marshal.SizeOf(rectNotifyIcon.GetType()));

    Marshal.Copy(byteBuffer3, 0, ptrOut2, byteBuffer3.Length);

    rectNotifyIcon = (RECT)Marshal.PtrToStructure(ptrOut2, typeof(RECT));

    MapWindowPoints(hWndTray, IntPtr.Zero, ref rectNotifyIcon, 2);

     

    // Display coordinates

    System.Diagnostics.Debug.Print("ICONS COORDINATES ARE: Top: {0}, Left: {1}, Bottom: {2}, Right: {3}",

    rectNotifyIcon.Top, rectNotifyIcon.Left, rectNotifyIcon.Bottom, rectNotifyIcon.Right);

    bIconFound = true;

    break;

    }

     

    // Free memory in parent process for system tray and close handle

    VirtualFreeEx(hTrayProc, lpData, 0, MEM_RELEASE);

    CloseHandle(hTrayProc);

     

    // return result to caller

    return bIconFound;

    }

    }

    Thursday, July 12, 2007 4:19 AM
  • Nice.  I don't notice anything that would make it noticeably more efficient.  I would suggest using SafeHandle for the result of OpenProcess (i.e. deriving a class from SafeHandleZeroOrMinusOneIsInvalid) and use the Disposable pattern to ensure it's closed.  I would also suggest ensuring VirtualFreeEx is called in a finally block to avoid memory leaks.

     

    Possibly, updating the icon somehow to get windows to re-show the icon might be better than changing a button's hidden state.

     

    How does it work when you dock the taskbar to the left, right or top of the screen?

    Thursday, July 12, 2007 4:43 AM
  • All RECT data looks correct when docking the appbar to any screen edge.   Haven't tried it with multi-mon yet, however it should work, i'm targetting the screen object for the hWnd returned by SHAppBarMessage/ABM_GETTASKBARPOS.    Thanks again for the additional advice.

     

    If anyone else has personal opinions, strong advice, i'd appreciate it...

    Thursday, July 12, 2007 6:03 AM
  • Hi all,
    i m having a problem, wish you expertrs will help me a lil to solve

    I have my Custom Command button on IE toolbar placed along with home,refresh buttons.
    i want to change its image using sendmessage win32 call in c#.net.

    Currently i have access to TBBUTTON objects structure in memory.
    I wnt to get string of TEXT


    problem 1: i want to get text from buffer to identify my custom command button..
    i have used
     lresult = SendMessage(hWnd, (IntPtr)TB_GETBUTTONTEXTW, (IntPtr)tbButtonData.idCommand, ref tbButtonData);      
    this returns length of command button text.
    This is fine... BUT i want text.

    problem 2: when i get my custom command, i want to change its IMAGE.

    i have used
    IntPtr ImList = SendMessage(hWnd, (IntPtr)TB_GETIMAGELIST, (IntPtr)0, (IntPtr)0);
                                  IntPtr iconhandle = IntPtr.Zero;
                                  System.Drawing.Bitmap image =new System.Drawing.Bitmap("D:\\closed24x24 copy.bmp");
                                  iconhandle = image.GetHbitmap();
                                  tbButtonData.iBitmap = ImageList_AddIcon((int)ImList, (int)iconhandle);     
    But it returns -1

    I tried to find sample in c#.. but havent got any useful post.

    Hope u guys can solve my problem. Please give me soln for 1 & 2 problems.




    Friday, July 27, 2007 5:29 AM
  • HI i m also sailing in the same boat,

    i want to access the pop-up right click menu items on the icon available in the system tray icon,

    please help me out how to access the same.

    I need the idea which function in which dll etc

    As i need to automate the application using perl

    Please do the needfulll

    Thanks & regards

    Badareesh

     

     

     

    Monday, August 6, 2007 5:21 PM
  • Hi,

    just in case someone looks a this thread (as I did) long time after creating it:

    There is a solution to this.
    If you use the Click event from the notification icon, you can examine the position of the mouse with ths static method
    Control.MousePosition.

    If you pop up the menu (or whatever it is) at this point, it will be beneath the notification icon.
    (tested in a multi-monitor environment)

    Guenter from Frankfurt/Germany

    WM_JUSTMYTWOCENTS
    Thursday, January 22, 2009 12:06 PM
  • Here's my solution to this problem.  Using the timer is a bit of a hack.  Capturing the system mouse move event would probably be a better solution, but this seems to work.


    Public Class Form1
    
    Private m_ptMouse As Drawing.Point
    
    Private Sub NotifyIcon1_MouseMove(ByVal sender As System.Object, _
    	ByVal e As System.Windows.Forms.MouseEventArgs) _
    	Handles NotifyIcon1.MouseMove
    
    	m_ptMouse = Cursor.Position
    
    	If Timer1.Enabled = False Then
    		Timer1.Interval = 200
    		Timer1.Enabled = True
    		Debug.WriteLine("In")
    	End If
    End Sub
    
    Private Sub Timer1_Tick(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) _
    Handles Timer1.Tick If Cursor.Position <> m_ptMouse Then Timer1.Enabled = False Debug.WriteLine("Out") End If End Sub End Class
    Monday, April 20, 2009 7:02 PM