I'm developing an C# application which includes a RichTextBox. I want to paste the copied text to RichTextBox automatically, every time user copies a text from other application like web browsers. I can paste the copied text by this code:
if (Clipboard.ContainsText())
rtb1.Paste();
The problem is I don't know when exactly user clicks on copy from pop up menu or presses Ctrl + C in other applications.
Is there any way to check that without having a Timer to check the clipboard content like every second?
I found my answer here.
In order to do that we need to pinvoke the AddClipboardFormatListener and RemoveClipboardFormatListener.
/// <summary>
/// Places the given window in the system-maintained clipboard format listener list.
/// </summary>
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AddClipboardFormatListener(IntPtr hwnd);
/// <summary>
/// Removes the given window from the system-maintained clipboard format listener list.
/// </summary>
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
/// <summary>
/// Sent when the contents of the clipboard have changed.
/// </summary>
private const int WM_CLIPBOARDUPDATE = 0x031D;
Then we need to add our window to the clipboard format listener list by calling the AddClipboardFormatListener method with our window’s handle as a parameter. Place the following code in your main window form constructor or any of its load events.
AddClipboardFormatListener(this.Handle); // Add our window to the clipboard's format listener list.
Override the WndProc method so we can catch when the WM_CLIPBOARDUPDATE is send.
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_CLIPBOARDUPDATE)
{
IDataObject iData = Clipboard.GetDataObject(); // Clipboard's data.
if (iData.GetDataPresent(DataFormats.Text))
{
rtb1.Paste();
}
}
}
And finally make sure to remove your main window from the clipboard format listener list before closing your form.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
RemoveClipboardFormatListener(this.Handle); // Remove our window from the clipboard's format listener list.
}
Related
Background
I am working on a application that make extensive use of SetParent functionality in order to play several video players into a single application while keeping memory of main applicaton under control.
Everytime the user requests to see a video, a new player.exe is executed and attached to the main window. This is working fine for most use case scenarios.
But there is one I am struggling with. In this scenario the user is playing lots of videos in a fast sequence, which means that main application is constantly killing and creating new players.
Everytime a player.exe is executed, a small hourglass icon appears on the mouse icon, and given that in this case scenario those players are created pretty fast, then the hourglass icon keeps playing constantly.
Motivation
I guess this is possible as for example google chrome makes use of this for each tab and you can add multiple taps without the busy hourglass icon to appear on each tab creation.
Details
I am in control of both main application and player applications just to note that I could do any change to both.
I have made a small windows form application as example of this behaviour, with 2 buttons and 1 panel.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace SetParentTest
{
public partial class Form1 : Form
{
private Process _childProcessPlayer;
public Form1()
{
InitializeComponent();
this.Closing += (sender, args) =>
{
Clear();
};
}
public const UInt32 WS_POPUP = 0x80000000;
public const UInt32 WS_CHILD = 0x40000000;
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetParent(
IntPtr windowChildHandle,
IntPtr windowNewParentHandle);
[DllImport("user32.dll", SetLastError = true)]
public static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport ( "user32.dll" )]
public static extern int SetWindowLong ( IntPtr hWnd, int nIndex, uint dwNewLong );
public enum WindowLongFlags : int
{
GWL_EXSTYLE = -20,
GWLP_HINSTANCE = -6,
GWLP_HWNDPARENT = -8,
GWL_ID = -12,
GWL_STYLE = -16,
GWL_USERDATA = -21,
GWL_WNDPROC = -4,
DWLP_USER = 0x8,
DWLP_MSGRESULT = 0x0,
DWLP_DLGPROC = 0x4
}
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MoveWindow(
IntPtr windowHandle,
int x,
int y,
int width,
int height,
[MarshalAs(UnmanagedType.Bool)] bool repaint);
[DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
/// <summary>Enumeration of the different ways of showing a window using
/// ShowWindow</summary>
private enum WindowShowStyle : uint
{
/// <summary>Hides the window and activates another window.</summary>
/// <remarks>See SW_HIDE</remarks>
Hide = 0,
/// <summary>Activates and displays a window. If the window is minimized
/// or maximized, the system restores it to its original size and
/// position. An application should specify this flag when displaying
/// the window for the first time.</summary>
/// <remarks>See SW_SHOWNORMAL</remarks>
ShowNormal = 1,
/// <summary>Activates the window and displays it as a minimized window.</summary>
/// <remarks>See SW_SHOWMINIMIZED</remarks>
ShowMinimized = 2,
/// <summary>Activates the window and displays it as a maximized window.</summary>
/// <remarks>See SW_SHOWMAXIMIZED</remarks>
ShowMaximized = 3,
/// <summary>Maximizes the specified window.</summary>
/// <remarks>See SW_MAXIMIZE</remarks>
Maximize = 3,
/// <summary>Displays a window in its most recent size and position.
/// This value is similar to "ShowNormal", except the window is not
/// actived.</summary>
/// <remarks>See SW_SHOWNOACTIVATE</remarks>
ShowNormalNoActivate = 4,
/// <summary>Activates the window and displays it in its current size
/// and position.</summary>
/// <remarks>See SW_SHOW</remarks>
Show = 5,
/// <summary>Minimizes the specified window and activates the next
/// top-level window in the Z order.</summary>
/// <remarks>See SW_MINIMIZE</remarks>
Minimize = 6,
/// <summary>Displays the window as a minimized window. This value is
/// similar to "ShowMinimized", except the window is not activated.</summary>
/// <remarks>See SW_SHOWMINNOACTIVE</remarks>
ShowMinNoActivate = 7,
/// <summary>Displays the window in its current size and position. This
/// value is similar to "Show", except the window is not activated.</summary>
/// <remarks>See SW_SHOWNA</remarks>
ShowNoActivate = 8,
/// <summary>Activates and displays the window. If the window is
/// minimized or maximized, the system restores it to its original size
/// and position. An application should specify this flag when restoring
/// a minimized window.</summary>
/// <remarks>See SW_RESTORE</remarks>
Restore = 9,
/// <summary>Sets the show state based on the SW_ value specified in the
/// STARTUPINFO structure passed to the CreateProcess function by the
/// program that started the application.</summary>
/// <remarks>See SW_SHOWDEFAULT</remarks>
ShowDefault = 10,
/// <summary>Windows 2000/XP: Minimizes a window, even if the thread
/// that owns the window is hung. This flag should only be used when
/// minimizing windows from a different thread.</summary>
/// <remarks>See SW_FORCEMINIMIZE</remarks>
ForceMinimized = 11
}
/// <summary>
/// Handles the Click event of the button1 control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
private void button1_Click(object sender, EventArgs e)
{
AttachWindow();
}
/// <summary>
/// Handles the Click event of the button1 control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
private void button2_Click(object sender, EventArgs e)
{
Clear();
}
private void Clear()
{
if (_childProcessPlayer == null)
return;
if (_childProcessPlayer.HasExited)
{
_childProcessPlayer = null;
return;
}
_childProcessPlayer.Kill();
_childProcessPlayer = null;
}
private void AttachWindow()
{
// do it only once per test.
if (_childProcessPlayer != null)
return;
// Instance of the remote process to start.
//_childProcessPlayer = Process.GetProcessesByName("notepad").FirstOrDefault();
_childProcessPlayer = new Process
{
StartInfo =
{
FileName = #"C:\Windows\System32\notepad.exe",
//CreateNoWindow = true,
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Minimized
},
EnableRaisingEvents = true
};
Cursor.Current = Cursors.Default;
_childProcessPlayer.Start();
Cursor.Current = Cursors.Default;
_childProcessPlayer.WaitForInputIdle();
Cursor.Current = Cursors.Default;
ShowWindow(_childProcessPlayer.MainWindowHandle, (int)WindowShowStyle.Hide);
// Get process window handle.
var mainWindowHandle = _childProcessPlayer.MainWindowHandle;
// To prevent focus steal when SetParent is called I need to add WS_CHILD to the style.
uint windowLong = GetWindowLong(
mainWindowHandle,
(int) WindowLongFlags.GWL_STYLE);
// add ws_child
windowLong |= WS_CHILD;
// remove pop_up (most cases this is not necessary as it is already unset)
windowLong &= ~WS_POPUP;
// modify the style.
SetWindowLong(
mainWindowHandle,
(int)WindowLongFlags.GWL_STYLE,
windowLong);
// Disable panel to prevent focus being stolen. (necessary in some cases)
panel1.Enabled = false;
// Execute Set parent.
SetParent(mainWindowHandle, panel1.Handle);
// Restore child state in order to allow editing in the notepad.
windowLong &= ~WS_CHILD;
SetWindowLong(
mainWindowHandle,
(int)WindowLongFlags.GWL_STYLE,
windowLong);
// Hide panel while notepad is resized.
panel1.Visible = false;
// Show notepad so resizing work
ShowWindow(_childProcessPlayer.MainWindowHandle, (int)WindowShowStyle.ShowNormal);
// Resize and move the window to the panel size.
MoveWindow(mainWindowHandle, 0, 0, panel1.Width, panel1.Height, true);
panel1.Visible = true;
panel1.Enabled = true;
}
}
}
I leave the whole code as someone might be interested. Obviously I am not in control of notepad.exe though.
This code is the closest I can get to the one I use in the original application. For unknown reasons starting hidden was not working fine with notepad so I had to hide it afterwards so it appears nicely without blinks into the panel.
Already tried
I have noticed that retrieving notepad if it is already started have
no issues.
Calling Process.Start in a Task, or a different thread,
have no effect.
I have noticed that the hourglass appears even when
you execute it directly on windows so the hourglass effect might me
something that could be disabled by the child executable. (which
means the adhoc test provided would never work as it is using
notepad.exe).
Question
Finally the question is: is it possible to call Process Start of a child application avoiding the hourglass to appear on the mouse while doing so?
Worst case scenario would be to disable hourglass icon at windows registry (I guess this is possible although I currenltly don't know) but this would be my last option.
Edit 1:
Another thing I have tried:
Forcing the mouse icon before calling Process start.
I thought it was going to work as it worked for the hand icon or a different icon than the pointer, but if the icon is the pointer, it does not work.
Cursor cr = new Cursor(Cursors.Arrow.Handle);
Icon ico = Icon.FromHandle(cr.Handle);
cr = new Cursor(ico.Handle);
Cursor.Current = cr;
_childProcessPlayer.Start();
_childProcessPlayer.WaitForInputIdle();
Cursor.Current = Cursors.Default;
I came up with 2 workarounds although not perfect ones:
1- Disable mouse with hourglass at windows level by configuring a different icon.
Obviously that affects everything.
2- Forcing the icon before the operation did work if it does not know the icon is the arrow:
Icon ico = Icon.FromHandle(Cursor.Current.Handle);
ico = (Icon)ico.Clone();
Cursor.Current = new Cursor(ico.Handle);
_childProcessPlayer.Start();
_childProcessPlayer.BeginOutputReadLine();
_childProcessPlayer.WaitForInputIdle();
Cursor.Current = Cursors.Default;
The problem with this other solution is that it only works well if the mouse remains over your application. If the mouse is outside it setting the icon does not work 100% of the times.
Please note that I have spent a lot of time searching through online posts including on SO but have been unsuccessful so far.
The problem is with the touchscreen keyboard that started being opened automatically because of the Windows 10 Touch Keyboard and Handwriting Panel Service whenever somebody clicks on a textbox whereas before with Windows 8.1 the keyboard was opened only due to the C# API calls from within our Structures Asset Management (SAM) app. Thus with Windows 10, the virtual keyboard was being opened twice whenever someone clicks on a textbox-—once because of the SAM C# API call and once due to the Touch Keyboard and Handwriting Panel Service.
Please note that we have attempted to disable the Touch Keyboard and Handwriting Panel Service but that then causes the touchscreen keyboard to not appear at all.
Normally, it would be fine to just let the OS open this touchscreen keyboard using the Touch Keyboard and Handwriting Panel Service but the problem is we need to sometimes show the touchscreen keyboard and other times show only a numeric keypad, so just relying on the Windows service is not an option.
Here are the classes that worked successfully for controlling the keyboard in Windows 8.1:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Input;
namespace Cpr.Apps.Sam.Controls
{
/// <summary>
/// Shows or hides the touch keyboard on tablets.
/// </summary>
public class TouchKeyboard
{
/// <summary>
/// The touch keyboard app's file path.
/// </summary>
private static string _touchKeyboardAppFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles), #"Microsoft Shared\ink\TabTip.exe");
/// <summary>
/// Set to true if the app is currently running on a touch device and false otherwise.
/// </summary>
private static bool _isTouchScreen = Tablet.TabletDevices.Cast<TabletDevice>().Any(tabletDevice => tabletDevice.Type == TabletDeviceType.Touch);
/// <summary>
/// The keyboard visible flag.
/// </summary>
/// <remarks>
/// This flag only keeps track of the keyboard's visibility if it was set using this class.
/// </remarks>
private static bool _isKeyboardVisible;
/// <summary>
/// The delay after which the keyboard will be hidden, in seconds.
/// </summary>
/// <remarks>
/// The keyboard is not hidden immediately when the associated input field loses the keyboard focus, so that it will
/// not flicker if another input field with this behavior obtains the keyboard focus immediately afterwards.
/// </remarks>
private const double KEYBOARD_HIDE_DELAY = 0.25;
/// <summary>
/// The number of milliseconds per second. Used for time conversions.
/// </summary>
private const long MILLISECONDS_PER_SECOND = 1000;
/// <summary>
/// True if the current device has a touch screen and false otherwise.
/// </summary>
public static bool IsTouchScreen
{
get { return _isTouchScreen; }
}
/// <summary>
/// Shows the touch keyboard if the app is running on a touch device.
/// </summary>
/// <remarks>
/// This method does nothing if the app is not currently running on a touch device.
/// </remarks>
public static void Show()
{
// check if the app is running on a touch device
if (_isTouchScreen && _touchKeyboardAppFilePath != null)
{
try
{
// launch the touch keyboard app
Process.Start(_touchKeyboardAppFilePath);
// set the keyboard visible flag
_isKeyboardVisible = true;
}
catch (Exception)
{
// do nothing
}
}
}
/// <summary>
/// Hides the touch keyboard if the app is running on a touch device.
/// </summary>
/// <remarks>
/// This method does nothing if the app is not currently running on a touch device.
/// </remarks>
public static void Hide()
{
// check if the app is running on a touch device
if (_isTouchScreen)
{
// reset the keyboard visible flag
_isKeyboardVisible = false;
// hide the keyboard after a delay so that if another input field with this behavior obtains the focus immediately,
// the keyboard will not flicker
Timer timer = null;
timer = new Timer((obj) =>
{
// check if the keyboard should still be hidden
if (!_isKeyboardVisible)
{
// check if the keyboard is visible
var touchKeyboardWindowHandle = FindWindow("IPTip_Main_Window", null);
if (touchKeyboardWindowHandle != _nullPointer)
{
// hide the keyboard
SendMessage(touchKeyboardWindowHandle, WM_SYSCOMMAND, SC_CLOSE, _nullPointer);
}
}
// release the timer
timer.Dispose();
}, null, (long)(KEYBOARD_HIDE_DELAY * MILLISECONDS_PER_SECOND), Timeout.Infinite);
}
}
// Win32 null pointer parameter
private static IntPtr _nullPointer = new IntPtr(0);
// Win32 command from the Window menu
private const uint WM_SYSCOMMAND = 0x0112;
// Win32 command to close a window
private static IntPtr SC_CLOSE = new IntPtr(0xF060);
// Win32 API to get a window reference
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr FindWindow(string sClassName, string sAppName);
// Win32 API to send a message to a window
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
}
}
And:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using Cpr.Apps.Sam.Controls;
namespace Cpr.Apps.Sam.Styles.Behaviors
{
/// <summary>
/// Behavior that shows the touch keyboard (on tablets only) when the associated control gets the keyboard focus.
/// </summary>
public class ControlShowTouchKeyboardOnFocusBehavior : Behavior<Control>
{
protected override void OnAttached()
{
base.OnAttached();
// add the event handlers
WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "GotKeyboardFocus", OnGotKeyboardFocus);
WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "LostKeyboardFocus", OnLostKeyboardFocus);
}
/// <summary>
/// Called when the associated control receives the keyboard focus.
/// </summary>
/// <param name="sender">The object triggering this event.</param>
/// <param name="e">The event parameters.</param>
private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// show the touch keyboard
TouchKeyboard.Show();
var textBox = sender as TextBox;
if (textBox != null)
textBox.SelectionStart = Math.Max(0, textBox.Text.Length); //Move the caret to the end of the text in the text box.
}
/// <summary>
/// Called when the associated control loses the keyboard focus.
/// </summary>
/// <param name="sender">The object triggering this event.</param>
/// <param name="e">The event parameters.</param>
private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// hide the touch keyboard
TouchKeyboard.Hide();
}
}
}
Basically, my question is, how can I make the touchscreen keyboard in Windows 10 behave the same way it did in Windows 8.1? Are there some configuration values I can change on the OS settings, or do I need to change something in the registry? What are the differences between the Touch Panel and Handwriting Service in Windows 8.1 and Windows 10? TIA.
UPDATE:
Please note that I have explored using the "On Screen Keyboard" which I believe is based on COM instead of the newer "Touchscreen Keyboard" but that did not help because ultimately because this COM keyboard requires admin privileges to close or minimize it. This is what I attempted with the "On Screen Keyboard":
using System;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using Cpr.Apps.Sam.Controls;
namespace Cpr.Apps.Sam.Styles.Behaviors
{
/// <summary>
/// Behavior that shows the touch keyboard (on tablets only) when the associated control gets the keyboard focus.
/// </summary>
public class ControlShowTouchKeyboardOnFocusBehavior : Behavior<Control>
{
[DllImport("User32")]
private static extern int ShowWindow(int hwnd, int nCmdShow);
private const int SW_HIDE = 0;
private const int SW_RESTORE = 9;
private int hWnd;
private readonly string _USB = "USB";
private readonly string _keyboard = #"osk.exe";
private Process _keyboardProcess = null;
private ProcessStartInfo _startInfo = null;
protected override void OnAttached()
{
base.OnAttached();
// add the event handlers
WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "GotKeyboardFocus", OnGotKeyboardFocus);
WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "LostKeyboardFocus", OnLostKeyboardFocus);
}
private bool GetKeyboardPresent()
{
bool flag = false;
foreach (ManagementBaseObject managementBaseObject in new ManagementObjectSearcher("Select * from Win32_Keyboard").Get())
{
foreach (PropertyData property in managementBaseObject.Properties)
{
if (Convert.ToString(property.Value).Contains(this._USB))
{
flag = true;
break;
}
}
}
return flag;
}
/// <summary>
/// Called when the associated control receives the keyboard focus.
/// </summary>
/// <param name="sender">The object triggering this event.</param>
/// <param name="e">The event parameters.</param>
private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// show the touch keyboard
// TouchKeyboard call here not needed in Windows 10 because of “Touch Keyboard and Handwriting Panel Service” causes virtual keyboard to show up twice. Use on screen keyboard instead.
//TouchKeyboard.Show();
if (!this.GetKeyboardPresent())
{
//_keyboardProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
Process[] pocesses = Process.GetProcessesByName(_keyboard);
if (pocesses.Any())
{
foreach (var proc in pocesses)
{
hWnd = (int) proc.MainWindowHandle;
ShowWindow(hWnd, SW_RESTORE);
}
}
else
{
_startInfo = new ProcessStartInfo(_keyboard);
_keyboardProcess = new Process
{
EnableRaisingEvents = true,
StartInfo = _startInfo
};
_keyboardProcess.Exited += new EventHandler(ProcessExited);
//Don't need this because it is for parent process: AppDomain.CurrentDomain.ProcessExit += (a, b) => _keyboardProcess.Kill();
_keyboardProcess.Start();
}
}
var textBox = sender as TextBox;
if (textBox != null)
textBox.SelectionStart = Math.Max(0, textBox.Text.Length); //Move the caret to the end of the text in the text box.
}
/// <summary>
/// Called when the associated control loses the keyboard focus.
/// </summary>
/// <param name="sender">The object triggering this event.</param>
/// <param name="e">The event parameters.</param>
private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// hide the touch keyboard
// TouchKeyboard call here not needed in Windows 10 because of “Touch Keyboard and Handwriting Panel Service” causes virtual keyboard to show up twice. Use on screen keyboard instead.
//TouchKeyboard.Hide();
if (!GetKeyboardPresent() && _keyboardProcess != null)
{
//Keyboard doesn't minimize if I call Kill() or SW_HIDE, and instead this simply causes the textbox to lose focus so commented out this code
//Process[] pocesses = Process.GetProcessesByName("osk");
//for (int i = 0; i < pocesses.Count(); i++)
//{
// var proc = pocesses[i];
// proc.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
//hWnd = (int)proc.MainWindowHandle;
//ShowWindow(hWnd, SW_HIDE);
//}
//Task.Delay(500);
}
}
private void ProcessExited(object sender, System.EventArgs e)
{
Debug.WriteLine("Exited _keyboardProcess");
_keyboardProcess = null;
}
}
}
UPDATE 2:
It looks like I may need to port my app from WPF to WinRT to get it to work on Windows 10: See https://learn.microsoft.com/en-us/windows/uwp/porting/ where it says
Move from WPF and Silverlight to WinRT
in
Related Topics
Ended up using a custom WPF software keyboard built in C# instead of the Windows “Touch Keyboard and Handwriting Panel Service” Touchscreen Keyboard and the Onscreen Keyboard.
I have a program which needs to send every line of a text file to an application while minimized. I am able to send the text to the application but this causes it to be opened. Is there a way to do this while the application is minimized? I have read that I could use postmessage or sendmessage but am unsure how to do this.
public partial class Form1 : Form
{
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lp1, string lp2);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IntPtr handle = FindWindow(null, "Application");
if (!handle.Equals(IntPtr.Zero))
{
if (SetForegroundWindow(handle))
{
string[] dic = System.IO.File.ReadAllLines(#"text file name");
foreach (string a in dic)
{
SendKeys.Send(a);
}
}
}
}
}
It's not clear from the question what "send the text" means. But, if you want to set the text in a text-box in the target application, then you're in luck.
You can get a handle do the text box control you want the text to go to in the target application. This is going to be the most difficult part because you will have to figure out a way to distinguish that text box from others the application may have (probably using a combination of Spy++ and trial-and-error).
Once you have figured out the text control you want to send the text to, the rest is just sending a WM_SETTEXT message to the other application's text box control.
Here is another SO relevant question for you to reference: SetText of textbox in external app. Win32 API
A client has a problem with employees opening a program displaying sensitive information and walking away without closing it. They've asked me to monitor when the application is open and close it after a certain amount of inactivity.
What I've done is created a new program that launches the original, but with another form on top of it. If my form is transparent, I can click through the form with no problems, and manipulate the underlying program. If my form is (slightly) opaque, clicks will register with my program, but will not pass through.
What I need is a way to let my form register that a click has happened, reset its timer, and pass the click through to the underlying application. I can reset the timer, or I can pass the click through, but not both.
Here's the code I'm currently trying. The first section defines my form as transparent and keeps it on top of the other application.
private void Form1_Load(object sender, EventArgs e)
{
this.Opacity = 0.40;
this.TopMost = true;
}
I thought this would let me monitor for a click, reset the timer, then pass it through, but it's not working, so I must be missing something. EDIT: WT_NCHITTEST = 0x84, and HTTRANSPARENT = -1, as indicated here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCHITTEST) // m.Msg 0x84 means that Windows is asking our form whether it is "transparent" or not.
{
timeToClose = 10;
m.Result = new IntPtr(HTTRANSPARENT); // tell Windows yes, to pass everything through.
}
base.WndProc(ref m);
}
That is way over engineered, I implement inactivity checks with System.Timers.Timer and PInvoke GetLastInputInfo. Run a second application that monitors for workstation inactivity and close sensitive applications when the threshold is violated.
Initialize the timer with an interval and set it to auto-reset, then just check for inactivity every time the timer elapses. If the inactivity time is greater than your threshold, shut it down.
Here is the code for GetLastInputInfo.
public static class Tracker
{
/// <summary>
/// Reference to the GetLastInputInfo in the user32.dll file.
/// </summary>
/// <param name="plii">LASTINPUTINFO struct</param>
/// <returns></returns>
[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
/// <summary>
/// Polls the system for the milliseconds elapsed since last user input.
/// </summary>
/// <returns>Milliseconds since last user input.</returns>
public static uint GetIdleTime()
{
LASTINPUTINFO lastInput = new LASTINPUTINFO();
lastInput.cbSize = (uint)Marshal.SizeOf(lastInput);
GetLastInputInfo(ref lastInput);
return ((uint)Environment.TickCount - lastInput.dwTime);
}
}
/// <summary>
/// Struct required and populated by the user32.dll GetLastInputInfo method.
/// </summary>
internal struct LASTINPUTINFO
{
public uint cbSize; //Size of the struct.
public uint dwTime; //TickCount at last input.
}
My inactivity timer implementation looks like this:
public void InitializeTimer()
{
ActivityTimer = new System.Timers.Timer(Configuration.TimeoutSettings["IntervalMilliseconds"]);
ActivityTimer.AutoReset = true;
ActivityTimer.Elapsed += OnElapsedPollForActivity;
ActivityTimer.Start();
}
/// <summary>
/// Method is called in ValidationForm_FormClosing, unsubscribes handler from event and stops the clock.
/// </summary>
public void TerminateTimer()
{
ActivityTimer.Elapsed -= OnElapsedPollForActivity;
ActivityTimer.Stop();
}
/// <summary>
/// Fires on ActivityTimer.Elapsed, polls workstation for time since last user input.
/// </summary>
private void OnElapsedPollForActivity(object sender, System.Timers.ElapsedEventArgs e)
{
if (Tracker.GetIdleTime() > Configuration.TimeoutSettings["TriggerMilliseconds"])
{
Logger.LogException(CurrentSession.SessionID, DateTime.Now, new InactivityException("Detected extended period of workstation inactivity."));
Application.Exit();
}
}
I am trying to invoke the "Run" dialogue box that is often on the Start Menu - I did some research and have only managed to find one way of accessing it (using "Windows Key" + R).
So I assume simulating key strokes e.g.:
SendKeys.Send("{TEST}")
would do the job? Although how can you simulate the "Windows" key on the keyboard?
I am sure there is an easier way of doing this - without using sendkeys - anyone have any ideas?
You can use PInvoke to invoke Run dialog.
[Flags()]
public enum RunFileDialogFlags : uint
{
/// <summary>
/// Don't use any of the flags (only works alone)
/// </summary>
None = 0x0000,
/// <summary>
/// Removes the browse button
/// </summary>
NoBrowse = 0x0001,
/// <summary>
/// No default item selected
/// </summary>
NoDefault = 0x0002,
/// <summary>
/// Calculates the working directory from the file name
/// </summary>
CalcDirectory = 0x0004,
/// <summary>
/// Removes the edit box label
/// </summary>
NoLabel = 0x0008,
/// <summary>
/// Removes the separate memory space checkbox (Windows NT only)
/// </summary>
NoSeperateMemory = 0x0020
}
we need to Import the DLL using the DllImport attribute.
[DllImport("shell32.dll", CharSet = CharSet.Auto, EntryPoint = "#61", SetLastError = true)]
static extern bool SHRunFileDialog(IntPtr hwndOwner,
IntPtr hIcon,
string lpszPath,
string lpszDialogTitle,
string lpszDialogTextBody,
RunFileDialogFlags uflags);
Implementation:
private void ShowRunDialog(object sender, RoutedEventArgs e)
{
SHRunFileDialog(IntPtr.Zero,
IntPtr.Zero,
"c:\\",
"Run Dialog using PInvoke",
"Type the name of a program, folder or internet address
and Windows will open that for you.",
RunFileDialogFlags.CalcDirectory);
}