I my program I need to capture when the Print Screen key is pressed down but it is not working (however it works with other keys).
I guess this has something to do with windows hijacking my authority and since im still new at this I'd love to know how I can get around this issue.
Here's my current code:
namespace Boom_Screenshot_
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
//SETTINGS
Key TRIGGER_KEY = Key.PrintScreen;
public Window1()
{
InitializeComponent();
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == TRIGGER_KEY)
{
MessageBox.Show("'PrintScreen' was pressed.");
}
}
}
}
I have an answer for you that I found here (I don't speak Chinese so don't ask me what it says :). You have to set a hook. He provides a wrapper class. I repeat some code here without the Chinese characters. RegisterHotKey.cs ...
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TestKeydown
{
public class RegisterHotKeyClass
{
private IntPtr m_WindowHandle = IntPtr.Zero;
private MODKEY m_ModKey = MODKEY.MOD_CONTROL;
private Keys m_Keys = Keys.A;
private int m_WParam = 10000;
private bool Star = false;
private HotKeyWndProc m_HotKeyWnd = new HotKeyWndProc();
public IntPtr WindowHandle
{
get { return m_WindowHandle; }
set { if (Star)return; m_WindowHandle = value; }
}
public MODKEY ModKey
{
get { return m_ModKey; }
set { if (Star)return; m_ModKey = value; }
}
public Keys Keys
{
get { return m_Keys; }
set { if (Star)return; m_Keys = value; }
}
public int WParam
{
get { return m_WParam; }
set { if (Star)return; m_WParam = value; }
}
public void StarHotKey()
{
if (m_WindowHandle != IntPtr.Zero)
{
if (!RegisterHotKey(m_WindowHandle, m_WParam, m_ModKey, m_Keys))
{
throw new Exception("");
}
try
{
m_HotKeyWnd.m_HotKeyPass = new HotKeyPass(KeyPass);
m_HotKeyWnd.m_WParam = m_WParam;
m_HotKeyWnd.AssignHandle(m_WindowHandle);
Star = true;
}
catch
{
StopHotKey();
}
}
}
private void KeyPass()
{
if (HotKey != null) HotKey();
}
public void StopHotKey()
{
if (Star)
{
if (!UnregisterHotKey(m_WindowHandle, m_WParam))
{
throw new Exception("");
}
Star = false;
m_HotKeyWnd.ReleaseHandle();
}
}
public delegate void HotKeyPass();
public event HotKeyPass HotKey;
private class HotKeyWndProc : NativeWindow
{
public int m_WParam = 10000;
public HotKeyPass m_HotKeyPass;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312 && m.WParam.ToInt32() == m_WParam)
{
if (m_HotKeyPass != null) m_HotKeyPass.Invoke();
}
base.WndProc(ref m);
}
}
public enum MODKEY
{
MOD_ALT = 0x0001,
MOD_CONTROL = 0x0002,
MOD_SHIFT = 0x0004,
MOD_WIN = 0x0008,
}
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr wnd, int id, MODKEY mode, Keys vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr wnd, int id);
}
}
Calling code in a Form ...
private RegisterHotKeyClass _RegisKey = new RegisterHotKeyClass();
void _Regis_HotKey()
{
MessageBox.Show("ok");
}
private void Form1_Load(object sender, EventArgs e)
{
_RegisKey.Keys = Keys.PrintScreen;
_RegisKey.ModKey = 0;
_RegisKey.WindowHandle = this.Handle;
_RegisKey.HotKey += new RegisterHotKeyClass.HotKeyPass(_Regis_HotKey);
_RegisKey.StarHotKey();
}
Below is my pure WPF solution.
We can achieve this in xaml by using NavigationCommands (Namespace: System.Window.Input) class which provides a standard set of navigation commands (e.g. NextPage, PreviousPage, Refresh, Search etc.)
Implementation Approach:
So we can call any custom code to execute on application refresh using NavigationCommands.Refresh as
<UserControl.CommandBindings>
<CommandBinding Command='NavigationCommands.Refresh'
Executed="ApplicationRefresh_Executed">
</CommandBinding>
</UserControl.CommandBindings>
Now in code behind class of UserControl we can define method as
private void ApplicationRefresh_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Implementation goes here.
}
Related
Is it possible to determine the pressed letter key depending on the layout?
Here is code (class):
class GlobalKeyboardHookEventArgs : HandledEventArgs
{
public GlobalKeyboardHook.KeyboardState KeyboardState { get; private set; }
public GlobalKeyboardHook.LowLevelKeyboardInputEvent KeyboardData { get; private set; }
public GlobalKeyboardHookEventArgs(
GlobalKeyboardHook.LowLevelKeyboardInputEvent keyboardData,
GlobalKeyboardHook.KeyboardState keyboardState)
{
KeyboardData = keyboardData;
KeyboardState = keyboardState;
}
}
//Based on https://gist.github.com/Stasonix
class GlobalKeyboardHook : IDisposable
{
public event EventHandler<GlobalKeyboardHookEventArgs> KeyboardPressed;
public GlobalKeyboardHook()
{
_windowsHookHandle = IntPtr.Zero;
_user32LibraryHandle = IntPtr.Zero;
_hookProc = LowLevelKeyboardProc; // we must keep alive _hookProc, because GC is not aware about SetWindowsHookEx behaviour.
_user32LibraryHandle = LoadLibrary("User32");
if (_user32LibraryHandle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode, $"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
.............
and call:
private void OnKeyPressed(object sender, GlobalKeyboardHookEventArgs e)
{
KeysConverter kc = new KeysConverter();
if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown)
{
GrabbedKeys += kc.ConvertToString(e.KeyboardData.VirtualCode);
return;
}
if (e.KeyboardData.VirtualCode != GlobalKeyboardHook.VkSnapshot)
return;
}
Its work fine, if I press on keyboard 's' my programm stored 's', but how I can make same for russian keyboard layout? If keyboard layout is ru-RU, I press 's' and my app stored 'ы'?
I've written a simple auto clicker using MouseKeyHook.
The reason I use MouseKeyHook is to detect global left clicks throughout Windows OS.
Although, when I run the .exe, the software lags on the click and after a while I can't seem to hit the 'X' button anymore and the application crashed my windows or slows down everything.
I am making this software to test our game, but this is not really helping :P
The code for the software can be found below:
using Gma.System.MouseKeyHook;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Rapid_Fire
{
public partial class Form1 : Form
{
#region structs
/// <summary>
/// Structure for SendInput function holding relevant mouse coordinates and information
/// </summary>
public struct INPUT
{
public uint type;
public MOUSEINPUT mi;
};
/// <summary>
/// Structure for SendInput function holding coordinates of the click and other information
/// </summary>
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
};
#endregion
// Constants for use in SendInput and mouse_event
public const int INPUT_MOUSE = 0x0000;
public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
public const int MOUSEEVENTF_LEFTUP = 0x0004;
private const int INTERVAL = 10;
private bool m_fire = false;
private bool m_close = false;
private int m_counter = INTERVAL;
private INPUT m_input = new INPUT();
private IKeyboardMouseEvents m_GlobalHook;
public Form1()
{
InitializeComponent();
Subscribe();
InitAutoClick();
this.FormClosed += new FormClosedEventHandler(formClosed);
}
private void Subscribe()
{
m_GlobalHook = Hook.GlobalEvents();
m_GlobalHook.KeyPress += GlobalHookKeyPress;
m_GlobalHook.MouseDownExt += GlobalHookMouseDownExt;
}
private void GlobalHookKeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 'q') m_fire = false;
}
private void GlobalHookMouseDownExt(object sender, MouseEventExtArgs e)
{
m_fire = true;
RapidFire();
}
private void InitAutoClick()
{
m_input.type = INPUT_MOUSE;
m_input.mi.dx = 0;
m_input.mi.dy = 0;
m_input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
m_input.mi.dwExtraInfo = IntPtr.Zero;
m_input.mi.mouseData = 0;
m_input.mi.time = 0;
}
private void RapidFire()
{
while (m_fire && !m_close)
{
if (m_counter <= 0)
{
// ClickLeftMouseButtonSendInput();
m_counter = INTERVAL;
}
m_counter--;
}
}
private void ClickLeftMouseButtonSendInput()
{
// Send a left click down followed by a left click up to simulate a full left click
SendInput(1, ref m_input, Marshal.SizeOf(m_input));
m_input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, ref m_input, Marshal.SizeOf(m_input));
}
private void formClosed(object sender, FormClosedEventArgs e)
{
m_fire = false;
m_close = true;
Unsubscribe();
}
public void Unsubscribe()
{
m_GlobalHook.MouseDownExt -= GlobalHookMouseDownExt;
m_GlobalHook.KeyPress -= GlobalHookKeyPress;
m_GlobalHook.Dispose();
}
}
}
Fixed the script by doing it another way. Turns out I had to attach it to a left mouse button down event :D
Here the script is:
using Gma.System.MouseKeyHook;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Rapid_Fire
{
public partial class Form1 : Form
{
[DllImport("user32.dll", SetLastError = true)]
public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize);
#region structs
/// <summary>
/// Structure for SendInput function holding relevant mouse coordinates and information
/// </summary>
public struct INPUT
{
public uint type;
public MOUSEINPUT mi;
};
/// <summary>
/// Structure for SendInput function holding coordinates of the click and other information
/// </summary>
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
};
#endregion
public const int INPUT_MOUSE = 0x0000;
public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
public const int MOUSEEVENTF_LEFTUP = 0x0004;
private const int TIMES_CLICK_FIRE = 25;
private bool m_fire = false;
private INPUT m_input = new INPUT();
private IKeyboardMouseEvents m_Events;
public Form1()
{
InitializeComponent();
SubscribeGlobal();
InitAutoClick();
this.FormClosed += new FormClosedEventHandler(formClosed);
}
private void SubscribeGlobal()
{
Unsubscribe();
Subscribe(Hook.GlobalEvents());
}
private void Subscribe(IKeyboardMouseEvents events)
{
m_Events = events;
m_Events.MouseUp += OnMouseUp;
m_Events.MouseDown += OnMouseDown;
}
private void InitAutoClick()
{
m_input.type = INPUT_MOUSE;
m_input.mi.dx = 0;
m_input.mi.dy = 0;
m_input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
m_input.mi.dwExtraInfo = IntPtr.Zero;
m_input.mi.mouseData = 0;
m_input.mi.time = 0;
}
private void Log(string text)
{
if (IsDisposed) return;
Console.WriteLine(text);
}
private void OnMouseDown(object sender, MouseEventArgs e)
{
m_fire = true;
Thread thread = new Thread(RapidFire);
thread.Start();
}
private void RapidFire()
{
while (m_fire)
{
for (; ; )
{
ClickLeftMouseButtonSendInput();
}
}
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
m_fire = false;
}
private void ClickLeftMouseButtonSendInput()
{
SendInput(1, ref m_input, Marshal.SizeOf(m_input));
m_input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, ref m_input, Marshal.SizeOf(m_input));
}
private void formClosed(object sender, FormClosedEventArgs e)
{
Unsubscribe();
}
private void Unsubscribe()
{
if (m_Events == null) return;
m_Events.MouseUp -= OnMouseUp;
m_Events.MouseDown -= OnMouseDown;
m_Events.Dispose();
m_Events = null;
}
}
}
I trying to allow people to write to NFC tags using my app, so that my app gets launched with a custom parameter. I want to be able to reprogram NFC tags which already have data on them.
I am using the following code but the problem is, that WP always recognizes the action which is already on the NFC tag and interrupts because it wants to launch the NFC tag action which was written anytime before.
How can I tell the OS to stop triggering the action of the tag so that I can immediately rewrite it?
public enum NfcHelperState
{
Initializing,
Waiting,
Ready,
Writing,
Finished,
Error,
NoDeviceFound
}
public class NfcHelper
{
private NfcHelperState _state = NfcHelperState.Initializing;
public NfcHelperState State
{
get { return _state; }
}
private ProximityDevice _nfcDevice;
private long _subscriptionId;
public NfcHelper()
{
Init();
}
public void Init()
{
UpdateState();
_nfcDevice = ProximityDevice.GetDefault();
if (_nfcDevice == null)
{
UpdateState(NfcHelperState.NoDeviceFound);
return;
}
UpdateState(NfcHelperState.Waiting);
}
private void UpdateState(NfcHelperState? state = null)
{
if (state.HasValue)
{
_state = state.Value;
}
if (OnStatusMessageChanged != null)
{
OnStatusMessageChanged(this, _state);
}
}
public void WriteToTag()
{
UpdateState(NfcHelperState.Ready);
_subscriptionId = _nfcDevice.SubscribeForMessage("WriteableTag", WriteableTagDetected);
}
private void WriteableTagDetected(ProximityDevice sender, ProximityMessage message)
{
UpdateState(NfcHelperState.Writing);
try
{
var str = "action=my_custom_action";
str += "\tWindowsPhone\t";
str += CurrentApp.AppId;
_nfcDevice.PublishBinaryMessage("LaunchApp:WriteTag", GetBufferFromString(str),
WriteToTagComplete);
}
catch (Exception e)
{
UpdateState(NfcHelperState.Error);
StopWaitingForTag();
}
}
private void WriteToTagComplete(ProximityDevice sender, long messageId)
{
sender.StopPublishingMessage(messageId);
UpdateState(NfcHelperState.Finished);
StopWaitingForTag();
}
private void StopWaitingForTag()
{
_nfcDevice.StopSubscribingForMessage(_subscriptionId);
}
private static IBuffer GetBufferFromString(string str)
{
using (var dw = new DataWriter())
{
dw.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf16LE;
dw.WriteString(str);
return dw.DetachBuffer();
}
}
public delegate void NfcStatusMessageChangedHandler(object myObject, NfcHelperState newState);
public event NfcStatusMessageChangedHandler OnStatusMessageChanged;
}
WriteToTag is called when a button in my app is tapped and the app waits for a writable tag. If a writable tag is recognized, WriteableTagDetected gets called and immediately starts the writing process. However, this is interrupted by the WP dialog which asks whether to perform the NFC action or not. After writing, WriteToTagComplete should be called, where StopWaitingForTag gets called and ends the write process.
I hope you guys can help me :)
Turns out I thought the wrong way. I didn't need to wait for a tag to arrive in order to rewrite it. In fact, there's no need to do _nfcDevice.SubscribeForMessage("WriteableTag", WriteableTagDetected); before writing. Just start using PublishBinaryMessage and it will write to the tag once it arrives at the device.
My final code looks like the following:
public enum NfcHelperState
{
Initializing,
Ready,
WaitingForWriting,
FinishedWriting,
ErrorWriting,
NoDeviceFound
}
public class NfcHelper
{
private NfcHelperState _state = NfcHelperState.Initializing;
public NfcHelperState State
{
get { return _state; }
}
private ProximityDevice _nfcDevice;
private long? _writingMessageId;
public NfcHelper()
{
Init();
}
public void Init()
{
UpdateState();
_nfcDevice = ProximityDevice.GetDefault();
if (_nfcDevice == null)
{
UpdateState(NfcHelperState.NoDeviceFound);
return;
}
UpdateState(NfcHelperState.Ready);
}
private void UpdateState(NfcHelperState? state = null)
{
if (state.HasValue)
{
_state = state.Value;
}
if (OnStatusMessageChanged != null)
{
OnStatusMessageChanged(this, _state);
}
}
public void WriteToTag()
{
StopWritingMessage();
UpdateState(NfcHelperState.WaitingForWriting);
try
{
var str = new StringBuilder();
str.Append("action=my_custom_action");
str.Append("\tWindowsPhone\t{");
str.Append(CurrentApp.AppId);
str.Append("}");
_writingMessageId = _nfcDevice.PublishBinaryMessage("LaunchApp:WriteTag", GetBufferFromString(str.ToString()),
WriteToTagComplete);
}
catch
{
UpdateState(NfcHelperState.ErrorWriting);
StopWritingMessage();
}
}
private void WriteToTagComplete(ProximityDevice sender, long messageId)
{
UpdateState(NfcHelperState.FinishedWriting);
StopWritingMessage();
}
private void StopWritingMessage()
{
if (_writingMessageId.HasValue)
{
_nfcDevice.StopPublishingMessage(_writingMessageId.Value);
_writingMessageId = null;
}
}
private static IBuffer GetBufferFromString(string str)
{
using (var dw = new DataWriter())
{
dw.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf16LE;
dw.WriteString(str);
return dw.DetachBuffer();
}
}
public delegate void NfcStatusMessageChangedHandler(object myObject, NfcHelperState newState);
public event NfcStatusMessageChangedHandler OnStatusMessageChanged;
}
I have an desktop console application created in visual studio 2010.How do i convert it to windows service?. basically in debug mode i want it as normal app , but in release mode i want a service build output
You can do it this way:
namespace Program
{
static class Program
{
public static bool Stopped = false;
[STAThread]
static void Main(string[] args)
{
Interactive.Initialize();
Interactive.OnStopped += new Interactive.StopedDelegate(OnStopped);
Interactive.Title = Path.GetFileNameWithoutExtension(
Assembly.GetExecutingAssembly().Location);
if (args.Length == 0) Interactive.Run(RunProc);
else if (args[0] == "-svc") ServiceBase.Run(new Service());
}
public static void RunProc() { yourConsoleMain(); }
public static void OnStopped() { Stopped = true; exitFromMain(); }
}
public class Service : ServiceBase
{
public static string Name = Path.GetFileNameWithoutExtension(
Assembly.GetExecutingAssembly().Location);
public static string CmdLineSwitch = "-svc";
public static ServiceStartMode StartMode = ServiceStartMode.Automatic;
public static bool DesktopInteract = true;
public bool Stopped = false;
public Service() { ServiceName = Name; }
public void Start() { OnStart(null); }
protected override void OnStart(string[] args)
{
System.Diagnostics.EventLog.WriteEntry(
ServiceName, ServiceName + " service started.");
Thread thread = new Thread(MainThread);
thread.Start();
}
protected override void OnStop()
{
System.Diagnostics.EventLog.WriteEntry(
ServiceName, ServiceName + " service stopped.");
Stopped = true;
Application.Exit();
}
private void MainThread()
{
Interactive.Run(Program.RunProc);
if (!Stopped) Stop();
}
}
}
Let me explain this... Basically, in Main you define that your program starts as a service if it is started with argument '-svc'.
Put in RunProc() what you normally do in main(), and in OnStopped() event handler some code that will cause main() to exit.
Then, override ServiceBase and perform some basic start/stop service.
In Windows 7 and later you must explicitly define that your service can interact with desktop if you want to see some output. But there is another problem, console window cannot be shown. So I created this console simulator which can write and also read input.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
namespace ProgramIO.Control
{
public delegate void WriteDelegate(string value, int x, int y);
public delegate void ReadDelegate(out string value, bool readLine);
public delegate void EnableInputDelegate(bool enable);
public partial class InteractiveForm : Form
{
private delegate void ClearInputBufferDelegate();
public enum EIOOperation { None = 0, Write, Read }
private EventWaitHandle eventInvoke =
new EventWaitHandle(false, EventResetMode.AutoReset);
private EventWaitHandle eventInput =
new EventWaitHandle(false, EventResetMode.AutoReset);
private bool readLine = false;
private string inputBuffer = "";
private int inputPosition = 0;
private int inputBufferPosition = 0;
private EIOOperation IOOperation;
private int bufferSize = 0x10000;
private bool CaretShown = false;
private delegate object DoInvokeDelegate(Delegate method, params object[] args);
private delegate void SetTitleDelegate(string value);
private delegate void SetForegroundcolorDelegate(Color value);
public string Title {
get { return Text; }
set {
if (InvokeRequired) InvokeEx(
(SetTitleDelegate)delegate(string title) { Text = title; },
1000, new object[] { value });
else Text = value; }}
public Color ForegroundColor {
get { return ForeColor; }
set {
if (InvokeRequired) InvokeEx(
(SetForegroundcolorDelegate)delegate(Color color) { ForeColor = color; },
1000, new object[] { value });
else ForeColor = value; }}
public InteractiveForm()
{
InitializeComponent();
DoubleBuffered = true;
}
#region Asynchronous Methods
private bool InvokeEx(Delegate method, int timeout, params object[] args)
{
BeginInvoke((DoInvokeDelegate)DoInvoke, new object[] { method, args });
if (eventInvoke.WaitOne(timeout)) return true;
else return false;
}
private void EnableInput(bool enable)
{
if (InvokeRequired)
InvokeEx((EnableInputDelegate)DoEnableInput, 1000, new object[] { enable });
else DoEnableInput(enable);
}
private void ClearInputBuffer()
{
if (InvokeRequired)
InvokeEx((ClearInputBufferDelegate)DoClearInputBuffer, 1000, new object[0]);
else DoClearInputBuffer();
}
public void Write(string value, int x = -1, int y = -1)
{
lock (this) {
IOOperation = EIOOperation.Write;
if (InvokeRequired)
InvokeEx((WriteDelegate)DoWrite, 1000, new object[] { value, x, y });
else DoWrite(value, x, y);
IOOperation = EIOOperation.None; }
}
public string Read(bool readLine)
{
lock (this) {
EnableInput(true);
IOOperation = EIOOperation.Read; this.readLine = readLine; string value = "";
ClearInputBuffer(); eventInput.WaitOne();
object[] args = new object[] { value, readLine };
if (InvokeRequired) {
InvokeEx((ReadDelegate)DoRead, 1000, args); value = (string) args[0]; }
else DoRead(out value, readLine);
//inputPosition = textBox.Text.Length; inputBuffer = "";
ClearInputBuffer();
IOOperation = EIOOperation.None;
EnableInput(false);
return value;
}
}
#endregion //Asynchronous Methods
#region Synchronous Methods
protected override void OnShown(EventArgs e) { base.OnShown(e); textBox.Focus(); }
public object DoInvoke(Delegate method, params object[] args)
{
object obj = method.DynamicInvoke(args);
eventInvoke.Set();
return obj;
}
private void CorrectSelection()
{
if (textBox.SelectionStart < inputPosition) {
if (textBox.SelectionLength > (inputPosition - textBox.SelectionStart))
textBox.SelectionLength -= inputPosition - textBox.SelectionStart;
else textBox.SelectionLength = 0;
textBox.SelectionStart = inputPosition; }
}
protected void DoClearInputBuffer()
{
inputPosition = textBox.Text.Length; inputBuffer = "";
}
protected void DoEnableInput(bool enable)
{
if (enable) { textBox.ReadOnly = false; textBox.SetCaret(true); }
else { textBox.ReadOnly = true; textBox.SetCaret(false); }
}
protected void DoWrite(string value, int x, int y)
{
string[] lines = textBox.Text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
string[] addLines = new string[0];
if (y == -1) y = lines.Length - 1;
if (lines.Length - 1 < y) addLines = new string[y - lines.Length - 1];
if (y < lines.Length) {
if (x == -1) x = lines[y].Length;
if (lines[y].Length < x)
lines[y] += new String(' ', x - lines[y].Length) + value;
else
lines[y] = lines[y].Substring(0, x) + value +
((x + value.Length) < lines[y].Length ?
lines[y].Substring(x + value.Length) : ""); }
else {
y -= lines.Length;
if (x == -1) x = addLines[y].Length;
addLines[y] += new String(' ', x - addLines[y].Length) + value; }
textBox.Text = (string.Join("\r\n", lines) +
(addLines.Length > 0 ? "\r\n" : "") + string.Join("\r\n", addLines));
textBox.Select(textBox.Text.Length, 0); textBox.ScrollToCaret();
inputBuffer = "";
}
protected void DoRead(out string value, bool readLine)
{
value = "";
if (readLine) {
int count = inputBuffer.IndexOf("\r\n");
if (count > 0) { value = inputBuffer.Substring(0, count); }}
else if (inputBuffer.Length > 0) {
value = inputBuffer.Substring(0, 1); }
inputBuffer = "";
}
private void textBox_TextChanged(object sender, EventArgs e)
{
if (IOOperation == EIOOperation.Read) {
inputBuffer = textBox.Text.Substring(inputPosition);
if (!readLine || inputBuffer.Contains("\r\n")) eventInput.Set(); }
if (textBox.Text.Length > bufferSize) { textBox.Text =
textBox.Text.Substring(textBox.Text.Length - bufferSize, bufferSize);
textBox.Select(textBox.Text.Length, 0); textBox.ScrollToCaret(); }
}
private void textBox_KeyDown(object sender, KeyEventArgs e)
{
if (IOOperation != EIOOperation.Read ||
(e.KeyCode == Keys.Back && inputBuffer.Length == 0))
e.SuppressKeyPress = true;
}
private void textBox_MouseUp(object sender, MouseEventArgs e)
{
CorrectSelection();
}
private void textBox_KeyUp(object sender, KeyEventArgs e)
{
if (!(IOOperation == EIOOperation.Read) ||
((e.KeyCode == Keys.Left || e.KeyCode == Keys.Up) &&
textBox.SelectionStart < inputPosition))
CorrectSelection();
}
private void InteractiveForm_FormClosing(object sender, FormClosingEventArgs e)
{
eventInput.Set();
lock (this) { }
}
#endregion //Synchronous Methods
}
public class InteractiveWindow : TextBox
{
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
private delegate void SetCaretDelegate(bool visible);
private const int WM_SETFOCUS = 0x0007;
private bool CaretVisible = true;
public void SetCaret(bool visible)
{
if (InvokeRequired) Invoke((SetCaretDelegate)DoSetCaret, new object[] { visible });
else DoSetCaret(visible);
}
private void DoSetCaret(bool visible)
{
if (CaretVisible != visible)
{
CaretVisible = visible;
if (CaretVisible) ShowCaret(Handle);
else HideCaret(Handle);
}
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_SETFOCUS)
{
if (CaretVisible) { ShowCaret(Handle); }
else HideCaret(Handle);
}
}
}
}
namespace ProgramIO
{
using ProgramIO.Control;
public static class Interactive
{
public delegate void StopedDelegate();
public delegate void RunDelegate();
public static bool Initialized = false;
private static InteractiveForm frmIO = null;
private static Thread IOThread = null;
private static EventWaitHandle EventStarted =
new EventWaitHandle(false, EventResetMode.AutoReset);
public static string Title {
get { return frmIO.Title; }
set { frmIO.Title = value; } }
public static Color ForegroundColor {
get {return frmIO.ForeColor; }
set { frmIO.ForeColor = value; } }
public static event StopedDelegate OnStopped = null;
private static void form_Show(object sender, EventArgs e)
{
frmIO = sender as InteractiveForm;
EventStarted.Set();
}
private static void form_FormClosed(object sender, FormClosedEventArgs e)
{
lock (frmIO) {
frmIO = null;
Application.Exit(); }
}
public static void Initialize()
{
IOThread = new Thread(IOThreadProc);
IOThread.Name = "Interactive Thread"; IOThread.Start();
EventStarted.WaitOne();
Initialized = true;
}
public static void Run(RunDelegate runProc = null)
{
if (!Initialized) Initialize();
if (runProc != null) runProc();
Application.Run();
if (OnStopped != null) OnStopped();
}
public static void IOThreadProc()
{
InteractiveForm form = new InteractiveForm();
form.Shown += new EventHandler(form_Show);
form.FormClosed += new FormClosedEventHandler(form_FormClosed);
Application.Run(form);
}
public static void Write(string value, int x = -1, int y = -1)
{
if (frmIO != null) lock (frmIO) { frmIO.Write(value, x, y); }
}
public static void WriteLine(string value)
{
if (frmIO != null) lock (frmIO) {
Interactive.Write(value); Interactive.Write("\r\n"); }
}
public static int Read()
{
if (frmIO != null) lock (frmIO) {
string input = frmIO.Read(false);
if (input.Length > 0) return input[0]; }
return 0;
}
public static string ReadLine()
{
if (frmIO != null) lock (frmIO) { return frmIO.Read(true); }
else return "";
}
}
}
This last class, Interactive, actually serve as invoker for asynchronous methods, and it is used in Main() at the beginning.
You can skip this whole second section of code if you don't want to see console window when program is run as a windows service.
I have also created an Installer class for this, but it would be just to much code on this page.
EDIT: This InteractiveForm is actually a form with designer class, but very simple, consisting only of Form and EditBox inside filling its area.
Basicallly you need 3 projects in your solution:
Application itself
WinService for production
Console Application for test purposes
So your application must have some kind of Start() method with e.g. infinite loop that does all work and maybe Stop() method to stop processing.
Winservice project must contain class derived from ServiceBase, it'l have OnStartmethod that calls your application's Start and OnStop that calls application's Stop method.
Next, in console application you do pretty much same - calling Start method in console's entry point.
So far for debug you run your console app, and for release you publish your winservice project
Winservice class might look like:
upd
Winservice codez:
public class MyWinService : ServiceBase
{
IMyApplicationService _myApplicationService;
//constructor - resolve dependencies here
public MyWinService()
{
_myApplicationService = new MyApplicationService();
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
try
{
_myApplicationService.Start();
}
catch (Exception exception)
{
//log exception
}
}
protected override void OnStop()
{
base.OnStop();
try
{
_myApplicationService.Stop();
}
catch (Exception exception)
{
//log exception
}
}
}
Application service:
public class MyApplicationService : IMyApplicationService
{
public MyApplicationService()
{
//some initializations
}
public Start()
{
//do work here
}
public Stop()
{
//...
}
}
I created this simple sample Form with the close button.
Everything is working as expected when NOT using the Interop.WMPLib.dll
I've seen other applications using this without problems but why isn't the Form process closed when I just add the line:
SoundPlayer myPlayer = new SoundPlayer();
and of course dispose it:
if (myPlayer != null)
{
myPlayer.Dispose();
myPlayer = null;
}
The Form closes but the debugger VS2008 is still active. The Form project and the dll are still active.
If you send me an email to xdasleepsense#gmail.com, I can send you the zipped project.
Below is the class for the dll:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using WMPLib;
namespace WindowsMobile.Utilities
{
public delegate void SoundPlayerStateChanged(SoundPlayer sender, SoundPlayerState newState);
public enum SoundPlayerState
{
Stopped,
Playing,
Paused,
}
public class SoundPlayer : IDisposable
{
[DllImport("coredll")]
public extern static int waveOutSetVolume(int hwo, uint dwVolume);
[DllImport("coredll")]
public extern static int waveOutGetVolume(int hwo, out uint dwVolume);
WindowsMediaPlayer myPlayer = new WindowsMediaPlayer();
public SoundPlayer()
{
myPlayer.uiMode = "invisible";
myPlayer.settings.volume = 100;
}
string mySoundLocation = string.Empty;
public string SoundLocation
{
get { return mySoundLocation; }
set { mySoundLocation = value; }
}
public void Pause()
{
myPlayer.controls.pause();
}
public void PlayLooping()
{
Stop();
myPlayer.URL = mySoundLocation;
myPlayer.settings.setMode("loop", true);
}
public int Volume
{
get { return myPlayer.settings.volume; }
set { myPlayer.settings.volume = value; }
}
public void Play()
{
Stop();
myPlayer.URL = mySoundLocation;
myPlayer.controls.play();
}
public void Stop()
{
myPlayer.controls.stop();
myPlayer.close();
}
#region IDisposable Members
public void Dispose()
{
try
{
Stop();
}
catch (Exception)
{
}
// need this otherwise the process won't exit?!
try
{
int ret = Marshal.FinalReleaseComObject(myPlayer);
}
catch (Exception)
{
}
myPlayer = null;
GC.Collect();
}
#endregion
}
}
A MessageBox or Below solved it. Thx.
public void Dispose()
{
try
{
Stop();
}
catch (Exception)
{
}
// need this otherwise the process won't exit?!
try
{
int ret = Marshal.FinalReleaseComObject(myPlayer);
}
catch (Exception)
{
}
myPlayer = null;
GC.Collect();
//If you don't do this, it will not quit
//http://www.eggheadcafe.com/software/aspnet/31363254/media-player-freezing-app.aspx
for (int s = 0; s < 100; s++)
{
Application.DoEvents();
Thread.Sleep(1);
}
GC.WaitForPendingFinalizers();
//MessageBox.Show("Application Exiting");
}
I just found from this link: http://software.itags.org/pocketpc-developer/163455/
a hint...
So I added a messagebox:
public void Dispose()
{
try
{
Stop();
}
catch (Exception)
{
}
// need this otherwise the process won't exit?!
try
{
int ret = Marshal.FinalReleaseComObject(myPlayer);
}
catch (Exception)
{
}
myPlayer = null;
GC.Collect();
**MessageBox.Show("Application Exiting");**
}
once I click OK, the debugger also thinks it's finished. Of course I can't have the user click OK.
So what's happening here?