prevent more than one tray icon in c# - c#

I am developing an application in c#.net,and for that i am writing code to display icon in a system tray,and whenever a new message arrives the balloon tooltip will be shown there,which has click event which will open new message arrived,everything works fine,but the problem is i am getting multiple numbers of icon generated in system tray,which shuld be only one,how can i prevent it?i found on internet how to dispose them,but couldn't find way to prevent more than one.or is there any better way to show notifications for newly received message..please help me if you know the solution..

There are better custom solutions available see here and here for some examples.
However, System Tray doesn't refresh automatically. If you show/hide multiple system tray icons, it can mess the tray up. Normally all disposed icons will disappear when you mouse hover. However, there is a way to refresh the system tray programmatically. Reference here.
Note : SendMessage function, sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
public void RefreshTrayArea()
{
IntPtr systemTrayContainerHandle = FindWindow("Shell_TrayWnd", null);
IntPtr systemTrayHandle = FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
IntPtr sysPagerHandle = FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
IntPtr notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
if (notificationAreaHandle == IntPtr.Zero)
{
notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area");
IntPtr notifyIconOverflowWindowHandle = FindWindow("NotifyIconOverflowWindow", null);
IntPtr overflowNotificationAreaHandle = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area");
RefreshTrayArea(overflowNotificationAreaHandle);
}
RefreshTrayArea(notificationAreaHandle);
}
private static void RefreshTrayArea(IntPtr windowHandle)
{
const uint wmMousemove = 0x0200;
RECT rect;
GetClientRect(windowHandle, out rect);
for (var x = 0; x < rect.right; x += 5)
for (var y = 0; y < rect.bottom; y += 5)
SendMessage(windowHandle, wmMousemove, 0, (y << 16) + x);
}

Related

C# Simulating mouseclicks in game doesn't work

Recently I tried to create a bot for an MMO-Game (called Florensia).
It should click on several positions in the game.
My problem is that it only sets the cursour to the position but the click doesn't work out. If I try it at my desktop or some other programs, it clicks correctly.
The game of course is in windowed mode and I already tried to set delays between the Mouseup and Mousedown.
Also to set the game to foreground window before the click didn't work.
Looking forward to any answers! :)
Try to use WinApi functions like in this example.
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
static void Main(string[] args)
{
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int MK_LBUTTON = 0x0001;
uint x = 100;
uint y = 100;
IntPtr handle = new IntPtr(0x00090996); //Your window handle
SetForegroundWindow(handle);
Thread.Sleep(300);
SendMessage(handle, WM_LBUTTONDOWN, new IntPtr(MK_LBUTTON), new IntPtr(y << 16 | x));
Thread.Sleep(300);
SendMessage(handle, WM_LBUTTONUP, new IntPtr(0), new IntPtr(y << 16 | x));
}

How to get active window that is not part of my application?

How can I get the Window Title that the user currently have focus on?
I'm making a program that runs with another Window, and if the user does not have focus on that window I find no reason for my program to keep updating.
So how can I determine what window the user have focus on?
I did try to look into
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
but I seems I can only use that if the Window is part of my application which is it not.
Check this code:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private string GetActiveWindowTitle()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
Use GetForegroundWindow to retrieve the handle of the focused window and GetWindowText to get the window title.
[ DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[ DllImport("user32.dll") ]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
static void Main() {
StringBuilder builder = new StringBuilder(255) ;
GetWindowText(GetForegroundWindow(), builder, 255) ;
Console.WriteLine(builder) ;
}

Getting a second IE Window to open on a different display

I'm writing a .exe that is supposed to run as a scheduled task to check if I have required IE windows open running .Xbaps on specific monitors. I have code that checks what URL is supposed to run, if it's not I use this code to launch it, then move it to the correct monitor:
Process myProcess = Process.Start("iexplore.exe", "-new -k " + "http://server01:123/software.client.xbap");
myProcess.WaitForInputIdle();
Thread.Sleep(500);
MoveWindowToMonitor(myProcess.MainWindowHandle, 1);
Window Moving code:
private static void MoveWindowToMonitor(IntPtr windowHandler, int monitor)
{
RECT windowRec = new RECT();
GetWindowRect(windowHandler, ref windowRec);
int width = windowRec.Right - windowRec.Left;
int height = windowRec.Top - windowRec.Bottom;
if (width < 0)
width = width * -1;
if (height < 0)
height = height * -1;
SetWindowPos(windowHandler, (IntPtr)SpecialWindowHandles.HWND_TOP, Screen.AllScreens[monitor].WorkingArea.Left,
Screen.AllScreens[monitor].WorkingArea.Top, width, height, SetWindowPosFlags.SWP_SHOWWINDOW);
}
Running a quick test version of this gets the first IE window open, Xbap launched, and then quickly moves it over to my other monitor. When I run it a second time, without closing the first IE window, I always get InvalidOperationException
"Process has exited, so the requested information is not available."
I've checked my Task Manager as this is happening and I actually get two iexplore.exe items under details the first time I run the task, and only one additional iexplorer.exe for each subsequent execution of the task. I also get one PresentationHost.exe per xbap launched.
Anyone have any idea what I'm doing wrong or a better way to do this?
My end goal is to be able to do this:
Launch IE in Kiosk Mode on monitor 1 with specific url X:
Launch IE in Kiosk Mode on monitor 2 with specific url Y:
After you launch an IE process, it does some funny stuff and that process you have launched can occasionally end right away as another takes over the window.
What I would do is, using the methods below, is EnumTheWindows which would step through every visible window running and look for Internet Explorer or my baseURL. Then I would pass that Window Handle to GetURL and get the specific URL that IE window was running. This allowed me to use ConfirmProcessIsOnProperMonitor() and MoveWindowToMonitor() to get the windows on the proper monitor.
Important stuff:
private static bool ConfirmProcessIsOnProperMonitor(IntPtr windowHandler, int monitor)
{
//make sure you don't go to an incorrect monitor
if (monitor >= Screen.AllScreens.Count()) monitor = Screen.AllScreens.Count() - 1;
RECT windowRec = new RECT();
GetWindowRect(windowHandler, ref windowRec);
if (windowRec.Left != Screen.AllScreens[monitor].WorkingArea.Left || windowRec.Top != Screen.AllScreens[monitor].WorkingArea.Top)
return false;
else
return true;
}
private static void MoveWindowToMonitor(IntPtr windowHandler, int monitor)
{
//make sure you don't go to an incorrect monitor
if (monitor >= Screen.AllScreens.Count()) monitor = Screen.AllScreens.Count() - 1;
RECT windowRec = new RECT();
GetWindowRect(windowHandler, ref windowRec);
int width = windowRec.Right - windowRec.Left;
int height = windowRec.Top - windowRec.Bottom;
if (width < 0)
width = width * -1;
if (height < 0)
height = height * -1;
SetWindowPos(windowHandler, (IntPtr)SpecialWindowHandles.HWND_TOP, Screen.AllScreens[monitor].WorkingArea.Left,
Screen.AllScreens[monitor].WorkingArea.Top, width, height, SetWindowPosFlags.SWP_SHOWWINDOW);
}
protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
{
int size = GetWindowTextLength(hWnd);
if (size++ > 0 && IsWindowVisible(hWnd))
{
StringBuilder sb = new StringBuilder(size);
GetWindowText(hWnd, sb, size);
string windowText = sb.ToString();
if (windowText.ToLower().Contains(_baseURL) || windowText.ToLower().Contains("internet explorer"))
{
string url = GetURL(hWnd);
_windowhandles.Add(hWnd, url);
}
}
return true;
}
private static string GetURL(IntPtr intPtr)
{
foreach (InternetExplorer ie in new ShellWindows())
{
if (ie.HWND == intPtr.ToInt32())
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(ie.FullName);
if ((fileNameWithoutExtension != null) && fileNameWithoutExtension.ToLower().Equals("iexplore"))
{
return ie.LocationURL;
}
else
{
return null;
}
}
}
return null;
}
Hard to read windows API code:
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, StringBuilder msgbody);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool IsWindowVisible(IntPtr hWnd);

Outlook security prompt auto approval

I'm writing a function that will allow users to import their e-mails from outlook in to corporate storage. But I've encounter a problem with security promt, and since we still have clients with office 2003 we can't disable it.
I'm trying to autoclick it with this code:
[DllImport("User32.dll")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
private const int WM_LBUTTONDOWN = 0x201;
private const int WM_LBUTTONUP = 0x0202;
private void button1_Click(object sender, EventArgs e)
{
int hwnd = 0;
IntPtr hwndChild = IntPtr.Zero;
while (true)
{
hwnd = FindWindow(null, "Microsoft Outlook");
if (hwnd != 0)
{
hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "Button", "Yes");
if (hwndChild != IntPtr.Zero)
{
SendMessage((int)hwndChild, WM_LBUTTONDOWN, 0, IntPtr.Zero);
SendMessage((int)hwndChild, WM_LBUTTONUP, 0, IntPtr.Zero);
}
else
{
//...
}
}
else
{
//...
}
hwnd = 0;
}
}
But when I'm trying to use that code I've encounter unexpected problem. Security promt will only disappear only when I'm actually performing mouse click no matter where even on some empty screen space. What is wrong with it?
Try out MAPILab's Advanced Security for Outlook. Should also work for Outlook 2003. This will let you give a permanent access for your application - a pop-up window will show only the first time you access Outlook items:
http://www.mapilab.com/outlook/security/
Advanced Security will have to be installed on each machine you run your app. It's free for noncommercial and commercial use.
You should try using SendKeys and send Y for Yes.

Interact with a form using handle C#

I am trying to automate a dynamically appearing dialogue box.
I need to pass text to it,s text field and then press a button over this.
What I have tried so far.
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
IntPtr handle= FindWindowByCaption(System.IntPtr.Zero, "Caption Of File");
I am getting the handle of dialogue box correctly.
List<IntPtr> childWindows= GetChildWindows(handle);//To get the child controls in this dialogue box
Source
But when I try to cast it to control I get null.
foreach (IntPtr i in childWindows)
{
Control c = Control.FromHandle(i);
}
So can any body tell what is wrong.I am supposing that I shall cast handle to control and then interact with control properties(e.g: text).
I've been using code like this sucessfully for years to perform single sign on to an application that prompts the user for their username/pwd/domain. The only caution is you need to know the control structure of the dialog you're targeting, but this is easily accomplished with Spy++ and rarely changes. Of course you will need to modify this code for the control structure of your window.
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,
string lpszClass, string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, string lParam);
[DllImport("User32.Dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
private const uint WM_GETTEXTLENGTH = 0x000E;
private const uint WM_SETTEXT = 0x000C;
private const uint WM_GETTEXT = 0x000D;
private const uint BM_CLICK = 0x00F5;
private const uint WM_CLOSE = 0x0010;
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
var dialog FindWindow("optionalClassNameHere", "Log On"); //Get the handle of the window
var w3 = GetWindow(dialog , (uint)GetWindow_Cmd.GW_CHILD); //I use GetWindow to walk the window controls
var wUid = FindWindowEx(w3, IntPtr.Zero, "Edit", "");
var w4 = GetWindow(wUid, (uint)GetWindow_Cmd.GW_HWNDNEXT);
var wPwd = FindWindowEx(w4 , IntPtr.Zero, "Edit", "");
var wOK = FindWindowEx(w3, IntPtr.Zero, "Button", "OK");
SendMessage(wUid, WM_SETTEXT, 0, _WinDomain + "\\" + Username); //Send username to username edit control
SendMessage(wPwd, WM_SETTEXT, 0, Password); //Send password to password edit control
PostMessage(wOK, BM_CLICK, 0, 0); //Send left click(0x00f5) to OK button
Control.FromHandle can only work for controls in your process that are implemented by Control descendents. I'd guess this window is outside your process.
You need to use Win32 API methods to modify it.

Categories