I am currently trying to retrieve the signal strength from a wireless access point using the wlanapi.dll WlanQueryInterface call.
Here is my api declaration
[DllImport("wlanapi.dll", SetLastError = true)]
private static extern UInt32 WlanQueryInterface(IntPtr hClientHandle, ref Guid pInterfaceGuid, WLAN_INTF_OPCODE OpCode, IntPtr pReserved, out Int32 pdwDataSize, ref IntPtr ppData, IntPtr pWlanOpCodeValueType);
The problem is when I look at the wlanSignalStrength entry in the WLAN_ASSOCIATION_ATTRIBUTES structure it is set to 5400. Microsoft API documentation says that it should be a value between 0 - 100.
Here is my structure declaration:
/// <summary>
/// Structure contains association attributes for a connection.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WLAN_ASSOCIATION_ATTRIBUTES
{
/// <summary>
/// A DOT11_SSID structure that contains the SSID of the association.
/// </summary>
public DOT11_SSID dot11Ssid;
/// <summary>
/// A DOT11_BSS_TYPE value that specifies whether the network is infrastructure or ad hoc.
/// </summary>
public DOT11_BSS_TYPE dot11BssType;
/// <summary>
/// A DOT11_MAC_ADDRESS that contains the BSSID of the association.
/// </summary>
public DOT11_MAC_ADDRESS dot11Bssid;
/// <summary>
/// A DOT11_PHY_TYPE value that indicates the physical type of the association
/// </summary>
public DOT11_PHY_TYPE dot11PhyType;
/// <summary>
/// The position of the DOT11_PHY_TYPE value in the structure containing the list of PHY types.
/// </summary>
public ulong uDot11PhyIndex;
/// <summary>
/// A percentage value that represents the signal quality of the network.
/// </summary>
public Int32 wlanSignalQuality;
/// <summary>
/// Contains the receiving rate of the association.
/// </summary>
public ulong ulRxRate;
/// <summary>
/// Contains the transmission rate of the association.
/// </summary>
public ulong ulTxRate;
}
Here is my call to WlanQueryInterface:
Int32 iDataSize;
IntPtr ppData = IntPtr.Zero;
WLAN_CONNECTION_ATTRIBUTES wcaAttributes = new WLAN_CONNECTION_ATTRIBUTES();
String[] sReturn = new String[4];
if (WlanQueryInterface(pClientHandle, ref gInterfaceGUID, WLAN_INTF_OPCODE.wlan_intf_opcode_current_connection, IntPtr.Zero, out iDataSize, ref ppData, IntPtr.Zero) == ERROR_SUCCESS)
{
wcaAttributes = (WLAN_CONNECTION_ATTRIBUTES)Marshal.PtrToStructure(ppData, typeof(WLAN_CONNECTION_ATTRIBUTES));
sReturn[0] = wcaAttributes.wlanAssociationAttributes.dot11Ssid.ucSSID;
sReturn[1] = wcaAttributes.strProfileName;
sReturn[2] = String.Format("{0:X2}-{1:X2}-{2:X2}-{3:X2}-{4:X2}-{5:X2}", wcaAttributes.wlanAssociationAttributes.dot11Bssid.bOne, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bTwo, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bThree, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bFour, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bFive, wcaAttributes.wlanAssociationAttributes.dot11Bssid.bSix);
sReturn[3] = wcaAttributes.wlanAssociationAttributes.wlanSignalQuality.ToString(); //This returns 5400 when the actual strength is ~99
WlanFreeMemory(ppData);
return sReturn;
}
else
{
throw new Exception("Unable to get interface connected SSID.");
}
Does anyone see what I am doing wrong? Thanks in advance!
I finally got it fixed. I had to set the LayoutKind for the WLAN_ASSOCIATION_ATTRIBUTES to Explicit and set the charset to Unicode.
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
private struct WLAN_ASSOCIATION_ATTRIBUTES
{
/// <summary>
/// A DOT11_SSID structure that contains the SSID of the association.
/// </summary>
[FieldOffset(0)]
public DOT11_SSID dot11Ssid;
/// <summary>
/// A DOT11_BSS_TYPE value that specifies whether the network is infrastructure or ad hoc.
/// </summary>
[FieldOffset(0x24)]
public DOT11_BSS_TYPE dot11BssType;
/// <summary>
/// A DOT11_MAC_ADDRESS that contains the BSSID of the association.
/// </summary>
[FieldOffset(40)]
public DOT11_MAC_ADDRESS dot11Bssid;
/// <summary>
/// A DOT11_PHY_TYPE value that indicates the physical type of the association
/// </summary>
[FieldOffset(0x30)]
public DOT11_PHY_TYPE dot11PhyType;
/// <summary>
/// The position of the DOT11_PHY_TYPE value in the structure containing the list of PHY types.
/// </summary>
[FieldOffset(0x34)]
public ulong uDot11PhyIndex;
/// <summary>
/// A percentage value that represents the signal quality of the network.
/// </summary>
[FieldOffset(0x38)]
public Int32 wlanSignalQuality;
/// <summary>
/// Contains the receiving rate of the association.
/// </summary>
[FieldOffset(60)]
public ulong ulRxRate;
/// <summary>
/// Contains the transmission rate of the association.
/// </summary>
[FieldOffset(0x40)]
public ulong ulTxRate;
}
Related
I have attempted to use winmm.dll to no avail, I have used several other projects Ive found like this well laid out tutorial but I haven't been able to get anything except for -1 returned for the getVolume method and nonsense values for other methods.
Is there a library I can use for this? Are there any more modern examples (this is from pre-2010)? I have looked into IAudioEndpointVolume interface, but it is not available through .NET and I'm not a c++ guy.
Any help much appreciated.
IAudioEndpointVolume is avalable in Windows Core Audio APIs .Net wrapper.
You can get whether master volume is muted or not by calling int GetMute([Out] [MarshalAs(UnmanagedType.Bool)] out Boolean isMuted) method:
// http://netcoreaudio.codeplex.com/SourceControl/latest#trunk/Code/CoreAudio/Interfaces/IAudioEndpointVolume.cs
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioEndpointVolume
{
/// <summary>
/// Gets the muting state of the audio stream.
/// </summary>
/// <param name="isMuted">The muting state. True if the stream is muted, false otherwise.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int GetMute([Out] [MarshalAs(UnmanagedType.Bool)] out Boolean isMuted);
}
I have created simple realization of GetMute function (and all necessary interfaces abstractions from Windows CoreAudio API).
AudioManager class code:
public static class AudioManager
{
/// <summary>
/// Gets the mute state of the master volume.
/// While the volume can be muted the <see cref="GetMasterVolume"/> will still return the pre-muted volume value.
/// </summary>
/// <returns>false if not muted, true if volume is muted</returns>
public static bool GetMasterVolumeMute()
{
IAudioEndpointVolume masterVol = null;
try
{
masterVol = GetMasterVolumeObject();
if (masterVol == null)
return false;
bool isMuted;
masterVol.GetMute(out isMuted);
return isMuted;
}
finally
{
if (masterVol != null)
Marshal.ReleaseComObject(masterVol);
}
}
private static IAudioEndpointVolume GetMasterVolumeObject()
{
IMMDeviceEnumerator deviceEnumerator = null;
IMMDevice speakers = null;
try
{
deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers);
Guid IID_IAudioEndpointVolume = typeof(IAudioEndpointVolume).GUID;
object o;
speakers.Activate(ref IID_IAudioEndpointVolume, 0, IntPtr.Zero, out o);
IAudioEndpointVolume masterVol = (IAudioEndpointVolume)o;
return masterVol;
}
finally
{
if (speakers != null) Marshal.ReleaseComObject(speakers);
if (deviceEnumerator != null) Marshal.ReleaseComObject(deviceEnumerator);
}
}
#region Abstracted COM interfaces from Windows CoreAudio API
[ComImport]
[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
internal class MMDeviceEnumerator
{
}
internal enum EDataFlow
{
eRender,
eCapture,
eAll,
EDataFlow_enum_count
}
internal enum ERole
{
eConsole,
eMultimedia,
eCommunications,
ERole_enum_count
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMMDeviceEnumerator
{
int NotImpl1();
[PreserveSig]
int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppDevice);
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMMDevice
{
[PreserveSig]
int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
}
// http://netcoreaudio.codeplex.com/SourceControl/latest#trunk/Code/CoreAudio/Interfaces/IAudioEndpointVolume.cs
[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAudioEndpointVolume
{
[PreserveSig]
int NotImpl1();
[PreserveSig]
int NotImpl2();
/// <summary>
/// Gets a count of the channels in the audio stream.
/// </summary>
/// <param name="channelCount">The number of channels.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int GetChannelCount(
[Out] [MarshalAs(UnmanagedType.U4)] out UInt32 channelCount);
/// <summary>
/// Sets the master volume level of the audio stream, in decibels.
/// </summary>
/// <param name="level">The new master volume level in decibels.</param>
/// <param name="eventContext">A user context value that is passed to the notification callback.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int SetMasterVolumeLevel(
[In] [MarshalAs(UnmanagedType.R4)] float level,
[In] [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext);
/// <summary>
/// Sets the master volume level, expressed as a normalized, audio-tapered value.
/// </summary>
/// <param name="level">The new master volume level expressed as a normalized value between 0.0 and 1.0.</param>
/// <param name="eventContext">A user context value that is passed to the notification callback.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int SetMasterVolumeLevelScalar(
[In] [MarshalAs(UnmanagedType.R4)] float level,
[In] [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext);
/// <summary>
/// Gets the master volume level of the audio stream, in decibels.
/// </summary>
/// <param name="level">The volume level in decibels.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int GetMasterVolumeLevel(
[Out] [MarshalAs(UnmanagedType.R4)] out float level);
/// <summary>
/// Gets the master volume level, expressed as a normalized, audio-tapered value.
/// </summary>
/// <param name="level">The volume level expressed as a normalized value between 0.0 and 1.0.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int GetMasterVolumeLevelScalar(
[Out] [MarshalAs(UnmanagedType.R4)] out float level);
/// <summary>
/// Sets the volume level, in decibels, of the specified channel of the audio stream.
/// </summary>
/// <param name="channelNumber">The channel number.</param>
/// <param name="level">The new volume level in decibels.</param>
/// <param name="eventContext">A user context value that is passed to the notification callback.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int SetChannelVolumeLevel(
[In] [MarshalAs(UnmanagedType.U4)] UInt32 channelNumber,
[In] [MarshalAs(UnmanagedType.R4)] float level,
[In] [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext);
/// <summary>
/// Sets the normalized, audio-tapered volume level of the specified channel in the audio stream.
/// </summary>
/// <param name="channelNumber">The channel number.</param>
/// <param name="level">The new master volume level expressed as a normalized value between 0.0 and 1.0.</param>
/// <param name="eventContext">A user context value that is passed to the notification callback.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int SetChannelVolumeLevelScalar(
[In] [MarshalAs(UnmanagedType.U4)] UInt32 channelNumber,
[In] [MarshalAs(UnmanagedType.R4)] float level,
[In] [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext);
/// <summary>
/// Gets the volume level, in decibels, of the specified channel in the audio stream.
/// </summary>
/// <param name="channelNumber">The zero-based channel number.</param>
/// <param name="level">The volume level in decibels.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int GetChannelVolumeLevel(
[In] [MarshalAs(UnmanagedType.U4)] UInt32 channelNumber,
[Out] [MarshalAs(UnmanagedType.R4)] out float level);
/// <summary>
/// Gets the normalized, audio-tapered volume level of the specified channel of the audio stream.
/// </summary>
/// <param name="channelNumber">The zero-based channel number.</param>
/// <param name="level">The volume level expressed as a normalized value between 0.0 and 1.0.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int GetChannelVolumeLevelScalar(
[In] [MarshalAs(UnmanagedType.U4)] UInt32 channelNumber,
[Out] [MarshalAs(UnmanagedType.R4)] out float level);
/// <summary>
/// Sets the muting state of the audio stream.
/// </summary>
/// <param name="isMuted">True to mute the stream, or false to unmute the stream.</param>
/// <param name="eventContext">A user context value that is passed to the notification callback.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int SetMute(
[In] [MarshalAs(UnmanagedType.Bool)] Boolean isMuted,
[In] [MarshalAs(UnmanagedType.LPStruct)] Guid eventContext);
/// <summary>
/// Gets the muting state of the audio stream.
/// </summary>
/// <param name="isMuted">The muting state. True if the stream is muted, false otherwise.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int GetMute(
[Out] [MarshalAs(UnmanagedType.Bool)] out Boolean isMuted);
/// <summary>
/// Gets information about the current step in the volume range.
/// </summary>
/// <param name="step">The current zero-based step index.</param>
/// <param name="stepCount">The total number of steps in the volume range.</param>
/// <returns>An HRESULT code indicating whether the operation passed of failed.</returns>
[PreserveSig]
int GetVolumeStepInfo(
[Out] [MarshalAs(UnmanagedType.U4)] out UInt32 step,
[Out] [MarshalAs(UnmanagedType.U4)] out UInt32 stepCount);
}
#endregion
}
Usage:
Call GetMasterVolumeMute() method:
bool isMuted = AudioManager.GetMasterVolumeMute();
What kind of project are you creating? One idea is to create a media player (in the background) and test for the media playback volume.
_mediaPlayer = new MediaPlayer();
_systemMediaTransportControls = _mediaPlayer.SystemMediaTransportControls;
double volume = _systemMediaTransportControls.Volume;
Using C# i'm trying to retrieve the name of the song that is currently playing and display it on a listBox, so every song that plays, it's shown in the listbox.
Using System;
Using WMPLib;
public IWMPMedia currentMedia { get; set; }
private void button1_Click(object sender, EventArgs e)
{
Player = new WMPLib.WindowsMediaPlayer();
string song = Player.currentMedia.name.ToString();
listBox1.Items.Add(song);
}
But it throws me the exception.
"Object reference not set to an instance of an object" here:
string song = Player.currentMedia.name.ToString();
Does anyone knows how to solve this?
You will have to use COM/OLE to do this. I did a program that did exactly that a little while ago, unfortunately tho I cannot find my client code, but I still have the code that implements IOleClientSite/IOleServiceProvider for WMPLib.
I found that code at the following URL:
http://sirayuki.sakura.ne.jp/WmpSample/WmpRemote.zip
Its some code that was writen by Jonathan Dibble, a Microsoft employee if I remember correctly. There is a CHM in the Zip with some explanation on each of the classes.
Heres the code that I still have, in case the link goes down, but like I said I cannot find my code that uses it. It worked almost correctly but I remember that one of the bug left was that it would leave behind wmplayer.exe processes after the media player and my application were closed.
UPDATE!
found some client code and a slighlty modified version of RemotedWindowsMediaPlayer.cs
I just found some coded that I tested this with, and it works. Its from a Winform project, and you need to reference WMPLib for this to work.
In my form I added a button and this code:
/// <summary>
/// Default Constructor
/// </summary>
RemotedWindowsMediaPlayer rm;
public FrmMain()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//Call me old fashioned - I like to do this stuff manually. You can do a drag
//drop if you like, it won't change the results.
rm = new RemotedWindowsMediaPlayer();
rm.Dock = System.Windows.Forms.DockStyle.Top;
panel1.Controls.Add(rm);
return;
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(((WMPLib.IWMPPlayer4)rm.GetOcx()).currentMedia.sourceURL);
}
RemotedWindowsMediaPLayer.cs:
namespace RemoteWMP
{
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using WMPLib;
/// <summary>
/// This is the actual Windows Media Control.
/// </summary>
[System.Windows.Forms.AxHost.ClsidAttribute("{6bf52a52-394a-11d3-b153-00c04f79faa6}")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class RemotedWindowsMediaPlayer : System.Windows.Forms.AxHost,
IOleServiceProvider,
IOleClientSite
{
/// <summary>
/// Used to attach the appropriate interface to Windows Media Player.
/// In here, we call SetClientSite on the WMP Control, passing it
/// the dotNet container (this instance.)
/// </summary>
protected override void AttachInterfaces()
{
try
{
//Get the IOleObject for Windows Media Player.
IOleObject oleObject = this.GetOcx() as IOleObject;
if (oleObject != null)
{
//Set the Client Site for the WMP control.
oleObject.SetClientSite(this as IOleClientSite);
// Try and get the OCX as a WMP player
if (this.GetOcx() as IWMPPlayer4 == null)
{
throw new Exception(string.Format("OCX is not an IWMPPlayer4! GetType returns '{0}'",
this.GetOcx().GetType()));
}
}
else
{
throw new Exception("Failed to get WMP OCX as an IOleObject?!");
}
return;
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
#region IOleServiceProvider Memebers - Working
/// <summary>
/// During SetClientSite, WMP calls this function to get the pointer to <see cref="RemoteHostInfo"/>.
/// </summary>
/// <param name="guidService">See MSDN for more information - we do not use this parameter.</param>
/// <param name="riid">The Guid of the desired service to be returned. For this application it will always match
/// the Guid of <see cref="IWMPRemoteMediaServices"/>.</param>
/// <returns></returns>
IntPtr IOleServiceProvider.QueryService(ref Guid guidService, ref Guid riid)
{
//If we get to here, it means Media Player is requesting our IWMPRemoteMediaServices interface
if (riid == new Guid("cbb92747-741f-44fe-ab5b-f1a48f3b2a59"))
{
IWMPRemoteMediaServices iwmp = new RemoteHostInfo();
return Marshal.GetComInterfaceForObject(iwmp, typeof(IWMPRemoteMediaServices));
}
throw new System.Runtime.InteropServices.COMException("No Interface", (int) HResults.E_NOINTERFACE);
}
#endregion
#region IOleClientSite Members
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException">E_NOTIMPL</exception>
void IOleClientSite.SaveObject()
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
object IOleClientSite.GetMoniker(uint dwAssign, uint dwWhichMoniker)
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
object IOleClientSite.GetContainer()
{
return (int)HResults.E_NOINTERFACE;
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
void IOleClientSite.ShowObject()
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
void IOleClientSite.OnShowWindow(bool fShow)
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
/// <summary>
/// Not in use. See MSDN for details.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.COMException"></exception>
void IOleClientSite.RequestNewObjectLayout()
{
throw new System.Runtime.InteropServices.COMException("Not Implemented", (int) HResults.E_NOTIMPL);
}
#endregion
/// <summary>
/// Default Constructor.
/// </summary>
public RemotedWindowsMediaPlayer() :
base("6bf52a52-394a-11d3-b153-00c04f79faa6")
{
}
}
}
RemoteHostInfo.cs
using System;
namespace RemoteWMP
{
using System.Runtime.InteropServices;
/// <summary>
/// This class contains the information to return to Media Player about our remote service.
/// </summary>
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class RemoteHostInfo :
IWMPRemoteMediaServices
{
#region IWMPRemoteMediaServices Members
/// <summary>
/// Returns "Remote" to tell media player that we want to remote the WMP application.
/// </summary>
/// <returns></returns>
public string GetServiceType()
{
return "Remote";
}
/// <summary>
/// The Application Name to show in Windows Media Player switch to menu
/// </summary>
/// <returns></returns>
public string GetApplicationName()
{
return System.Diagnostics.Process.GetCurrentProcess().ProcessName;
}
/// <summary>
/// Not in use, see MSDN for more info.
/// </summary>
/// <param name="name"></param>
/// <param name="dispatch"></param>
/// <returns></returns>
public HResults GetScriptableObject(out string name, out object dispatch)
{
name = null;
dispatch = null;
//return (int) HResults.S_OK;//NotImplemented
return HResults.E_NOTIMPL;
}
/// <summary>
/// For skins, not in use, see MSDN for more info.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public HResults GetCustomUIMode(out string file)
{
file = null;
return HResults.E_NOTIMPL;//NotImplemented
}
#endregion
}
}
COM Interfaces.cs
using System;
namespace RemoteWMP
{
using System.Runtime.InteropServices;
#region Useful COM Enums
/// <summary>
/// Represents a collection of frequently used HRESULT values.
/// You may add more HRESULT VALUES, I've only included the ones used
/// in this project.
/// </summary>
public enum HResults
{
/// <summary>
/// HRESULT S_OK
/// </summary>
S_OK = unchecked((int)0x00000000),
/// <summary>
/// HRESULT S_FALSE
/// </summary>
S_FALSE = unchecked((int)0x00000001),
/// <summary>
/// HRESULT E_NOINTERFACE
/// </summary>
E_NOINTERFACE = unchecked((int)0x80004002),
/// <summary>
/// HRESULT E_NOTIMPL
/// </summary>
E_NOTIMPL = unchecked((int)0x80004001),
/// <summary>
/// USED CLICKED CANCEL AT SAVE PROMPT
/// </summary>
OLE_E_PROMPTSAVECANCELLED = unchecked((int)0x8004000C),
}
/// <summary>
/// Enumeration for <see cref="IOleObject.GetMiscStatus"/>
/// </summary>
public enum DVASPECT
{
/// <summary>
/// See MSDN for more information.
/// </summary>
Content = 1,
/// <summary>
/// See MSDN for more information.
/// </summary>
Thumbnail = 2,
/// <summary>
/// See MSDN for more information.
/// </summary>
Icon = 3,
/// <summary>
/// See MSDN for more information.
/// </summary>
DocPrint = 4
}
/// <summary>
/// Emumeration for <see cref="IOleObject.Close"/>
/// </summary>
public enum TAGOLECLOSE :uint{
OLECLOSE_SAVEIFDIRTY = unchecked((int)0),
OLECLOSE_NOSAVE = unchecked((int)1),
OLECLOSE_PROMPTSAVE = unchecked((int)2)
}
#endregion
#region IWMPRemoteMediaServices
/// <summary>
/// Interface used by Media Player to determine WMP Remoting status.
/// </summary>
[ComImport,
ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("CBB92747-741F-44fe-AB5B-F1A48F3B2A59")]
public interface IWMPRemoteMediaServices
{
/// <summary>
/// Service type.
/// </summary>
/// <returns><code>Remote</code> if the control is to be remoted (attached to WMP.)
/// <code>Local</code>if this is an independent WMP instance not connected to WMP application. If you want local, you shouldn't bother
/// using this control!
/// </returns>
[return: MarshalAs(UnmanagedType.BStr)]
string GetServiceType();
/// <summary>
/// Value to display in Windows Media Player Switch To Application menu option (under View.)
/// </summary>
/// <returns></returns>
[return: MarshalAs(UnmanagedType.BStr)]
string GetApplicationName();
/// <summary>
/// Not in use, see MSDN for details.
/// </summary>
/// <param name="name"></param>
/// <param name="dispatch"></param>
/// <returns></returns>
[PreserveSig]
[return: MarshalAs(UnmanagedType.U4)]
HResults GetScriptableObject([MarshalAs(UnmanagedType.BStr)] out string name,
[MarshalAs(UnmanagedType.IDispatch)] out object dispatch);
/// <summary>
/// Not in use, see MSDN for details.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[PreserveSig]
[return: MarshalAs(UnmanagedType.U4)]
HResults GetCustomUIMode([MarshalAs(UnmanagedType.BStr)] out string file);
}
#endregion
#region IOleServiceProvider
/// <summary>
/// Interface used by Windows Media Player to return an instance of IWMPRemoteMediaServices.
/// </summary>
[ComImport,
GuidAttribute("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(true)]
public interface IOleServiceProvider
{
/// <summary>
/// Similar to QueryInterface, riid will contain the Guid of an object to return.
/// In our project we will look for <see cref="IWMPRemoteMediaServices"/> Guid and return the object
/// that implements that interface.
/// </summary>
/// <param name="guidService"></param>
/// <param name="riid">The Guid of the desired Service to provide.</param>
/// <returns>A pointer to the interface requested by the Guid.</returns>
IntPtr QueryService(ref Guid guidService, ref Guid riid);
}
/// <summary>
/// This is an example of an INCORRECT entry - do not use, unless you want your app to break.
/// </summary>
[ComImport,
GuidAttribute("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(true)]
public interface BadIOleServiceProvider
{
/// <summary>
/// This is incorrect because it causes our return interface to be boxed
/// as an object and a COM callee may not get the correct pointer.
/// </summary>
/// <param name="guidService"></param>
/// <param name="riid"></param>
/// <returns></returns>
/// <example>
/// For an example of a correct definition, look at <see cref="IOleServiceProvider"/>.
/// </example>
[return: MarshalAs(UnmanagedType.Interface)]
object QueryService(ref Guid guidService, ref Guid riid);
}
#endregion
#region IOleClientSite
/// <summary>
/// Need to implement this interface so we can pass it to <see cref="IOleObject.SetClientSite"/>.
/// All functions return E_NOTIMPL. We don't need to actually implement anything to get
/// the remoting to work.
/// </summary>
[ComImport,
ComVisible(true),
Guid("00000118-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown) ]
public interface IOleClientSite
{
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
void SaveObject();
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
[return: MarshalAs(UnmanagedType.Interface)]
object GetMoniker(uint dwAssign, uint dwWhichMoniker);
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
[return: MarshalAs(UnmanagedType.Interface)]
object GetContainer();
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
void ShowObject();
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
void OnShowWindow(bool fShow);
/// <summary>
/// See MSDN for more information. Throws <see cref="COMException"/> with id of E_NOTIMPL.
/// </summary>
/// <exception cref="COMException">E_NOTIMPL</exception>
void RequestNewObjectLayout();
}
#endregion
#region IOleObject
/// <summary>
/// This interface is implemented by WMP ActiveX/COM control.
/// The only function we need is <see cref="SetClientSite"/>.
/// </summary>
[ComImport, ComVisible(true),
Guid("00000112-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleObject
{
/// <summary>
/// Used to pass our custom <see cref="IOleClientSite"/> object to WMP. The object we pass must also
/// implement <see cref="IOleServiceProvider"/> to work right.
/// </summary>
/// <param name="pClientSite">The <see cref="IOleClientSite"/> to pass.</param>
void SetClientSite(IOleClientSite pClientSite);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
IOleClientSite GetClientSite();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void SetHostNames(
[MarshalAs(UnmanagedType.LPWStr)]string szContainerApp,
[MarshalAs(UnmanagedType.LPWStr)]string szContainerObj);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void Close(uint dwSaveOption);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void SetMoniker(uint dwWhichMoniker, object pmk);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
object GetMoniker(uint dwAssign, uint dwWhichMoniker);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void InitFromData(object pDataObject, bool fCreation, uint dwReserved);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
object GetClipboardData(uint dwReserved);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void DoVerb(uint iVerb, uint lpmsg, [MarshalAs(UnmanagedType.Interface)]object pActiveSite,
uint lindex, uint hwndParent, uint lprcPosRect);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
object EnumVerbs();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void Update();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[PreserveSig]
[return: MarshalAs(UnmanagedType.U4)]
HResults IsUpToDate();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
Guid GetUserClassID();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.LPWStr)]
string GetUserType(uint dwFormOfType);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void SetExtent(uint dwDrawAspect, [MarshalAs(UnmanagedType.Interface)] object psizel);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
object GetExtent(uint dwDrawAspect);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
uint Advise([MarshalAs(UnmanagedType.Interface)]object pAdvSink);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void Unadvise(uint dwConnection);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
[return: MarshalAs(UnmanagedType.Interface)]
object EnumAdvise();
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
uint GetMiscStatus([MarshalAs(UnmanagedType.U4)] DVASPECT dwAspect);
/// <summary>
/// Implemented by Windows Media Player ActiveX control.
/// See MSDN for more information.
/// </summary>
void SetColorScheme([MarshalAs(UnmanagedType.Interface)] object pLogpal);
}
#endregion
}
I'm working on a custom outlook addin where I need to subclass the appointment window. This works basically pretty well following the principles mentioned in the following ariticle:
http://www.codeproject.com/Articles/27262/Additional-custom-panel-in-Microsoft-Outlook
I'm struggeling by getting the handle to the social connector within the new appointment window.
I've tryied out a few approaches (FindWindow, FindWindowEx, EnumChildWindow) but none of them gave me the correct handle.
Here you can find a small addin project to have a quick look at it.
Download
Or have a quick look at this abstract
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
namespace FindSocialConnector._2013
{
public partial class ThisAddIn
{
/// <summary>
/// Delegate for the EnumChildWindows method
/// </summary>
/// <param name="hWnd">Window handle</param>
/// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
/// <returns>True to continue enumerating, false to bail.</returns>
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
/// <summary>
/// Hält den Klassennamen des NewAppointment Windows.
/// </summary>
public const string NewAppointmentWindowClass = "rctrl_renwnd32";
private Inspectors _inspectors;
/// <summary>
/// The EnumChildWindows function enumerates the child windows that belong to the specified parent window by passing the handle to each child window,
/// in turn, to an application-defined callback function. EnumChildWindows continues until the last child window is enumerated or the callback function returns FALSE.
/// </summary>
/// <param name="parentHandle">
/// Handle to the parent window whose child windows are to be enumerated.
/// If this parameter is NULL, this function is equivalent to EnumWindows.
/// Windows 95/98/Me: parentHandle cannot be NULL.
/// </param>
/// <param name="callbackFunction">
/// Pointer to an application-defined callback function. For more information, see EnumChildProc.
/// </param>
/// <param name="param">
/// Specifies an application-defined value to be passed to the callback function.
/// </param>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int EnumChildWindows(IntPtr parentHandle, Delegate callbackFunction, IntPtr param);
/// <summary>
/// Retrieves a handle to the top-level window whose class name and window name match the specified strings. This function does not search child windows.
/// This function does not perform a case-sensitive search. To search child windows, beginning with a specified child window, use the FindWindowEx function.
/// <returns>
/// <param name="className">
/// The class name or a class atom created by a previous call to the RegisterClass or RegisterClassEx function.
/// The atom must be in the low-order word of lpClassName; the high-order word must be zero.
/// If lpClassName points to a string, it specifies the window class name.
/// The class name can be any name registered with RegisterClass or RegisterClassEx, or any of the predefined control-class names.
/// If lpClassName is NULL, it finds any window whose title matches the lpWindowName parameter.
/// </param>
/// <param name="windowName">The window name (the window's title). If this parameter is NULL, all window names match.</param>
/// If the function succeeds, the return value is a handle to the window that has the specified class name and window name.
/// If the function fails, the return value is NULL. To get extended error information, call GetLastError.
/// </returns>
/// </summary>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string className, string windowName);
/// <summary>
/// The FindWindowEx function retrieves a handle to a window whose class name and window name match the specified strings.
/// The function searches child windows, beginning with the one following the specified child window.
/// This function does not perform a case-sensitive search.
/// </summary>
/// <param name="parentHandle">
/// Handle to the parent window whose child windows are to be searched.
/// If hwndParent is NULL, the function uses the desktop window as the parent window.
/// The function searches among windows that are child windows of the desktop.
/// </param>
/// <param name="childAfter">
/// Handle to a child window. The search begins with the next child window in the Z order.
/// The child window must be a direct child window of hwndParent, not just a descendant window.
/// If hwndChildAfter is NULL, the search begins with the first child window of hwndParent.
/// </param>
/// <param name="className">
/// Pointer to a null-terminated string that specifies the class name or a class atom created by a previous call to the RegisterClass or RegisterClassEx function.
/// The atom must be placed in the low-order word of lpszClass; the high-order word must be zero.
/// </param>
/// <param name="windowTitle">
/// Pointer to a null-terminated string that specifies the window name (the window's title).
/// If this parameter is NULL, all window names match.
/// </param>
/// <returns>
/// If the function succeeds, the return value is a handle to the window that has the specified class and window names.
/// If the function fails, the return value is NULL. To get extended error information, call GetLastError.
/// </returns>
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
/// <summary>
/// Liefert das Handle des NewAppointmentWindow's.
/// </summary>
private static IntPtr FindNewAppointmentWindowByCaption(string caption)
{
IntPtr newAppointmentWindowHandle = FindWindow(NewAppointmentWindowClass, caption);
if (newAppointmentWindowHandle == IntPtr.Zero)
{
throw new ArgumentException("NewAppointment Window wasn't found.");
}
return newAppointmentWindowHandle;
}
private void ThisAddIn_Startup(object sender, EventArgs e)
{
_inspectors = Application.Inspectors;
_inspectors.NewInspector += Inspectors_NewInspector;
}
private void Inspectors_NewInspector(Inspector inspector)
{
AppointmentItem appointmentItem = inspector.CurrentItem as AppointmentItem;
if (appointmentItem != null)
{
IntPtr appointmentWindow = FindNewAppointmentWindowByCaption(inspector.Caption);
// Get all child windows based on the new appointment window
// Unfortunately the social connector handle isn't returned
GetChildWindows(appointmentWindow);
// Directly get the social connector based on the class name
// Unfortunately this returns 0
IntPtr socialConnectorWindow = FindWindowEx(appointmentWindow, IntPtr.Zero, "MerenguePane", null);
}
}
/// <summary>
/// Callback method to be used when enumerating windows.
/// </summary>
/// <param name="handle">Handle of the next window</param>
/// <param name="pointer">Pointer to a GCHandle that holds a reference to the list to fill</param>
/// <returns>True to continue the enumeration, false to bail</returns>
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
Debug.WriteLine("Current Window Handle: {0}, Hex: {1}", handle, handle.ToString("X"));
list.Add(handle);
// You can modify this to check to see if you want to cancel the operation, then return a null here
return true;
}
/// <summary>
/// Returns a list of child windows
/// </summary>
/// <param name="parent">Parent of the windows to return</param>
/// <returns>List of child windows</returns>
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
EnumWindowProc childProc = EnumWindow;
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
{
listHandle.Free();
}
}
return result;
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
Startup += ThisAddIn_Startup;
}
}
}
Btw. the social connector is only displayed if you directly create a meeting request e.g. go to the calendar, right click --> New meeting request
Any thoughts on this?
Regards,
Lukas
protected override void OnStart(string[] args)
{
base.OnStart(args);
CaptureScreen();
}
protected override void OnStop()
{
base.OnStop();
}
private void CaptureScreen()
{
Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(printscreen as Image);
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);
printscreen.Save(#"L:\" + Counter++ + ".jpg", ImageFormat.Jpeg);
}
I checked interact with desktop
tried the the localService account & user
This is part of the session 0 isolation feature that was added to Vista. Services now run their own session with their own workstation and desktop. Much like the session that the login prompt and screen saver run in. You are taking a screenshot of that session's desktop, there's nothing in it. Getting access to the user desktop is no longer possible. It is a security feature, it prevents shatter attacks. Admittedly, I don't understand why the 'interact with desktop' checkbox wasn't removed.
You'll need to change your program to run as a "windows application", not a service. Put a shortcut in the Startup folder or use the Run registry key. Which is okay, there's nothing much worth snapping when no user is logged in.
You need to set your service to the users windows station. This is not my code and I can't remember where I got it from.
Add these two classes
then you can create a Desktop object
Desktop userDesk = new Desktop();
Then when you need your service to interact with the user session you would write
userDesk.BeginInteraction();
and finally to return to your service's session you call
userDesk.EndInteraction();
internal class Desktop
{
private IntPtr m_hCurWinsta = IntPtr.Zero;
private IntPtr m_hCurDesktop = IntPtr.Zero;
private IntPtr m_hWinsta = IntPtr.Zero;
private IntPtr m_hDesk = IntPtr.Zero;
/// <summary>
/// associate the current thread to the default desktop
/// </summary>
/// <returns></returns>
internal bool BeginInteraction()
{
EndInteraction();
m_hCurWinsta = User32DLL.GetProcessWindowStation();
if (m_hCurWinsta == IntPtr.Zero)
return false;
m_hCurDesktop = User32DLL.GetDesktopWindow();
if (m_hCurDesktop == IntPtr.Zero)
return false;
m_hWinsta = User32DLL.OpenWindowStation("winsta0", false,
WindowStationAccessRight.WINSTA_ACCESSCLIPBOARD |
WindowStationAccessRight.WINSTA_ACCESSGLOBALATOMS |
WindowStationAccessRight.WINSTA_CREATEDESKTOP |
WindowStationAccessRight.WINSTA_ENUMDESKTOPS |
WindowStationAccessRight.WINSTA_ENUMERATE |
WindowStationAccessRight.WINSTA_EXITWINDOWS |
WindowStationAccessRight.WINSTA_READATTRIBUTES |
WindowStationAccessRight.WINSTA_READSCREEN |
WindowStationAccessRight.WINSTA_WRITEATTRIBUTES
);
if (m_hWinsta == IntPtr.Zero)
return false;
User32DLL.SetProcessWindowStation(m_hWinsta);
m_hDesk = User32DLL.OpenDesktop("default", OpenDesktopFlag.DF_NONE, false,
DesktopAccessRight.DESKTOP_CREATEMENU |
DesktopAccessRight.DESKTOP_CREATEWINDOW |
DesktopAccessRight.DESKTOP_ENUMERATE |
DesktopAccessRight.DESKTOP_HOOKCONTROL |
DesktopAccessRight.DESKTOP_JOURNALPLAYBACK |
DesktopAccessRight.DESKTOP_JOURNALRECORD |
DesktopAccessRight.DESKTOP_READOBJECTS |
DesktopAccessRight.DESKTOP_SWITCHDESKTOP |
DesktopAccessRight.DESKTOP_WRITEOBJECTS
);
if (m_hDesk == IntPtr.Zero)
return false;
User32DLL.SetThreadDesktop(m_hDesk);
return true;
}
/// <summary>
/// restore
/// </summary>
internal void EndInteraction()
{
if (m_hCurWinsta != IntPtr.Zero)
User32DLL.SetProcessWindowStation(m_hCurWinsta);
if (m_hCurDesktop != IntPtr.Zero)
User32DLL.SetThreadDesktop(m_hCurDesktop);
if (m_hWinsta != IntPtr.Zero)
User32DLL.CloseWindowStation(m_hWinsta);
if (m_hDesk != IntPtr.Zero)
User32DLL.CloseDesktop(m_hDesk);
}
}
public static class User32DLL
{
/// <summary>
/// The GetDesktopWindow function returns a handle to the desktop window.
/// The desktop window covers the entire screen.
/// The desktop window is the area on top of which other windows are painted.
/// </summary>
/// <returns>The return value is a handle to the desktop window. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetDesktopWindow();
/// <summary>
/// Retrieves a handle to the current window station for the calling process.
/// </summary>
/// <returns>If the function succeeds,
/// the return value is a handle to the window station.
/// If the function fails, the return value is NULL.</returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetProcessWindowStation();
/// <summary>
/// Retrieves a handle to the desktop assigned to the specified thread.
/// </summary>
/// <param name="dwThread">[in] Handle to the thread
/// for which to return the desktop handle.</param>
/// <returns>If the function succeeds, the return value is a handle to the
/// desktop associated with the specified thread.
/// If the function fails, the return value is NULL.</returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetThreadDesktop(uint dwThread);
/// <summary>
/// Opens the specified window station.
/// </summary>
/// <param name="lpszWinSta">Pointer to a null-terminated
/// string specifying the name of the window station
/// to be opened. Window station names are case-insensitive.
/// This window station must belong to the current session.
/// </param>
/// <param name="fInherit">[in] If this value
/// is TRUE, processes created by this process
/// will inherit the handle. Otherwise,
/// the processes do not inherit this handle.
/// </param>
/// <param name="dwDesiredAccess">[in] Access to the window station</param>
/// <returns>If the function succeeds, the return value
/// is the handle to the specified window station.
/// If the function fails, the return value is NULL.</returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenWindowStation(string lpszWinSta
, bool fInherit
, WindowStationAccessRight dwDesiredAccess
);
/// <summary>
/// Assigns the specified window station to the calling process.
/// This enables the process to access objects in the window
/// station such as desktops, the clipboard, and global atoms.
/// All subsequent operations on the window station
/// use the access rights granted to hWinSta.
/// </summary>
/// <param name="hWinSta">[in] Handle to the window
/// station to be assigned to the calling process</param>
/// <returns>If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr SetProcessWindowStation(IntPtr hWinSta);
/// <summary>
/// Closes an open window station handle.
/// </summary>
/// <param name="hWinSta">[in] Handle
/// to the window station to be closed.</param>
/// <returns>If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CloseWindowStation(IntPtr hWinSta);
/// <summary>
/// Opens the specified desktop object.
/// </summary>
/// <param name="lpszDesktop">[in] Pointer to null-terminated string
/// specifying the name of the desktop to be opened.
/// Desktop names are case-insensitive.
/// This desktop must belong to the current window station.</param>
/// <param name="dwFlags">[in] This parameter can
/// be zero or DF_ALLOWOTHERACCOUNTHOOK=0x0001</param>
/// <param name="fInherit">[in] If this value is TRUE, processes created by
/// this process will inherit the handle.
/// Otherwise, the processes do not inherit this handle. </param>
/// <param name="dwDesiredAccess">[in] Access
/// to the desktop. For a list of access rights</param>
/// <returns>If the function succeeds, the return value is a handle to the opened desktop.
/// When you are finished using the handle, call the CloseDesktop function to close it.
/// If the function fails, the return value is NULL.
/// </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenDesktop(string lpszDesktop
, OpenDesktopFlag dwFlags
, bool fInherit
, DesktopAccessRight dwDesiredAccess
);
/// <summary>
/// Closes an open handle to a desktop object.
/// </summary>
/// <param name="hDesktop">[in] Handle to the desktop to be closed.</param>
/// <returns>If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CloseDesktop(IntPtr hDesktop);
/// <summary>
/// Assigns the specified desktop to the calling thread.
/// All subsequent operations on the desktop use the access rights granted to the desktop.
/// </summary>
/// <param name="hDesktop">[in] Handle to the desktop
/// to be assigned to the calling thread.</param>
/// <returns>If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. </returns>
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool SetThreadDesktop(IntPtr hDesktop);
}
/// <summary>
/// REF MSDN:Window Station Security and Access Rights
/// ms-help://MS.MSDN.vAug06.en/dllproc/base/window_station_security_and_access_rights.htm
/// </summary>
[FlagsAttribute]
public enum WindowStationAccessRight : uint
{
/// <summary>All possible access rights for the window station.</summary>
WINSTA_ALL_ACCESS = 0x37F,
/// <summary>Required to use the clipboard.</summary>
WINSTA_ACCESSCLIPBOARD = 0x0004,
/// <summary>Required to manipulate global atoms.</summary>
WINSTA_ACCESSGLOBALATOMS = 0x0020,
/// <summary>Required to create new desktop
/// objects on the window station.</summary>
WINSTA_CREATEDESKTOP = 0x0008,
/// <summary>Required to enumerate existing desktop objects.</summary>
WINSTA_ENUMDESKTOPS = 0x0001,
/// <summary>Required for the window station to be enumerated.</summary>
WINSTA_ENUMERATE = 0x0100,
/// <summary>Required to successfully call the ExitWindows or ExitWindowsEx function.
/// Window stations can be shared by users and this access type can prevent other users
/// of a window station from logging off the window station owner.</summary>
WINSTA_EXITWINDOWS = 0x0040,
/// <summary>Required to read the attributes of a window station object.
/// This attribute includes color settings
/// and other global window station properties.</summary>
WINSTA_READATTRIBUTES = 0x0002,
/// <summary>Required to access screen contents.</summary>
WINSTA_READSCREEN = 0x0200,
/// <summary>Required to modify the attributes of
/// a window station object.
/// The attributes include color settings
/// and other global window station properties.</summary>
WINSTA_WRITEATTRIBUTES = 0x0010,
}
/// <summary>
/// OpenDesktop 2nd param
/// </summary>
public enum OpenDesktopFlag : uint
{
/// <summary>
/// Default value
/// </summary>
DF_NONE = 0x0000,
/// <summary>
/// Allows processes running in other accounts on the desktop
/// to set hooks in this process.
/// </summary>
DF_ALLOWOTHERACCOUNTHOOK = 0x0001,
}
/// <summary>
/// REF MSDN:Desktop Security and Access Rights
/// ms-help://MS.MSDN.vAug06.en/dllproc/base/desktop_security_and_access_rights.htm
/// </summary>
[FlagsAttribute]
public enum DesktopAccessRight : uint
{
/// <summary>Required to create a menu on the desktop. </summary>
DESKTOP_CREATEMENU = 0x0004,
/// <summary>Required to create a window on the desktop. </summary>
DESKTOP_CREATEWINDOW = 0x0002,
/// <summary>Required for the desktop to be enumerated. </summary>
DESKTOP_ENUMERATE = 0x0040,
/// <summary>Required to establish any of the window hooks. </summary>
DESKTOP_HOOKCONTROL = 0x0008,
/// <summary>Required to perform journal playback on a desktop. </summary>
DESKTOP_JOURNALPLAYBACK = 0x0020,
/// <summary>Required to perform journal recording on a desktop. </summary>
DESKTOP_JOURNALRECORD = 0x0010,
/// <summary>Required to read objects on the desktop. </summary>
DESKTOP_READOBJECTS = 0x0001,
/// <summary>Required to activate the desktop
/// using the SwitchDesktop function. </summary>
DESKTOP_SWITCHDESKTOP = 0x0100,
/// <summary>Required to write objects on the desktop. </summary>
DESKTOP_WRITEOBJECTS = 0x0080,
}
The service is "headless", no UI and without being a 100% sure (The documentation for CopyFromScreen is rather vague) I'd expect that to fail when running headless. How would the service know which screen to copy in the case where multiple users are logged on at the same time?
see this questions as well
In the case of XP/2003 the Interact with Desktop should help.
In the case of Windows 7/Windows 2008 an Interact with Desktop works differently.
The best solution for you would be to analyze logon sessions from the service and, for new session, start the "desktop" process in user session and communicate with that process to get screens.
It may just be as simple as turning the accelerator off in your browser. That worked for me. In Chrome it's under the System menu.
I've got this class which seems to work quite well on non-64bit.
using System;
using System.Runtime.InteropServices;
namespace DeleteToRecycleBin
{
/// <summary>
/// Send files directly to the recycle bin.
/// </summary>
public class RecybleBin
{
/// <summary>
/// Possible flags for the SHFileOperation method.
/// </summary>
[Flags]
public enum FileOperationFlags: ushort
{
/// <summary>
/// Do not show a dialog during the process
/// </summary>
FOF_SILENT = 0x0004,
/// <summary>
/// Do not ask the user to confirm selection
/// </summary>
FOF_NOCONFIRMATION = 0x0010,
/// <summary>
/// Delete the file to the recycle bin. (Required flag to send a file to the bin
/// </summary>
FOF_ALLOWUNDO = 0x0040,
/// <summary>
/// Do not show the names of the files or folders that are being recycled.
/// </summary>
FOF_SIMPLEPROGRESS = 0x0100,
/// <summary>
/// Surpress errors, if any occur during the process.
/// </summary>
FOF_NOERRORUI = 0x0400,
/// <summary>
/// Warn if files are too big to fit in the recycle bin and will need
/// to be deleted completely.
/// </summary>
FOF_WANTNUKEWARNING = 0x4000,
}
/// <summary>
/// File Operation Function Type for SHFileOperation
/// </summary>
public enum FileOperationType: uint
{
/// <summary>
/// Move the objects
/// </summary>
FO_MOVE = 0x0001,
/// <summary>
/// Copy the objects
/// </summary>
FO_COPY = 0x0002,
/// <summary>
/// Delete (or recycle) the objects
/// </summary>
FO_DELETE = 0x0003,
/// <summary>
/// Rename the object(s)
/// </summary>
FO_RENAME = 0x0004,
}
/// <summary>
/// SHFILEOPSTRUCT for SHFileOperation from COM
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
private struct SHFILEOPSTRUCT
{
public IntPtr hwnd;
[MarshalAs(UnmanagedType.U4)]
public FileOperationType wFunc;
public string pFrom;
public string pTo;
public FileOperationFlags fFlags;
[MarshalAs(UnmanagedType.Bool)]
public readonly bool fAnyOperationsAborted;
public readonly IntPtr hNameMappings;
public readonly string lpszProgressTitle;
}
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);
/// <summary>
/// Send file to recycle bin
/// </summary>
/// <param name="path">Location of directory or file to recycle</param>
/// <param name="flags">FileOperationFlags to add in addition to FOF_ALLOWUNDO</param>
public static bool Send(string path, FileOperationFlags flags)
{
try
{
SHFILEOPSTRUCT fs = new SHFILEOPSTRUCT
{
wFunc = FileOperationType.FO_DELETE,
pFrom = path + '\0' + '\0',
fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags
};
// important to double-terminate the string.
SHFileOperation(ref fs);
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Send file to recycle bin. Display dialog, display warning if files are too big to fit (FOF_WANTNUKEWARNING)
/// </summary>
/// <param name="path">Location of directory or file to recycle</param>
public static bool Send(string path) {
return Send(path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_WANTNUKEWARNING);
}
/// <summary>
/// Send file silently to recycle bin. Surpress dialog, surpress errors, delete if too large.
/// </summary>
/// <param name="path">Location of directory or file to recycle</param>
public static bool SendSilent(string path)
{
return Send(path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI | FileOperationFlags.FOF_SILENT);
}
}
}
Any way to fix it so it works good on x64 too? I've tried chaning ushort to ulong and couple of other modifications but it doesn't work.
I know there are other solutions that require reference to Microsoft.VisualBasic but i would prefer p/invoke way.
CORRECT ANSWER IS:
Under x64, the SHFILEOPSTRUCT must be declared without the Pack = 1 parameter, or it will fail. This is a real pain if you want your code to be platform independent, as you have to declare two separate structures, one with Pack = 1, and one without. You then have to declare two different SHFileOperation calls, one for each of the structures. Then you have to decide which one to call depending on whether you are running on 32 or 64 bit.
As strange as it seems, .NET already has functions to delete to the Recycle Bin... but they're in the Microsoft.VisualBasic namespace. Specifically, Microsoft.VisualBasic.FileIO.
using Microsoft.VisualBasic.FileIO;
// class declaration, method start here
// Send file to recycle bin without dialog
FileSystem.DeleteFile("pathToFile", UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
// Send file to recycle bin without dialog
FileSystem.DeleteFile("pathToFile", UIOption.AllDialogs, RecycleOption.SendToRecycleBin);
// Directories are the same, but with DeleteDirectory instead
Have you looked at the PInvoke site? It has a slight different definition for the FILEOPSTRUCT type, forcing Unicode for one thing. I wonder if the charset = auto is confusing things...like it defaults to ANSI on 32 bit, but Unicode on 64 bit and something is going wrong somewhere in the middle.
EDIT;
Also, the Visual Basic reference approach is a simple one...I know people have an aversion to it for some reason, but the relevant DLLs are still part of the core framework, so you won't be adding any new dependencies.