I want to automate a program called Spotify from C#, the best way (I think) to do this is by triggering fake keypresses. I want to program to pause playback, and I don't know enough about this stuff to find another way than keypresses. So I use Visual Studio's Spy++ to see what message Spotify gets when pressing the play button on my keyboard, I copy the data from that message into my Console Application and run it, when I run I can see the PostMessage in Spy++'s Message Logging, so this is working but it doesn't pause/play my music. I guess this is because I also have to send another PostMessage with another destination, but how do I know what else to send?
Post Message call:
MessageHelper.PostMessage((int)hwndSpotify, 0x100, 0x000000B3, 0x01000001);
I hope someone is familiar with this and can help me out.
To automate Spotify, first you have to get the handle of the window with the following class name: SpotifyMainWindow (using FindWindow()).
Then, you can use the SendMessage() method to send a WM_APPCOMMAND message to the Spotify's window.
Following a simple code to do that:
internal class Win32
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
internal class Constants
{
internal const uint WM_APPCOMMAND = 0x0319;
}
}
public enum SpotifyAction : long
{
PlayPause = 917504,
Mute = 524288,
VolumeDown = 589824,
VolumeUp = 655360,
Stop = 851968,
PreviousTrack = 786432,
NextTrack = 720896
}
For instance, to play or pause the current track:
Win32.SendMessage(hwndSpotify, Win32.Constants.WM_APPCOMMAND, IntPtr.Zero, new IntPtr((long)SpotifyAction.PlayPause));
Pressing the "play buttion" results in a virtual key code - for an official list see http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx .
There you find for example VK_VOLUME_UP VK_MEDIA_PLAY_PAUSE VK_ZOOM .
Even some Remotes translate to these codes to be as compatible as possible with existing software.
These were introduced back in the day when Windows ME (!) came out and are still in use - at least when I checked the registry of my Windows 2008 R2 !
Basically Windows translates certain VK* into WM_APPCOMMAND messages with certain codes which the applications listen to...
If the key has something to do with launching an app to do (i.e. Mail, Browser etc.) then the magic happens via Windows Explorer which reads the mapping (either by association or direct exec) from the registry at Software\ Microsoft\ Windows\ CurrentVersion\ Explorer\ AppKey - either HKLM or HKCU.
Some links with old but as it seems still valid information:
http://msdn.microsoft.com/en-us/windows/hardware/gg463446.aspx
http://msdn.microsoft.com/en-us/windows/hardware/gg462991
http://msdn.microsoft.com/en-us/windows/hardware/gg463372
Related
So I'm currently trying to check if a user is using a screen reader on our site. The reason I would like to check if they are is because our site provides a training module in which if they are using a screen reader, I would like to show a button that would allow them to download a printable version of the training.
Here is what I have tried so far:
internal class UnsafeNativeMethods
{
public const uint SPI_GETSCREENREADER = 0x0046;
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref bool pvParam, uint fWinIni);
}
public static class ScreenReader
{
public static bool IsRunning
{
get
{
bool returnValue = false;
if (!UnsafeNativeMethods.SystemParametersInfo(UnsafeNativeMethods.SPI_GETSCREENREADER, 0, ref returnValue, 0))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "error calling SystemParametersInfo");
}
return returnValue;
}
}
}
I snagged this code from the following StackOverflow thread: C# : How to detect if screen reader is running?
The method I'm using apparently works for some as you can see on this thread, but I'm currently always getting "false" when calling ScreenReader.IsRunning. I'm storing the ScreenReader.IsRunning value in a ViewBag and then in my view I'm using razor syntax to show a button if that value is true. Not really sure why its always false. I have tested this using JAWS as well as Narrator that comes on everyone's computer if you are using Windows 10 I think. Any help would be much appreciated. Thank you all!
It's not possible to detect whether a user is running a screenreader. If it were possible, it would open a door for unscrupulous types to home in on people with disabilities, or for a totally different "accessible" browser experience to be delivered, rather than building interfaces that are inclusive by design.
You could create a button that's placed off-screen but still in the tab order, and make it visible when it receives focus. Then blind users could find it, and sighted keyboard users wouldn't think something strange had happened when the button received focus.
I think you can only check if user has a chrome extensions or something like that working on client side with javascript.
Idea:
You can create an exe or a bath file for check users system and send information about this to your server. If user download this file and there is no screen reader then load the page. Otherwise give error about the screen reader. And when response come from user computer maybe you can use SignalR for show content to user. You can make this file a must works in users system and start downloading this file when user load the page. Its not a good way but maybe you can check this with this way.
The HttpRequest.Browser property returns a HttpBrowserCapabilities object that enlists the capabilities of the device that has made the request. Bear in mind that ASP.NET uses the User-Agent string sent as part of the HTTP request to identify a client. Then to populate the HttpBrowserCapabilities properties, ASP.NET processes the user-agent string using a set of pre-installed browser files, which are contained in the following location: %SystemRoot%\Microsoft.NET\Framework\v4.0.30319\CONFIG\Browsers
HttpBrowserCapabilities Class
There are also third-parties which are far more detailed and updated with detecting device info, i.e. 51Degrees
I have some program that login to webSite and trying to download file,right now i am using WatIn and User32 FindWindowEx to find the SaveAs dialog and send PostMessage with tab and enter to press Save button
MainPopUp = browserToRun.hWnd.ToInt32();
int currChild = FindWindowEx(MainPopUp, 0, ClassName, WindowName);
PostMessage(currChild, WM_KEYDOWN, VK_TAB, 2);
PostMessage(currChild, WM_KEYDOWN, VK_ENTER, 2);
this works,but not all the time.
This is secured webSite sow i cant see the DownloadUrl and i can't use
[DllImport("urlmon.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern Int32 URLDownloadToFile(Int32 pCaller, string szURL, string szFileName, Int32 dwReserved, Int32 lpfnCB);
int response = URLDownloadToFile(0, browserToRun.Button(Find.ById("btnExcelExport")).Url, #"C:\Users\vladimirp\VN.xls", 0, 0);
I need some mothed that can handle this PopUp dialog,and with out UI,because the User Pc can be locked,sow this have to work even if user windows is lock.
*I dont see the downloadURL sow WebClient.DownloadFileAsync(url,Path) will not work
Do any one know how to handle IE save dialog? .Net c#
Please refer to Handling File Download PopUp post. However the solution in that post requires an active session of desktop.
I need to find open process or application textbox and change its value. But i wanna do it with c# way. If anyone knows could you please share with me? Or do i have to use c++ and how?
Thanks for your advices.
Like another said, UIAutomation is the way to go. http://msdn.microsoft.com/en-us/library/ms753107.aspx
The following code will open Notepad.exe, open its File dialog, then type in some text into the file name field.
Process notepad = Process.Start("notepad");
Thread.Sleep(5000);
SendKeys.SendWait("^o"); //ctrl+o to open the File Dialog
var notepadTextBox = AutomationElement.RootElement.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, "1148"));
object valuePattern = null;
if (notepadTextBox.TryGetCurrentPattern(ValuePattern.Pattern, out valuePattern))
{
((ValuePattern)valuePattern).SetValue("THERE YOU GO"); // this text will be entered in the textbox
}
else
{
//ERROR
}
So this is really a combination of sending keystrokes to control the UI (bring up the File Open dialog) & UIAutomation, but you could change it to drive the Menu like a user would if you need to.
Also you might be wondering where the magic string "1148" comes from - that is the "Automation Id" of the file name entry field in Notepad. I used inspect.exe (included in the Windows SDK) to find the automation Id, you will need that for your application to see its AutomationIds, if it has any.
One way to do this is if the application is out of your control in terms of using libraries and wrappers:
Process[] Procs = Process.GetProcessesByName("NameofProcess");
that will give you the process in question. Now this is where it will get tricky and depend upon what exactly you need to do.
You would eventually need to find where the strings are stored in memory, you could use a memory profiler to do this or something like CheatEngine to find the values, not going to get into what you use CheatEngine for or how you use it, but it is just a simple way of finding memory locations.
You could then read/write to the memory locations using something like this:
[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out int lpNumberOfBytesWritten);
public static byte[] ReadMem(IntPtr MemAddy, uint bytestoread, Process Proc)
{
//
//Create new Memory buffer and pointer to that buffer
//
byte[] buffer = new byte[bytestoread];
IntPtr bufferptr;
//
//Read Process Memory and output to buffer
//
ReadProcessMemory(Proc.Handle, MemAddy, buffer, bytestoread, out bufferptr);
//
//Return the buffer
//
return buffer;
}
public static bool WriteMem(IntPtr MemAddy, byte[] buffer, Process Proc)
{
int NumWriten;
WriteProcessMemory(Proc.Handle, MemAddy, buffer, (uint)buffer.Length, out NumWriten);
if (NumWriten != buffer.Length)
{
return false;
}
else return true;
}
These two functions would allow you to read and write to some arbitrary processes memory locations.
if you want the window in question you could use:
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
Like So:
IntPtr HWND = FindWindow(null, "WinName");
Which will give you the handle to the window in question.
Another way to do this would be to find the window and then pass some events to it, like bring the window to focus and then tab through the text boxes programmatically. However without more information about what exactly you are trying to do I am not sure what else to say here.
The tool you are looking for is UI Automation. It will let you see the other program's controls and send text to those controls. I have done this in the past where I had to export data from a corrupted database and I had to click OK on a dialog every time it hit a corrupted record.
The topic is too complex to go in to depth on how to do it in the space of a SO answer, but here is a tutorial I found on CodePlex that goes over how to do it.
There are also 3rd party wrapper libraries to make it easier to do. My personal favorite is White.
I am fairly new to C# as well as windows programming and I am attempting to establish communication between a USB HID device and an app written in c# on a windows xp pc. I have obtained the device path successfully and have used this to establish a valid Handle on the device:
IntPtr drive = CreateFile(devicePath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero,
OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, IntPtr.Zero);
This proved to be a valid handle that yields a positive integer when tested. After creating the handle I call 'HidD_GetPreparsedData' and 'HidP_GetCaps' which yield a struct previously imported (HIDP_CAPS) that stores specific data related to the device attached. Next, I try to call writefile():
bool success = WriteFile(drive, ref outputReportBuffer,
caps.OutputReportByteLength, ref numberOfBytesWritten,
IntPtr.Zero);
drive: The Handle of the device
outputReportBuffer:The array of bytes to write [65]
caps.OutputReportByteLength: The amount of bytes to write, caps is the struct of HIDP_CAPS
numberOfBytesWritten: hardcoded to 0
IntPtr.Zero: Everything I have read passes this last parameter as I have done. In the formal parameters of 'writefile' the last parameter is listed as 'IntPtr ipOverlapped', but I have not been able to figure out what that is, except that It should be passed as some form of 0
How WriteFile is imported:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteFile(IntPtr hFile,
ref byte[] lpBuffer,
uint nNumberOfBytesToWrite,
ref uint lpNumberOfBytesWritten,
IntPtr ipOverlapped);
When writefile is executed it simply does nothing. I get no error, but when tested, it reveals that communication was never established and it was not successful. If anyone could share any knowledge or provide any resources to help I would really appreciate it. Thank you for reading.
Regards.
Remove the ref in your WriteFile declaration.
While http://www.pinvoke.net/ is a great resource for P/Invoke declarations, it's a wiki-style website and many declarations are wrong (often they won't work on a x64 machine).
I need to play a wav file from a C# application running as a Windows Service. I have tried both System.Media.SoundPlayer and a P/Invoke call to WinMM.dll (which is probably what SoundPlayer is doing).
[DllImport("WinMM.dll")]
private static extern bool PlaySound(string fname, int Mod, int flag);
If I run my code as a console application, the sounds play. When I run it from a service, no luck, and I guess I'm not surprised.
So is there a way to play a sound from a windows service? Would something like DirectSound help? Or am I going to be stuck writing a console application and having the windows service app communicate with it as an intermediary?
Thanks in advance
Playing a wav file from a service is definitely possible, at least on Windows 7 (and most likely Vista), by using the Windows Core Audio APIs. I recently verified this by making a small test service using NAudio. I just downloaded the NAudio sources and copied the "Wsapi" parts from their NAudioDemo project. This was on Windows 7 Enterprise 64bit, but I don't think that matters. The service was using the LocalSystem account.
For the record, playing sounds from a service is a perfectly legitimate thing to do in an embedded setting.
You can do this via the PlaySound API via winmm.dll, in Windows Vista or above. Microsoft added a seperate session for 'System Sounds' that can be used even from services, by merely adding a flag.
I've formatted this properly to avoid issues with the c# 2017 IDE throwing a wobbly over the DllImport not being in a class named 'NativeMethods'.
using System.Runtime.InteropServices;
namespace Audio
{
internal static class NativeMethods
{
[DllImport("winmm.dll", EntryPoint = "PlaySound", SetLastError = true, CharSet = CharSet.Unicode, ThrowOnUnmappableChar = true)]
public static extern bool PlaySound(
string szSound,
System.IntPtr hMod,
PlaySoundFlags flags);
[System.Flags]
public enum PlaySoundFlags : int
{
SND_SYNC = 0x0000,/* play synchronously (default) */
SND_ASYNC = 0x0001, /* play asynchronously */
SND_NODEFAULT = 0x0002, /* silence (!default) if sound not found */
SND_MEMORY = 0x0004, /* pszSound points to a memory file */
SND_LOOP = 0x0008, /* loop the sound until next sndPlaySound */
SND_NOSTOP = 0x0010, /* don't stop any currently playing sound */
SND_NOWAIT = 0x00002000, /* don't wait if the driver is busy */
SND_ALIAS = 0x00010000,/* name is a registry alias */
SND_ALIAS_ID = 0x00110000, /* alias is a pre d ID */
SND_FILENAME = 0x00020000, /* name is file name */
SND_RESOURCE = 0x00040004, /* name is resource name or atom */
SND_PURGE = 0x0040, /* purge non-static events for task */
SND_APPLICATION = 0x0080, /* look for application specific association */
SND_SENTRY = 0x00080000, /* Generate a SoundSentry event with this sound */
SND_RING = 0x00100000, /* Treat this as a "ring" from a communications app - don't duck me */
SND_SYSTEM = 0x00200000 /* Treat this as a system sound */
}
}
public static class Play
{
public static void PlaySound(string path, string file = "")
{
NativeMethods.PlaySound(path + file, new System.IntPtr(), NativeMethods.PlaySoundFlags.SND_ASYNC | NativeMethods.PlaySoundFlags.SND_SYSTEM);
}
}
}
Applied the NAudio to simply allow to play audio file.
http://bresleveloper.blogspot.co.il/2012/06/c-service-play-sound-with-naudio.html
You've chosen the wrong application type. A windows service is for longer running applications that execute non-interactively, whether or not someone has logged into the computer. For example SQL Server, IIS etc.
You are also prevented in Windows Vista and later, from displaying user interface windows from a windows service. For Windows XP,2000 Server and you can display a MessageBox, however this is not recommended for most services.
So in general, services are not permitted to be "interactive", this includes playing sounds, multimedia etc.
You either need to change the application type to a normal Console/Windows Forms application, or live without playing sounds from your service.
For more information see this page on interactive services and related pages at MSDN.