I would like to enable or disable phone radio in low connectivity areas. Is it possible to do this? I am using motorola ES400 for development.
First : Import these dlls
[DllImport("ossvcs.dll", EntryPoint = "#276", CharSet = CharSet.Unicode)]
private static extern uint GetWirelessDevice(ref IntPtr pDevice, int pDevVal);
[DllImport("ossvcs.dll", EntryPoint = "#273", CharSet = CharSet.Unicode)]
private static extern uint ChangeRadioState(ref RDD pDevice, int dwState, int saveAction);
[DllImport("ossvcs.dll", EntryPoint = "#280", CharSet = CharSet.Unicode)]
private static extern uint FreeDeviceList(IntPtr pDevice);
And here's a copy of the code I use for the Motorola MC65, which should work for yours as well.
[StructLayout(LayoutKind.Auto)]
struct RADIODEVSTATE
{
public const int RADIODEVICES_ON = 1;
public const int RADIODEVICES_OFF = 0;
}
/*
typedef enum _RADIODEVTYPE
{
RADIODEVICES_MANAGED = 1,
RADIODEVICES_PHONE,
RADIODEVICES_BLUETOOTH,
} RADIODEVTYPE;
*/
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Unicode)]
struct RADIODEVTYPE
{
public const int RADIODEVICES_MANAGED = 1;
public const int RADIODEVICES_PHONE = 2;
public const int RADIODEVICES_BLUETOOTH = 3;
}
/*
typedef enum _SAVEACTION
{
RADIODEVICES_DONT_SAVE = 0,
RADIODEVICES_PRE_SAVE,
RADIODEVICES_POST_SAVE,
} SAVEACTION;
*/
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Unicode)]
struct SAVEACTION
{
public const int RADIODEVICES_DONT_SAVE = 0;
public const int RADIODEVICES_PRE_SAVE = 1;
public const int RADIODEVICES_POST_SAVE = 2;
}
/*
struct RDD
{
RDD() : pszDeviceName(NULL), pNext(NULL), pszDisplayName(NULL) {}
~RDD() { LocalFree(pszDeviceName); LocalFree(pszDisplayName); }
LPTSTR pszDeviceName; // Device name for registry setting.
LPTSTR pszDisplayName; // Name to show the world
DWORD dwState; // ON/off/[Discoverable for BT]
DWORD dwDesired; // desired state - used for setting registry etc.
RADIODEVTYPE DeviceType; // Managed, phone, BT etc.
RDD * pNext; // Next device in list
}; //radio device details
*/
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct RDD
{
[MarshalAs(UnmanagedType.LPTStr)]
public string pszDeviceName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszDisplayName;
public uint dwState;
public uint dwDesired;
public int DeviceType;
public IntPtr pNext;
}
private static bool SetDeviceState(int dwDevice, int dwState)
{
var pDevice = new IntPtr(0);
//Get the first wireless device
var result = GetWirelessDevice(ref pDevice, 0);
if (result != 0)
return false;
//While we're still looking at wireless devices
while (pDevice != IntPtr.Zero)
{
//Marshall the pointer into a C# structure
var device = (RDD)System.Runtime.InteropServices.Marshal.PtrToStructure(pDevice, typeof(RDD));
//If this device is the device we're looking for
if (device.DeviceType == dwDevice)
{
//Change the state of the radio
result = ChangeRadioState(ref device, dwState, SAVEACTION.RADIODEVICES_PRE_SAVE);
}
//Set the pointer to the next device in the linked list
pDevice = device.pNext;
}
//Free the list of devices
FreeDeviceList(pDevice);
//Turning off radios doesn't correctly report the status, so return true anyway.
return result == 0 || dwState == RADIODEVSTATE.RADIODEVICES_OFF;
}
And to turn off the phone simply call following method:
/// <summary>
/// Disables the phone radio on device
/// </summary>
public void DisablePhoneRadio()
{
SetDeviceState(RADIODEVTYPE.RADIODEVICES_PHONE, RADIODEVSTATE.RADIODEVICES_OFF);
}
So just use whatever conditional statements are needed and call DisablePhoneRadio() whenever you need to disable it, and when enabling the phone radio simply swat out the RADIODEVSTATE.RADIODEVICES_OFF with RADIODEVSTATE.RADIODEVICES_ON like so:
/// <summary>
/// Enables the phone radio on device
/// </summary>
public void EnablePhoneRadio()
{
SetDeviceState(RADIODEVTYPE.RADIODEVICES_PHONE, RADIODEVSTATE.RADIODEVICES_ON);
}
Hope this helps!
You need to P/Invoke GetDeviceList and ChangeRadioState from ossvcs.dll. The code to actually do this is a bit long for a SO post, so I'll leave it to you to get it worked out - it's not terribly hard (there's some C code here, and there's some C# code on CodeProject even, I've not used it so YMMV).
Another alternative is to use the Radios class in the SDF, which already has these wrapped.
Check this thread as well. Interesting take on threaded calls and monitoring the device connectivity state and powering on and off the cellular radio on windows mobile.
http://www.codeproject.com/Messages/4117749/Re-Csharp-Wrapper.aspx
Related
I'm making a game for a school assignment. With background music that uses WMP and one of the specifications is To turn off the background music. When entering one of the game modes. The way the game is coded is that It opens a new window for the specific. Game mode. But I'm unable to Pause/stop The music windows specific Windows are open From my basic knowledge of programming, it's probably using an
IF Statement that when. The specific window is open, the music stops. That's my best idea,
static class MediaMixer
{
static public void StopPlaying()
{
var input = new NativeMethods.INPUT { Type = 1 };
input.Data.Keyboard = new NativeMethods.KEYBDINPUT
{
Vk = 0xB2,
Scan = 0,
Flags = 0,
Time = 0,
ExtraInfo = IntPtr.Zero
};
var inputs = new NativeMethods.INPUT[] { input };
NativeMethods.SendInput(1, inputs, Marshal.SizeOf(typeof(NativeMethods.INPUT)));
}
static public void MuteVolume(IntPtr handle)
{
NativeMethods.SendMessageW(handle.Value,
NativeMethods.WM_APPCOMMAND,
handle.Value,
(IntPtr)NativeMethods.APPCOMMAND_VOLUME_MUTE);
}
}
static class NativeMethods
{
public const int WM_APPCOMMAND = 0x319;
public const int APPCOMMAND_VOLUME_MUTE = 0x80000;
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
public uint Type;
public MOUSEKEYBDHARDWAREINPUT Data;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort Vk;
public ushort Scan;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
[DllImport("user32.dll", SetLastError = true)]
static public extern uint SendInput(uint numberOfInputs,
INPUT[] inputs,
int sizeOfInputStructure);
}
I need to create a record file activity on my USB drive.
What I can do so far:
It detects the insertion and extraction (detects the extraction after the memory was removed) of a USB memory using ManagementEventWatcher:
using System.Management;
var insertQuery = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2");
var insertWatcher = new ManagementEventWatcher(insertQuery);
insertWatcher.EventArrived += DeviceInsertedEvent;
insertWatcher.Start();
Using FileSystemWatcher I can record all the action, ex. Files created, modified, deleted and renamed:
FileSystemWatcher m_Watcher = new FileSystemWatcher();
m_Watcher.Path = e.PathDevice + "\\";
string strFilter = "*.*";
m_Watcher.Filter = strFilter;
m_Watcher.NotifyFilter =
NotifyFilters.Attributes |
NotifyFilters.FileName;
m_Watcher.IncludeSubdirectories = true;
m_Watcher.Created += new FileSystemEventHandler(OnCreated);
m_Watcher.EnableRaisingEvents = true;
The problem:
As FileSystemWatcher is looking at the unit, if I try to eject the unit safely it tells me that I can not because the process of my application is using it. This variable when set to true EnableRaisingEvents = true; enable the events to listen to the changes in the memory and is the one that does not allow me to remove the memory safely, I did a test and start the application and I set it to false EnableRaisingEvents = false; and I can remove the memory safely.
Possible solution:
How can I detect the removal of the device before the operating system removes it? This way I can stop using the FileSystemWatcher on the device and remove the usb device safely.
After several days looking for an answer to the planted problem I found the solution.
This article was very helpful to solve the problem and this.
The solution changes if we are using a service or a windows form application. My answer is based on a service.
Services have a control handler which receives all messages from Windows. These might include codes to stop or pause the service, or as in our case, device events. We need to register our own service handler, so we could catch device events. This would disable all callbacks like OnStop except OnStart, which is called before we tell Windows to use our handler.
The Windows API function for this is RegisterServiceCtrlHandlerEx, which accepts a service name and a callback function to call when a message is received. We will call it in the OnStart function in our service.
The service control handler's signature is like this:
public delegate int ServiceControlHandlerEx(int control,int eventType,
IntPtr eventData, IntPtr context);
public partial class Service1 : ServiceBase{
private FileSystemWatcher fileSystemWatcher;
private IntPtr deviceNotifyHandle;
private IntPtr deviceEventHandle;
private IntPtr directoryHandle;
private Win32.ServiceControlHandlerEx myCallback;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
//
RegisterDeviceNotification();
fileSystemWatcher = new FileSystemWatcher();
fileSystemWatcher.Created += new System.IO.FileSystemEventHandler(fileSystemWatcher_Created);
fileSystemWatcher.Deleted += new System.IO.FileSystemEventHandler(fileSystemWatcher_Deleted);
fileSystemWatcher.Changed += new System.IO.FileSystemEventHandler(fileSystemWatcher_Changed);
fileSystemWatcher.Renamed += new System.IO.RenamedEventHandler(fileSystemWatcher_Renamed);
}
}
Register for Device Notifications
In the OnStart method, apart from registering for a control handler, we will register for device notifications by using the Win32 API function RegisterDeviceNotification. We give it our service's handle, a pointer to a DEV_BROADCAST_DEVICEINTERFACE struct (telling the function to register for a class of devices), and some flags, among which is the DEVICE_NOTIFY_SERVICE_HANDLE, which specifies that the caller is a service and not a window, for example. It returns a handle, which we must preserve in order to unregister when we don't need device messages anymore (for example, we could do this in the SERVICE_CONTROL_STOP event).
Using this function allows us to capture the DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE event types. We get them through the eventType parameter of our Service Control Handler. There, we can handle the SERVICE_CONTROL_DEVICEEVENT and do anything we like.
public void RegisterDeviceNotification()
{
InitArrayDevNotifyHandle();
myCallback = new Win32.ServiceControlHandlerEx(ControlHandler);
Win32.RegisterServiceCtrlHandlerEx(service.ServiceName, myCallback, IntPtr.Zero);
if (service.GetServiceHandle() == IntPtr.Zero)
{
// TODO handle error
}
Win32.DEV_BROADCAST_DEVICEINTERFACE deviceInterface = new Win32.DEV_BROADCAST_DEVICEINTERFACE();
int size = Marshal.SizeOf(deviceInterface);
deviceInterface.dbcc_size = size;
deviceInterface.dbcc_devicetype = Win32.DBT_DEVTYP_DEVICEINTERFACE;
IntPtr buffer = default(IntPtr);
buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(deviceInterface, buffer, true);
deviceEventHandle = Win32.RegisterDeviceNotification(service.GetServiceHandle(), buffer, Win32.DEVICE_NOTIFY_SERVICE_HANDLE | Win32.DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
if (deviceEventHandle == IntPtr.Zero)
{
// TODO handle error
}
}
DBT_DEVICEQUERYREMOVE - The Solution
Here is the main thing to answer the question
I needed notifies to application of a change to the hardware configuration of a device. Specifically a USB memory change before SO will remove the memory. Thanks to #ZdeněkJelínek I was able to find the event DBT_DEVICEQUERYREMOVE that permission is requested to remove a device or piece of media. This event is being held just before a device is about to be removed.
The solution is to create a handle to the device itself, use it in a DEV_BROADCAST_HANDLE structure, and register with it to our Service Control Handler. In order to accomplish all this, it takes a couple of things:
Find which drive letter the device. I was able using the ManagementEventWatcher class, which allowed me to subscribe to the device insertion event and it provides me with information about the inserted device.
All this was done with the in order to get a device handle using the CreateFileHandle function. Only after that are we able to get the DBT_DEVICEQUERYREMOVE event, disable the FileSystemWatcher, and allow the USB to be freely removed.
private int ControlHandler(int control, int eventType, IntPtr eventData, IntPtr context)
{
if (control == Win32.SERVICE_CONTROL_STOP || control == Win32.SERVICE_CONTROL_SHUTDOWN)
{
UnregisterHandles();
Win32.UnregisterDeviceNotification(deviceEventHandle);
base.Stop();
}
else if (control == Win32.SERVICE_CONTROL_DEVICEEVENT)
{
string c;
switch (eventType)
{
case Win32.DBT_DEVICEARRIVAL:
//This is an example ... I do not use the DBT_DEVICEARRIVAL event, but it can be used. Instead use the ManagementEventWatcher class to detect when a device arrives and driveLetter.
RegisterForHandle(driveLetter);
fileSystemWatcher.Path = driveLetter + ":\\";
fileSystemWatcher.EnableRaisingEvents = true;
break;
case Win32.DBT_DEVICEQUERYREMOVE:
Win32.DEV_BROADCAST_HDR hdrR;
Win32.DEV_BROADCAST_HANDLE dbhdl;
hdrR = (Win32.DEV_BROADCAST_HDR)
Marshal.PtrToStructure(eventData, typeof(Win32.DEV_BROADCAST_HDR));
if (hdrR.dbcc_devicetype == Win32.DBT_DEVTYP_HANDLE)
{
dbhdl = (Win32.DEV_BROADCAST_HANDLE)
Marshal.PtrToStructure(eventData, typeof(Win32.DEV_BROADCAST_HANDLE));
UnregisterHandles();
fileSystemWatcher.EnableRaisingEvents = false;
fileSystemWatcher = null;
}
break;
}
}
return 0;
}
private void UnregisterHandles()
{
if (directoryHandle != IntPtr.Zero)
{
Win32.CloseHandle(directoryHandle);
directoryHandle = IntPtr.Zero;
}
if (deviceNotifyHandle != IntPtr.Zero)
{
Win32.UnregisterDeviceNotification(deviceNotifyHandle);
deviceNotifyHandle = IntPtr.Zero;
}
}
private void RegisterForHandle(char c)
{
Win32.DEV_BROADCAST_HANDLE deviceHandle = new Win32.DEV_BROADCAST_HANDLE();
int size = Marshal.SizeOf(deviceHandle);
deviceHandle.dbch_size = size;
deviceHandle.dbch_devicetype = Win32.DBT_DEVTYP_HANDLE;
directoryHandle = CreateFileHandle(c + ":\\");
deviceHandle.dbch_handle = directoryHandle;
IntPtr buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(deviceHandle, buffer, true);
deviceNotifyHandle = Win32.RegisterDeviceNotification(this.ServiceHandle, buffer, Win32.DEVICE_NOTIFY_SERVICE_HANDLE);
if (deviceNotifyHandle == IntPtr.Zero)
{
// TODO handle error
}
}
public static IntPtr CreateFileHandle(string driveLetter)
{
// open the existing file for reading
IntPtr handle = Win32.CreateFile(
driveLetter,
Win32.GENERIC_READ,
Win32.FILE_SHARE_READ | Win32.FILE_SHARE_WRITE,
0,
Win32.OPEN_EXISTING,
Win32.FILE_FLAG_BACKUP_SEMANTICS | Win32.FILE_ATTRIBUTE_NORMAL,
0);
if (handle == Win32.INVALID_HANDLE_VALUE)
{
return IntPtr.Zero;
}
else
{
return handle;
}
}
public class Win32
{
public const int DEVICE_NOTIFY_SERVICE_HANDLE = 1;
public const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 4;
public const int SERVICE_CONTROL_STOP = 1;
public const int SERVICE_CONTROL_DEVICEEVENT = 11;
public const int SERVICE_CONTROL_SHUTDOWN = 5;
public const uint GENERIC_READ = 0x80000000;
public const uint OPEN_EXISTING = 3;
public const uint FILE_SHARE_READ = 1;
public const uint FILE_SHARE_WRITE = 2;
public const uint FILE_SHARE_DELETE = 4;
public const uint FILE_ATTRIBUTE_NORMAL = 128;
public const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
public const int DBT_DEVTYP_DEVICEINTERFACE = 5;
public const int DBT_DEVTYP_HANDLE = 6;
public const int DBT_DEVICEARRIVAL = 0x8000;
public const int DBT_DEVICEQUERYREMOVE = 0x8001;
public const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
public const int WM_DEVICECHANGE = 0x219;
public delegate int ServiceControlHandlerEx(int control, int eventType, IntPtr eventData, IntPtr context);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern IntPtr RegisterServiceCtrlHandlerEx(string lpServiceName, ServiceControlHandlerEx cbex, IntPtr context);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetVolumePathNamesForVolumeNameW(
[MarshalAs(UnmanagedType.LPWStr)]
string lpszVolumeName,
[MarshalAs(UnmanagedType.LPWStr)]
string lpszVolumePathNames,
uint cchBuferLength,
ref UInt32 lpcchReturnLength);
[DllImport("kernel32.dll")]
public static extern bool GetVolumeNameForVolumeMountPoint(string
lpszVolumeMountPoint, [Out] StringBuilder lpszVolumeName,
uint cchBufferLength);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr RegisterDeviceNotification(IntPtr IntPtr, IntPtr NotificationFilter, Int32 Flags);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern uint UnregisterDeviceNotification(IntPtr hHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateFile(
string FileName, // file name
uint DesiredAccess, // access mode
uint ShareMode, // share mode
uint SecurityAttributes, // Security Attributes
uint CreationDisposition, // how to create
uint FlagsAndAttributes, // file attributes
int hTemplateFile // handle to template file
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DEV_BROADCAST_DEVICEINTERFACE
{
public int dbcc_size;
public int dbcc_devicetype;
public int dbcc_reserved;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)]
public byte[] dbcc_classguid;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] dbcc_name;
}
[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_HDR
{
public int dbcc_size;
public int dbcc_devicetype;
public int dbcc_reserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_HANDLE
{
public int dbch_size;
public int dbch_devicetype;
public int dbch_reserved;
public IntPtr dbch_handle;
public IntPtr dbch_hdevnotify;
public Guid dbch_eventguid;
public long dbch_nameoffset;
public byte dbch_data;
public byte dbch_data1;
}
}
I want to play a video but before the video is played i want to know if the audio device connected to the system is working.
public static bool IsAudioDeviceAvailable()
{
ManagementObjectSearcher objSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_SoundDevice");
ManagementObjectCollection objCollection = objSearcher.Get();
if(objCollection.Count > 0)
{
return true;
}
else
{
return false;
}
}
but it doesnt work
Solution I used suggested by user3060520
Detecting Audio Input & output devices connected to system
public static bool IsAudioDeviceAvailable()
{
string[] mydevices = null;
mydevices = Win32.GetSoundDevices();
if (mydevices.Count() > 0)
{
return true;
}
else
{
return false;
}
}
}
public class Win32
{
[DllImport("winmm.dll", SetLastError = true)]
static extern uint waveOutGetNumDevs();
[DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint waveOutGetDevCaps(uint hwo, ref WAVEOUTCAPS pwoc, uint cbwoc);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WAVEOUTCAPS
{
public ushort wMid;
public ushort wPid;
public uint vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string szPname;
public uint dwFormats;
public ushort wChannels;
public ushort wReserved1;
public uint dwSupport;
}
public static string[] GetSoundDevices()
{
uint devices = waveOutGetNumDevs();
string[] result = new string[devices];
WAVEOUTCAPS caps = new WAVEOUTCAPS();
for (uint i = 0; i < devices; i++)
{
waveOutGetDevCaps(i, ref caps, (uint)Marshal.SizeOf(caps));
result[i] = caps.szPname;
}
return result;
}
Also i would like to add that it will not work for virtual audio devices.
You can also use devcon.exe to find devices by ID / Class etc and parse its status. Eg.
devcon.exe status =media //this will find all media devices and show its tatus
devcon.exe status [Device HW ID] //this will find device by id and show its status
sample output:
devcon.exe status [Device HW ID]
Device HW ID
Name: Realtek High Definition Audio
Driver is running.
Now you only have to parse the output string looking for "Driver is running" or smthing like that do detect wheter device driver is working correctly.
You can find more info about devcon here
There are already many answers about this topic, but is there a single way to get the the total amount of memory on a windows system from XP and above including Windows Server 2003?
What I have found:
Win32_LogicalMemoryConfiguration (Deprecated)
Win32_ComputerSystem (Minimum supported client: Vista)
Microsoft.VisualBasic.Devices.ComputerInfo (no XP support according to platforms)
thx
Add reference to Microsoft.VisualBasic and
var info = new Microsoft.VisualBasic.Devices.ComputerInfo();
Debug.WriteLine(info.TotalPhysicalMemory);
Debug.WriteLine(info.AvailablePhysicalMemory);
Debug.WriteLine(info.TotalVirtualMemory);
Debug.WriteLine(info.AvailableVirtualMemory);
edit : How can I get the total physical memory in C#?
or
You can make use of GlobalMemoryStatusEx : Example Here
private void DisplayMemory()
{
// Consumer of the NativeMethods class shown below
long tm = System.GC.GetTotalMemory(true);
NativeMethods oMemoryInfo = new NativeMethods();
this.lblMemoryLoadNumber.Text = oMemoryInfo.MemoryLoad.ToString();
this.lblIsMemoryTight.Text = oMemoryInfo.isMemoryTight().ToString();
if (oMemoryInfo.isMemoryTight())
this.lblIsMemoryTight.Text.Font.Bold = true;
else
this.lblIsMemoryTight.Text.Font.Bold = false;
}
Native class wrapper.
[CLSCompliant(false)]
public class NativeMethods {
private MEMORYSTATUSEX msex;
private uint _MemoryLoad;
const int MEMORY_TIGHT_CONST = 80;
public bool isMemoryTight()
{
if (_MemoryLoad > MEMORY_TIGHT_CONST )
return true;
else
return false;
}
public uint MemoryLoad
{
get { return _MemoryLoad; }
internal set { _MemoryLoad = value; }
}
public NativeMethods() {
msex = new MEMORYSTATUSEX();
if (GlobalMemoryStatusEx(msex)) {
_MemoryLoad = msex.dwMemoryLoad;
//etc.. Repeat for other structure members
}
else
// Use a more appropriate Exception Type. 'Exception' should almost never be thrown
throw new Exception("Unable to initalize the GlobalMemoryStatusEx API");
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint) Marshal.SizeOf(typeof( MEMORYSTATUSEX ));
}
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GlobalMemoryStatusEx( [In, Out] MEMORYSTATUSEX lpBuffer);
}
I need to know whether the Windows taskbar is hidden or not. I believe there is no .NET method to do this, and also I have come across a lot of "how to hide and show the taskbar" samples, but I haven't seen anything based on what I am looking for. I am not familiar with the Windows API, so I find it hard to understand traditional Windows code. Can someone please direct me to an article or type code telling whether the current state of the taskbar is hidden or not? I am coding in C#.
Thanks.
winSharp93 presents a helper class ("Find out Size (and position) of the taskbar") that seems to work. It uses Win32's SHAppBarMessage function.
Here's the code (with minor additions) from his blog:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace TaskbarTest
{
public enum TaskbarPosition
{
Unknown = -1,
Left,
Top,
Right,
Bottom,
}
public sealed class Taskbar
{
private const string ClassName = "Shell_TrayWnd";
public Rectangle Bounds {
get;
private set;
}
public TaskbarPosition Position {
get;
private set;
}
public Point Location {
get {
return this.Bounds.Location;
}
}
public Size Size {
get {
return this.Bounds.Size;
}
}
//Always returns false under Windows 7
public bool AlwaysOnTop {
get;
private set;
}
public bool AutoHide {
get;
private set;
}
public Taskbar() {
IntPtr taskbarHandle = User32.FindWindow(Taskbar.ClassName, null);
APPBARDATA data = new APPBARDATA();
data.cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA));
data.hWnd = taskbarHandle;
IntPtr result = Shell32.SHAppBarMessage(ABM.GetTaskbarPos, ref data);
if (result == IntPtr.Zero)
throw new InvalidOperationException();
this.Position = (TaskbarPosition)data.uEdge;
this.Bounds = Rectangle.FromLTRB(data.rc.left, data.rc.top, data.rc.right, data.rc.bottom);
data.cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA));
result = Shell32.SHAppBarMessage(ABM.GetState, ref data);
int state = result.ToInt32();
this.AlwaysOnTop = (state & ABS.AlwaysOnTop) == ABS.AlwaysOnTop;
this.AutoHide = (state & ABS.Autohide) == ABS.Autohide;
}
}
public enum ABM : uint
{
New = 0x00000000,
Remove = 0x00000001,
QueryPos = 0x00000002,
SetPos = 0x00000003,
GetState = 0x00000004,
GetTaskbarPos = 0x00000005,
Activate = 0x00000006,
GetAutoHideBar = 0x00000007,
SetAutoHideBar = 0x00000008,
WindowPosChanged = 0x00000009,
SetState = 0x0000000A,
}
public enum ABE : uint
{
Left = 0,
Top = 1,
Right = 2,
Bottom = 3
}
public static class ABS
{
public const int Autohide = 0x0000001;
public const int AlwaysOnTop = 0x0000002;
}
public static class Shell32
{
[DllImport("shell32.dll", SetLastError = true)]
public static extern IntPtr SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData);
}
public static class User32
{
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
[StructLayout(LayoutKind.Sequential)]
public struct APPBARDATA
{
public uint cbSize;
public IntPtr hWnd;
public uint uCallbackMessage;
public ABE uEdge;
public RECT rc;
public int lParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
}
The author claims it works on his Windows 7 machine and it appears to work on my XP Pro machine.
Here's how you might use it:
Taskbar tb = new Taskbar();
Console.WriteLine("w:{0}, h:{1} - hide:{2}", tb.Size.Width, tb.Size.Height, tb.AutoHide);
Where: tb.Size.Width and tb.Size.Height returns the width and height of the Taskbar, and tb.AutoHide returns true if the Taskbar is hidden and false if it is not.
All solutions I found didn't work for me, so I had follwing idea and it works great for me.
public static bool IsTaskbarVisible()
{
return Math.Abs(SystemParameters.PrimaryScreenHeight - SystemParameters.WorkArea.Height) > 0;
}
SystemParameters.PrimaryScreenHeight returns the real display height.
SystemParameters.WorkArea.Height returns the available workarea height.
If they are different, the taskbar is showing.
SystemParametersInfo with SPI_GETWORKAREA
Retrieves the size of the work area on the primary display monitor. The work area is the portion of the screen not obscured by the system taskbar or by application desktop toolbars. The pvParam parameter must point to a RECT structure that receives the coordinates of the work area, expressed in virtual screen coordinates.
To get the work area of a monitor other than the primary display monitor, call the GetMonitorInfo function.
You can use IsWindowVisible Win32 function.
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);
IntPtr hWnd = FindWindow("Shell_TrayWnd", null);
if (hWnd != null) IsTaskBarVisible = IsWindowVisible(hWnd);