Enable only one instance of WPF application - wpf

I have WPF allocation and I want to be able to open only one instance of my application.
So i have this 2 classes:
public sealed class SingleInstance
{
public static bool AlreadyRunning()
{
bool running = false;
try
{
// Getting collection of process
Process currentProcess = Process.GetCurrentProcess();
// Check with other process already running
foreach (var p in Process.GetProcesses())
{
if (p.Id != currentProcess.Id) // Check running process
{
if (p.ProcessName.Equals(currentProcess.ProcessName) == true)
{
running = true;
IntPtr hFound = p.MainWindowHandle;
if (User32API.IsIconic(hFound)) // If application is in ICONIC mode then
User32API.ShowWindow(hFound, User32API.SW_RESTORE);
User32API.SetForegroundWindow(hFound); // Activate the window, if process is already running
break;
}
}
}
}
catch { }
return running;
}
}
And:
public class User32API
{
[DllImport("User32.dll")]
public static extern bool IsIconic(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public const int SW_RESTORE = 9;
}
App.xaml:
protected override void OnStartup(StartupEventArgs e)
{
if (SingleInstance.AlreadyRunning())
App.Current.Shutdown(); // Just shutdown the current application,if any instance found.
base.OnStartup(e);
}
So with this solution only one instance is allow but in case the user try to open another instance i can see that in the task bar i have new icon of my application, this icon automatically close when the mouse is over but I want to prevent this icon to be show so I remove this from App.xaml:
StartupUri="MainWindow.xaml"
And now my application not started (probably started but i cannot see it).
Any chance to achieve what I want ?
I need to call MainWindow but I don't know from where
UPDATE
So I try this approach:
protected override void OnStartup(StartupEventArgs e)
{
if (SingleInstance.AlreadyRunning())
App.Current.Shutdown(); // Just shutdown the current application,if any instance found.
base.OnStartup(e);
new MainWindow().Show();
}
And still i can see the second (and third and so...) icons when the user try to open another instance

Related

How to open file from explorer into already instantiated window of the program?

I'm using WPF and have created a custom file type for the program. When a user double clicks the file in explorer to open it, or right clicks then clicks "open", my program starts up. However if the program is already opened, a new instance of the program is created instead of opening the file in the already opened instance of the program.
Right now i'm catching the file in App.xaml.cs with:
private void Application_Startup(object sender, StartupEventArgs e)
{
if (e.Args.Length == 1)
{
FileInfo file = new FileInfo(e.Args[0]);
if (file.Exists)
{
//OPEN FILE
}
}
}
However, this is when the program starts up with a command line argument. I do not want to instantiate a new window of the program. I want to open the file in the already existing instance (if it exist, otherwise, create a new instance of the program).
I also do no want to restrict the program to only be able to have one active instance. If user manually opens two instances of the program he should be able to do that. But when opening a file from explorer the file should be opened in the last active instance of the program
I got it to work with code from: https://www.codeproject.com/Articles/1191863/Opening-a-specific-file-format-with-a-single-insta
add the .cs files "MessageHelper" and "SingleInstanceHelper" to project.
add this to your Main Window's code-behind:
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle messages...
if (msg == MessageHelper.WM_COPYDATA)
{
//Reconstruct copy data structure
COPYDATASTRUCT _dataStruct = Marshal.PtrToStructure<COPYDATASTRUCT>(lParam);
//Get the messag (file name we sent from the other instance)
string _strMsg = Marshal.PtrToStringUni(_dataStruct.lpData, _dataStruct.cbData / 2);
//deal with the file here (_strMsg is the filepath)
//for my application: FileManager.OpenInverterFile(_strMsg);
}
return IntPtr.Zero;
}
Then add this to App.xaml.cs (code-behind for App)
private void Application_Startup(object sender, StartupEventArgs e)
{
string[] args = e.Args;
if (SingleInstanceHelper.CheckInstancesFromRunningProcesses())
{
if (args.Length > 0)
{
//send argument to already opened application and close this instance
Process _otherInstance = SingleInstanceHelper.GetAlreadyRunningInstance();
MessageHelper.SendDataMessage(_otherInstance, args[0]);
Shutdown();
}
}
else if (args.Length == 1)
{
//open file in this instance
FileInfo file = new FileInfo(e.Args[0]);
if (file.Exists)
{
//deal with the file here (file.FullName)
}
}
}

WPF equivilent of unity 3D's Screen.lockCursor

I haven't used Unity 3D but I gather you can use Screen.lockCursor to take control of the mouse for FPS games. Is this possible in WPF/Win32?
Obviously you have to release it when exiting or in the event of a crash
Thanks
I found the answer spread across a whole bunch of links, so
(1) Set a captureMouse flag, press once to go into this mode, again to come out,
hide the cursor while you are in there
bool captureMouse = false;
private void viewport3D1_MouseDown(object sender, MouseButtonEventArgs e)
{
if (!captureMouse)
{
captureMouse = true;
Mouse.OverrideCursor = Cursors.None;
}
else
{
Mouse.OverrideCursor = null;
captureMouse = false;
}
}
(2) While you're in this mode constantly put the mouse back to the middle of the window
private void theWindow_MouseMove(object sender, MouseEventArgs e)
{
if (!captureMouse)
return;
Point windowPoint = WpfToRealPixels(theWindow, new Point(500, 500));
NativeMethods.SetCursorPos((int)windowPoint.X, (int)windowPoint.Y);
oldP = new Point(500, 500);
}
(3) Translate the co-ords
private Point WpfToRealPixels(Window w, Point p)
{
return theWindow.PointToScreen(p);
}
(4) To put the mouse back you'll need a native Win32 call
public partial class NativeMethods
{
[System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SetCursorPos")]
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool SetCursorPos(int X, int Y);
}
Hope that helps someone.

WPF Winforms Interop eating keystroke

I create a winform project with a single form with 4 textboxes and a button.
On button click, I perform the following:
Window1 w = new Window1();
ElementHost.EnableModelessKeyboardInterop(w);
w.Show();
Where window 1 is a Wpf window. Window1 has a single button on it and when that button is clicked the following occurs:
System.Windows.MessageBox.Show("HelloWOrld");
When you run the application the WinForm Form pops ups. If you hit tab it cycles through the 4 textboxes no problem. Then Click the button to open the WPF window. Click that button and popup the messagebox. Leave them open and then go back to the WinForm form you can no longer tab through the fields but you can type other characters. It appears as though the textboxes get the keystrokes but the form doesn't get them. I also get a system beep as though the model was getting the keystroke.
EDIT 9/9/2014 3:44PM
Hans responded in the comments and was correct. I tried describing a simpler case that would be easier for other people to reproduce that gave use the same symptoms. Our actual problem is that we have created a window base class that supports modal to parent capabilities. Here is the relevant code for our BaseWindow
public class BaseWindow: Window
{
[DllImport("user32.dll")]
static extern bool EnableWindow(IntPtr hWnd, bool bEnable);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
public void ShowModalToParent(Window frmParent, Action<bool?> callback = null)
{
IntPtr myHandle = (new System.Windows.Interop.WindowInteropHelper(this)).Handle;
EnableWindow(myHandle,
SetForegroundWindow(myHandle);
this.Closing += Window_Closing;
ShowInTaskbar = false;
Owner = frmParent; // Keep on top of parent
ClosedCallBack += callback ?? (p => { _modalDialogResult = p; });
var parentHandle = (new System.Windows.Interop.WindowInteropHelper(frmParent)).Handle;
EnableWindow(parentHandle, false); // Prevent events for parent
new ShowAndWaitHelper(this).ShowAndWait();
}
internal class ShowAndWaitHelper
{
private readonly Window _window;
private DispatcherFrame _dispatcherFrame;
internal ShowAndWaitHelper(Window window)
{
if (window == null)
{
throw new ArgumentNullException("panel");
}
this._window = window;
}
internal void ShowAndWait()
{
if (this._dispatcherFrame != null)
{
throw new InvalidOperationException("Cannot call ShowAndWait while waiting for a previous call to ShowAndWait to return.");
}
this._window.Closed += new EventHandler(this.OnPanelClosed);
_window.Show();
this._dispatcherFrame = new DispatcherFrame();
Dispatcher.PushFrame(this._dispatcherFrame);
}
private void OnPanelClosed(object source, EventArgs eventArgs)
{
if (this._dispatcherFrame == null)
{
return;
}
this._window.Closed -= new EventHandler(this.OnPanelClosed);
this._dispatcherFrame.Continue = false;
this._dispatcherFrame = null;
}
}
}
I'm sure this code was taken from a Blog/Forum post of some sort but am unable to find any reference to it in code. We want to keep the modal to parent but some how address the odd key press issue. To reproduce the issue replace the button_click in Window1 to call ShowModalToParent on a window that uses this as a base class.

How to turn off all touch input at application, window or control level?

Using c# for a wpf application, if in Windows 7 touch is enabled in the control panel, a user by default can 'write' on an InkCanvas with a finger. I want to disable that and force stylus input only.
I'd like to know how to do it more than one way if possible: first by disabling touch on the InkCanvas, second by disabling it for a particular window, and third by disabling it for the entire application. A bonus fourth would be knowing how to turn touch on or off system-wide.
I have tried UnregisterTouchWindow, and I have tried setting Stylus.SetIsTouchFeedbackEnabled to false for the InkCanvas, but neither has worked.
Further digging helped me put together the following as a way to toggle touch on/off system-wide. If anyone knows how to accomplish this in any of the other 3 ways, I'd still appreciate those answers.
The basic steps are to check the current registry status, change it if necessary (and then refresh the system to recognize the change), and make note of the initial state to restore if needed on program exit.
Thanks to the posters at these two links for the education.
public MainWindow(){
InitializeComponent();
RegistryKey regKey = Registry.CurrentUser;
regKey = regKey.OpenSubKey(#"Software\Microsoft\Wisp\Touch", true);
string currKey = regKey.GetValue("TouchGate").ToString();
if (currKey == "1")
{
regKey.SetValue("TouchGate", 0x00000000);
User32Utils.Notify_SettingChange();
UserConfig.TGate = "1";
}
regKey.Close();
...
}
public static class UserConfig {
public static string TGate { get; set; }
...
}
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e){
...
if (UserConfig.TGate == "1")
{
RegistryKey regKey = Registry.CurrentUser;
regKey = regKey.OpenSubKey(#"Software\Microsoft\Wisp\Touch", true);
regKey.SetValue("TouchGate", 0x00000001);
User32Utils.Notify_SettingChange();
regKey.Close();
}
}
//------------------User32Utils.cs
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace (...)
{
internal class User32Utils
{
#region USER32 Options
static IntPtr HWND_BROADCAST = new IntPtr(0xffffL);
static IntPtr WM_SETTINGCHANGE = new IntPtr(0x1a);
#endregion
#region STRUCT
enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0000,
SMTO_BLOCK = 0x0001,
SMTO_ABORTIFHUNG = 0x2,
SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
}
#endregion
#region Interop
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr SendMessageTimeout(IntPtr hWnd,
uint Msg,
UIntPtr wParam,
UIntPtr lParam,
SendMessageTimeoutFlags fuFlags,
uint uTimeout,
out UIntPtr lpdwResult);
#endregion
internal static void Notify_SettingChange()
{
UIntPtr result;
SendMessageTimeout(HWND_BROADCAST, (uint)WM_SETTINGCHANGE,
UIntPtr.Zero, UIntPtr.Zero,
SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out result);
}
}
}

Custom Message Box Advice

Well I'm using a Window as my custom message box with a couple of controls which are displayed/populated with text depending on which constructor is called.
I have a defined event, which is subscribed to via the original class, this fires once the button has been clicked.
However I can't see how to use this effectively, preferably I'd like to return a bool whether Yes or No was clicked, however obviously my code will carry on executing, hence the method which is subscibed to the button click. Below is some example code to make the issue clearer.
Message Box Window
public partial class CustomMessageBox : Window
{
public delegate void MessageBoxHandler(object sender, EventArgs e);
public event MessageBoxHandler MessageBoxEvent;
public CustomMessageBox()
{
InitializeComponent();
}
public CustomMessageBox(string message)
{
InitializeComponent();
this.txtdescription.Text = message;
}
public CustomMessageBox(string message, string title, string firstBtnText)
{
InitializeComponent();
this.lbltitle.Content = title;
this.txtdescription.Text = message;
this.btnstart.Content = firstBtnText;
}
}
public static class MessageBoxButtonClick
{
public static bool Yes { get; set; }
public static bool No { get; set; }
public static bool Cancel { get; set; }
}
Window Which Instantiates the MessageBox Window
private void StartProcess_Click(object sender, System.Windows.RoutedEventArgs e)
{
foreach (var result in results)
{
if(result.ToBeProcessed)
_validResults.Add(new ToBeProcessed(result.Uri, result.Links));
}
_msgbox = new CustomMessageBox("Each Uri's backlinks will now be collected from Yahoo and filtered, finally each link will be visited and parsed. The operation is undertaken in this manner to avoid temporary IP Blocks from Yahoo's servers.", "Just a FYI", "OK");
_msgbox.MessageBoxEvent += (MessageBoxHandler);
if (_msgBoxProceed)
{
_msgbox.Close();
Yahoo yahoo = new Yahoo();
yahoo.Status.Sending += (StatusChange);
//What I'd like to happen here is the code simply stop, like it does when calling a messagebox is winforms
//e.g.
// if(ProceedClicked == true)
// do stuff
// yahoo.ScrapeYahoo(_validResults[Cycle].Uri, _validResults[Cycle].LinkNumber);
//Cycle++;
}
else
{
_msgbox.Close();
}
}
private void MessageBoxHandler(object sender, EventArgs e)
{
if (MessageBoxButtonClick.Yes)
{
ProceedClicked = true;
}
else
{
ProceedClicked = false;
}
}
Hopefully that makes it clear enough, I can't put any execution code ie call a certain method due to using it multiple times throughout my application.
Very hard to understand what the problem exactly is. Also the code you wrote here, doesn't seemt to have any calls, that would actually show the CustomMessageBoxWindow.
But I'll take a stab at this...
First of all, am I right in guessing that in your main Window you want your code to wait at if(_msgBoxProceed) until the user actually presses a button in your CustomMessageBoxWindow (currently it just shows the message box and continues executing the next statements)?
If so then I'm guessing you are showing your message box window with the Show() method. Use ShowDialog() instead. That will cause code execution to stop, until the message box gets closed.
If you don't want to use a modal dialog then there are two options. Either use thread syncrhonization objects (eg AutoResetEvent) or set up a new event for when the message box closes and continue your code execution in the closed event handler (in StartProcess_Click the last line would be a call to _msgBox.Show() and everything from if(_msgBoxProceed) would be in the closed event handler).

Resources