Tray button handles in Windows 10 - winapi

I have a project that I developed about seven years ago in Win95, and works in Win7. It is developed in Visual Studio 2005. This application looks for the "You have new email" tray icon that appears in the tray (in various forms) by most email applications. I use it to blink an LED on a serial port, so I can glance in the room to see if I have email, rather than going to the computer, moving the mouse to wake the screen, and looking at the tray or the email program itself. It's a time-saver and aggravation-reducer.
It works by getting the system tray handle, and then using this handle, iterates all the buttons in the tray, and comparing the button text for a specific string. Here is the part that is having a problem in Windows 10:
IntPtr hWndTray = GetSystemTrayHandle();
listBoxIcons.Items.Add(string.Format("Tray handle=0x{0:X}", (int)hWndTray));
UInt32 count = User32.SendMessage(hWndTray, TB.BUTTONCOUNT, 0, 0);
listBoxIcons.Items.Add(string.Format("Tray button count={0:D}", count));
The call to GetSystemTrayHandle() works fine, I get a non-null value. The call to SendMessage(hWndTray, TB.BUTTONCOUNT, ...) returns zero, even though in the test case I'm using, there are nine buttons in the tray.
Did the concept of "tray icons", or the API calls to get them, change in Windows 10?
Here are the API calls I am using:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
From User32.cs:
internal class TB
{
public const uint GETBUTTON = WM.USER + 23 ;
public const uint BUTTONCOUNT = WM.USER + 24 ;
public const uint CUSTOMIZE = WM.USER + 27 ;
public const uint GETBUTTONTEXTA = WM.USER + 45 ;
public const uint GETBUTTONTEXTW = WM.USER + 75 ;
}
Here is the GetSystemTrayHandle() method:
private IntPtr GetSystemTrayHandle()
{
IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "TrayNotifyWnd", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "SysPager", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "ToolbarWindow32", null);
return hWndTray;
}
}
}
return IntPtr.Zero;
}
The "SendMessage" call has existed since about the inception of Windows, so if it no longer works, TB.BUTTONCOUNT may have been redefined or superceded in Windows 10. I cannot find any information on this.
Edit: Developed on Win98, not Win95.

Remy's message spurred further research into notification icons. The answer was found using information at http://www.ghacks.net/2015/03/11/manage-and-display-system-tray-icons-in-windows-10/. Once notifications were enabled, for example "email" and "volume," this program, as written, can now see them.

Related

make webcam device invisible to a process

Some context:
I have an application that opens the first webcam device on Windows 10 64bit (whatever index 0 is during enumeration of devices) and does some processing on the frames. The application's source code is not accessible.
Question:
I need to make this application to work with two webcams at the same time. I thought maybe there is a way to do the following:
hide webcam 2
run application (picks up webcam 1)
hide webcam 1, unhide webcam 2
run application (picks up webcam 2)
Is there a way to do this without interrupting camera's operation? Note that both applications are running at the same time so hard-disabling a camera is not an option. Calling either a Win32 api or doing this in PowerShell is acceptable.
Thanks!
Thanks to comments on my original question, I managed to solve my problem by hooking into CM_Get_Device_Interface_List_ExW Win32 API call.
I had to verify what API is being called, so I used and API tracer tool (API monitor v2 64bit). Debugger should work too but for some reason my VS debugger did not show me any symbols (possibly missing pdbs).
The original process I tried to hook into is written in C# so I hooked into the call via an injected C# DLL containing EasyHook. Here is my code snippet (actual injection code left out):
using System;
using System.Runtime.InteropServices;
using EasyHook;
public class HookDevices : IEntryPoint
{
LocalHook FunctionLocalHook;
// construct this to hook into calls
HookDevices()
{
try
{
FunctionLocalHook = LocalHook.Create(
LocalHook.GetProcAddress("CfgMgr32.dll", "CM_Get_Device_Interface_List_ExW"),
new FunctionHookDelegate(CM_Get_Device_Interface_List_Ex_Hooked),
this);
FunctionLocalHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
}
catch (Exception ExtInfo)
{
Debug.LogException(ExtInfo);
return;
}
}
[UnmanagedFunctionPointer(CallingConvention.StdCall,
CharSet = CharSet.Unicode,
SetLastError = true)]
delegate uint FunctionHookDelegate(
ref Guid interfaceClassGuid,
string deviceID,
IntPtr buffer,
uint bufferLength,
uint flags,
IntPtr hMachine);
[DllImport("CfgMgr32.dll",
CharSet = CharSet.Unicode,
SetLastError = true,
CallingConvention = CallingConvention.StdCall)]
static extern uint CM_Get_Device_Interface_List_ExW(
ref Guid interfaceClassGuid,
string deviceID,
IntPtr buffer,
uint bufferLength,
uint flags,
IntPtr hMachine);
// this is where we are intercepting all API accesses!
static uint CM_Get_Device_Interface_List_Ex_Hooked(
ref Guid interfaceClassGuid,
string deviceID,
IntPtr buffer,
uint bufferLength,
uint flags,
IntPtr hMachine)
{
// pass-through original API
uint ret = CM_Get_Device_Interface_List_ExW(
ref interfaceClassGuid,
deviceID,
buffer,
bufferLength,
flags,
hMachine);
// do custom logic here and re-arrange "buffer"
return ret;
}
}

SetForegroundWindow isn't working on windows mobile 6.5

I have a auto log off functionality on my application. Which activates based on settings. When user make a re-login with different username then I have to dispose the existing form.
Here comes the main problem.
When a user open the application from file browser of mobile and re-login with different username then the application goes to background.File explorer comes on front.
To overcome this problem i have used SetForegroundWindow of coredll.dll
But it isn't working.
I made a track of current process.And put it to a Global place.
[DllImport("coredll.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
if (_autoLogOff)
{
if (cboUsers.Text != Globals.UserName)
{
List<frmAutoLogOff> openedForms = Globals.OpenedForms;
for (int i = openedForms.Count - 1; i >= 0; i--)
{
if (openedForms[i] != null && openedForms[i].Name != "frmMenu1")
{
//openedForms[i].SuspendLayout();
openedForms[i].Dispose();
}
}
}
SetForegroundWindow(currentProcess);
Globals.UserName = cboUsers.Text;
CDataAccess.ShowMessageForUser();
}
Any suggestion or solution will cordially accepted.
Use FindWindow to SetForgroundWindow
// For Windows Mobile, replace user32.dll with coredll.dll
[DllImport("coredll.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
Set text of ur frmMainMenu1.cs suppose "MainMenu" and call them at proper place
public int FindWindow(string windowName, bool wait)
{
int hWnd = FindWindow(null, windowName).ToInt32();
while (wait && hWnd == 0)
{
System.Threading.Thread.Sleep(500);
hWnd = FindWindow(null, windowName).ToInt32();
}
return hWnd;
}
And call this
int hWnd = FindWindow("MainMenu", wait);
if (hWnd != 0)
{
return SetForegroundWindow((IntPtr)hWnd);
}

How to determine if app is really not responding as shown in Task Manager

My specific problem:
I need to develop a watchdog app that needs to keep various applications running.
I am using visual studio and a windows environment that supports .net 4.0
Since I am not creating those applications and I do not have access to modify them in any way I can only rely on the information provided by windows.
For the past week I've been trying to find exactly how to get the "not responding" property as shown in task manager for an application.
I have tried:
1 Using system diagnostics, getting the process information and interpreting the information within. The problem is, when an app stops working (crashes) the process is still running, the JIT Debugger message pops and reports the app crashed. At this particular moment Task Manager reports the app "Not responding" but the process information (although it does have a main window handle ) has the property Responding set to "true".
I found a lot of open source task managers (top 5) and all use the "Responding" property to determine if a application is running.
So the problem is : task manager shows not responding, Process property responding = True, this method to determine if an app is not responding is INVALID
2 Sending timeout messages to the main window handler.
I used the SendMessageTimeout functions
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644952(v=vs.85).aspx
*I used the SMTO_ABORTIFHUNG, SMTO_BLOCK, SMTO_NORMAL, SMTO_NOTIMEOUTIFNOTHUNG and SMTO_ERRORONEXIT
And encountered the same problem:
-before the application crashes: reports running ( all messages return 1)
-after the application crashes (JIT debugger popup reports app crashed and displayed "Not Responding" in task manager) all the above messages sent to the process window handler return 1 .
So this method to determine if app is not responding is also INVALID
I am amazed I haven't been able to find relevant resources related to my issue.
Here is some code from what I've tried:
bool IsResponding(Process process)
{
HandleRef handleRef = new HandleRef(process, process.MainWindowHandle);
int timeout = 2000;
IntPtr lpdwResult;
IntPtr lResult = SendMessageTimeout(
handleRef,
0,
IntPtr.Zero,
IntPtr.Zero,
1,
1000,
out lpdwResult);
lResult = SendMessageTimeout(
handleRef,
0,
IntPtr.Zero,
IntPtr.Zero,
2,
1000,
out lpdwResult);
lResult = SendMessageTimeout(
handleRef,
0,
IntPtr.Zero,
IntPtr.Zero,
0,
1000,
out lpdwResult);
lResult = SendMessageTimeout(
handleRef,
0,
IntPtr.Zero,
IntPtr.Zero,
8,
1000,
out lpdwResult);
lResult = SendMessageTimeout(
handleRef,
0,
IntPtr.Zero,
IntPtr.Zero,
20,
1000,
out lpdwResult);
return lResult != IntPtr.Zero;
}
and the testing part:
processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension("...testAppLocation.exe"));
bool test = processes[0].Responding;
test = asd.IsResponding(processes[0]);
I've run the sample in debug mode so I am sure all the messages return 1 as a value whether the actual application is running or it is crashed.
And "processes[0]" was tested against a real process and does have the process information
at runtime.
I am out of ideas and I still haven't figured out what resources Task manager uses to determine an application is "Not Responding".
The first solution, provided with the help of Hans Passant would look like this:
Functions to get active windows (including hung ):
internal static class NativeMethods{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsHungAppWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern Int32 EnumWindows(EnumWindowsCallback lpEnumFunc, Int32 lParam);
[DllImport("user32.dll")]
public static extern void GetWindowText(IntPtr hWnd, StringBuilder lpString, Int32 nMaxCount);
[DllImport("user32.dll")]
static extern UInt64 GetWindowLongA(IntPtr hWnd, Int32 nIndex);
public static readonly Int32 GWL_STYLE = -16;
public static readonly UInt64 WS_VISIBLE = 0x10000000L;
public static readonly UInt64 WS_BORDER = 0x00800000L;
public static readonly UInt64 DESIRED_WS = WS_BORDER | WS_VISIBLE;
public delegate Boolean EnumWindowsCallback(IntPtr hwnd, Int32 lParam);
public static List<WindowWrapper> GetAllWindows()
{
List<WindowWrapper> windows = new List<WindowWrapper>();
StringBuilder buffer = new StringBuilder(100);
EnumWindows(delegate(IntPtr hwnd, Int32 lParam)
{
if ((GetWindowLongA(hwnd, GWL_STYLE) & DESIRED_WS) == DESIRED_WS)
{
GetWindowText(hwnd, buffer, buffer.Capacity);
WindowWrapper wnd = new WindowWrapper();
wnd.handle = hwnd;
wnd.title = buffer.ToString();
windows.Add(wnd);
}
return true;
}, 0);
return windows;
}
.
.
.
What I put in my is hung check-er function:
Note that for each app that is hung (JIT debugger pop-up saying it's not working)
You will get 2 entries with the same window handler title:
The app original window handler - which is taken over by the jit debugger will return
false (that means it's not hung) while for the other entry -which is assigned a new
IntPtr the IsHungAppWindow will return true
foreach (var wnd in NativeMethods.GetAllWindows())
{
Console.WriteLine(wnd.title + " and status is " + IsHungAppWindow(wnd.Handle));
}
If anyone has other specific, tested solutions to this issue I would greatly appreciate them.
You'll need to pinvoke IsHungAppWindow(). It returns true when the window is replaced by the ghost window that displays "Not responding".
And keep in mind that this never means that the app crashed and not that often means that the app is actually hung. Certainly not on my pokey laptop when it tries to run VS2010+. Or most any Winforms or WPF app written by a programmer that hasn't yet mastered the art of threading. So don't just arbitrarily kill processes.

HidD_SetFeature() works great, HidD_GetFeature() fails with ERROR_CRC (23). What could cause this?

I'm developing a USB device as a standard HID keyboard with an 8-byte feature report added to the report descriptor; I'm writing an host app to configure the device. I'm trying to adapt the wonderful HidLibrary to utilize the HidD_GetFeature() function in hid.dll.
Before I start posting c# code, I will say that I have successfully tested my firmware using the SimpleHidWrite utility with both Get and Set Feature commands, so I'm fairly confident that's not the issue.
The HidD_SetFeature() function, as wrapped in the HidLibrary API, works great. I can write 8 bytes to the device and I've verified using the SimpleHidWrite tool that they are stored correctly. However, I can't pull those bytes back using HidD_GetFeature(), and I'm baffled as to why.
Here are what I believe to be the pertinent details.
First, the CreateFile call built into the library with values:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
ref HidLibrary.NativeMethods.SECURITY_ATTRIBUTES lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
where (using test vid/pid):
lpFileName = "\\?\hid#vid_03eb&pid_2042#7&1fef463f&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
dwDesiredAccess = 0
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE (0x01 | 0x02)
lpSecurityAttributes = { bInheritHandle = true, lpSecurityDescriptor = 0, nLength = 12 }
dwCreationDisposition = OPEN_EXISTING (3)
dwFlagsAndAttributes = 0
hTemplateFile = 0
The import definition:
[DllImport("hid.dll", SetLastError = true)]
static internal extern bool HidD_GetFeature(IntPtr hidDeviceObject, ref byte[] lpReportBuffer, int reportBufferLength);
And finally the API method I'm creating that is currently failing on the HidD_GetFeature() call with error 23 (ERROR_CRC):
public bool ReadFeatureData(byte reportId, out byte[] data)
{
if (_deviceCapabilities.FeatureReportByteLength <= 0)
{
data = new byte[0];
return false;
}
// FeatureReportByteLength returns 9 (byte 0 is the report id and 8 bytes for the actual report length)
data = new byte[_deviceCapabilities.FeatureReportByteLength];
//yields a 9-byte array
var buffer = this.CreateFeatureInputBuffer();
buffer[0] = reportId;
IntPtr hidHandle = IntPtr.Zero;
bool success = false;
try
{
// Performs the CreateFile call above resulting in an IntPtr handle
hidHandle = OpenDeviceIO(_devicePath, NativeMethods.ACCESS_NONE);
success = NativeMethods.HidD_GetFeature(hidHandle, ref buffer, buffer.Length);
// at this point, success is false, and buffer has gone from 9 bytes to 1
if(success)
{
Array.Copy(buffer, 0, data, 0, Math.Min(data.Length, _deviceCapabilities.FeatureReportByteLength));
}
else
{
//Yes, i know casting to a byte isn't good here; it's dirty but helping me debug for now
data[0] = (byte)Marshal.GetLastWin32Error(); //returns 23 (verified, actual) - ERROR_CRC
}
}
catch (Exception exception)
{
throw new Exception(string.Format("Error accessing HID device '{0}'.", _devicePath), exception);
}
finally
{
if (hidHandle != IntPtr.Zero)
CloseDeviceIO(hidHandle);
}
return success;
}
I've read there are some issues with working with system devices like keyboards and mice, and that may or may not play in here, however I know that it's possible to interact with the device in the way I'm trying because I was able to do so with SimpleHidWrite. That said, I haven't ruled anything out and any ideas are welcome.
Let me know if I need to provide any more info.
I think this declaration may be the problem.
[DllImport("hid.dll", SetLastError = true)]
static internal extern bool HidD_GetFeature(IntPtr hidDeviceObject, ref byte[] lpReportBuffer, int reportBufferLength);
Try changing the lpReportBuffer ref parameter to out, or omitting it altogether.
Yes your declaration is the problem.
use:
[DllImport("hid.dll", SetLastError = true)]
protected static extern bool HidD_GetFeature( IntPtr hDevInfo,
Byte[] lpReportBuffer,
Int32 ReportBufferLength);
NO: ref or out

how to detect a right-to-left windows interface c#?

i want to place a small form above the notification icons
in left-to-right interface the icons to the right of the screen
in right-to-left interface the icons to the left of the screen
i want the code for that to work on xp and win7 please
Is this what you're looking for?
private static bool IsRightToLeft()
{
return CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft;
}
The flag you're looking for is WS_EX_LAYOUTRTL (400000 hexadecimal). You get this flag by calling GetWindowLong(FindWindow(L"HHTaskBar", NULL), GWL_EXSTYLE).
Any System.Windows.Forms.Control support such check: Control.RightToLeft.
MSDN
Stuart Dunkeld
that dosnt help , CultureInfo has nothing to do with the interface
if i could locate the location of the start button (on the taskbar) that would help
If you insist you can find the position and size of the Windows start button.
To do that, first add this inside your class:
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hwnd, ref Rectangle rectangle);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, IntPtr className, string lpszWindow);
Then use such code.. in this example I show its width but you can read its Left/Right location as well:
IntPtr hwndTaskBarWin = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "Shell_TrayWnd", null);
IntPtr hwndStartButton = FindWindowEx(hwndTaskBarWin, IntPtr.Zero, "Button", null);
if (hwndStartButton.Equals(IntPtr.Zero))
{
//Maybe Vista/Windows7?
hwndStartButton = FindWindowEx(IntPtr.Zero, IntPtr.Zero, (IntPtr)0xC017, null);
}
if (hwndStartButton.Equals(IntPtr.Zero))
{
MessageBox.Show("Sorry, can't find the Start button/orb");
}
else
{
Rectangle rect = Rectangle.Empty;
if (GetWindowRect(hwndStartButton, ref rect))
MessageBox.Show("Start button width: " + rect.Width);
}
Tested successfully under XP and Windows7, the Vista/7 trick credit goes to Waylon Flynn in his answer to this question.

Resources