I am planning to make a simple program that I can use in my daily life.
My goal is to create a program that can sendkeys into 2 applications like Notepad and Word or notepad1 and notepad2 at the same time. I don't have yet a code because I don't know how and where should I start.
I would like to use .net or C# or C++.
// import the function in your class
[DllImport ("User32.dll")]
static extern int SetForegroundWindow(IntPtr point);
Process[] ps = Process.GetProcessesByName("notepad");
foreach (Process p in ps)
{
IntPtr h = p.MainWindowHandle;
SetForegroundWindow(h);
SendKeys.SendWait("TEXT TO SEND");
}
Source: C# using Sendkey function to send a key to another application
Related
I would like to close notepad file without prompting "Would you like to save changes" dialog box. I tried:
SendMessage(handle, 0x0010, IntPtr.Zero, IntPtr.Zero);
But asks me whether I'd like to save changes or not. Also DestroyWindow(HWND) doesn't work.
How to overcome this problem?
Thanks a lot...
If you don't care about the data on notepad then simply kill its process.
[DllImport("user32.dll", SetLastError=true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
Now kill the process using its process id
Process p = Process.GetProcessById(processId);
p.Kill();
Just to add to the answer posted by #prem, there is absolutely no need for using APIs. .NET already includes everything to do this like in the example below.
var processes = Process.GetProcessesByName("notepad");
foreach (var process in processes)
process.Kill();
I’m trying to get information (list full names of opened documents) about all running instances of AutoCAD 2007 through its COM interface with C# external application. Here’s a code:
…
using AutoCAD = Autodesk.AutoCAD.Interop;
using System.Runtime.InteropServices.ComTypes;
…
[DllImport("ole32.dll")]
extern static IntPtr CreateBindCtx(IntPtr reserved, out IBindCtx ppbc);
…
static void ListACADDocs()
{
IntPtr HRESULT;
IBindCtx objCtx = null;
HRESULT = CreateBindCtx(new IntPtr(0), out objCtx);
IRunningObjectTable objRot = null;
objCtx.GetRunningObjectTable(out objRot);
IEnumMoniker RunningMonikers = null;
objRot.EnumRunning(out RunningMonikers);
RunningMonikers.Reset();
IntPtr pointerFetchedMonikers = IntPtr.Zero;
IMoniker[] monikerContainer = new IMoniker[1];
String strDisplayName;
Object COMObject = null;
List<Object> colACADInstances = new List<Object>();
while (RunningMonikers.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
monikerContainer[0].GetDisplayName(objCtx, null, out strDisplayName);
objRot.GetObject(monikerContainer[0], out COMObject);
//AutoCAD.Application.17 class ID: {28B7AA99-C0F9-4C47-995E-8A8D729603A1}
if (strDisplayName == "!{28B7AA99-C0F9-4C47-995E-8A8D729603A1}")
colACADInstances.Add(COMObject);
}
foreach (Object obj in colACADInstances)
foreach(AutoCAD.AcadDocument doc in
((AutoCAD.AcadApplication)obj).Documents)
Console.WriteLine(doc.FullName);
}
In result, it finds correct number of monikers that corresponds to all ACAD running instances, but retrieves documents’ names from the “earliest” instance only. It looks like all monikers refer to single AutoCAD.AcadApplication object. Is there any way to do that for every instance?
AutoCAD only registers once in the Running Object Table anyway, so going down that road gets you nowhere. I was in this exact same spot a few years ago, and even opened up a discussion with Kean Walmsley about it. He pointed me to a technique that required running a pseduo-registration to a custom service from inside each AutoCAD session from VBA, and then having your .NET application look to that custom registration. Sloppy? Definitely. However the concept is sound if you really need to get it to work.
This is typical behavior for "heavy" programs, like AutoCAD. MS Word is another example. They are single-instance apps. If you already have AutoCAD running then the second time you start it, it passes the command line to the first instance to ask it to open the document. And exits.
So there really is only one process, it has multiple documents opened. Use Taskmgr.exe, Processes tab to verify this.
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 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
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.