Reputation: 4875
I have a WPF application that is started with no parameters or flags. In the App.xaml.cs
I added an OnStartUp
handler that attempts to do some IPC to another instance of the application IF it executed with parameters. For example, my main application might be started by simply executing mainApp
, which would load the main windows. Then I might later execute mainApp msg bob some_message
which would pass the condition in OnStartUp
and send "msg bob some_message" to the up and running application to handle in its WndProc
override.
Code in App.xaml.cs:
private void OnStartUp(object sedner, StartupEventArgs e)
{
Process localProcess = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName(localProcess.ProcessName))
{
if (process.Id != localProcess.Id)
{
NativeMethods.SendMessage(process.MainWindowHandle, NativeMethods.HWND_IPC, IntPtr.Zero, IntPtr.Zero);
Environment.Exit(0);
}
}
}
Code in main window codebehind:
public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr iParam, ref bool handled)
{
if (msg == NativeMethods.HWND_IPC)
{
MessageBox.Show("Message Received!");
}
return IntPtr.Zero;
}
internal class NativeMethods
{
public const int HWND_BROADCAST = 0xffff;
public const int HWND_IPC = 0xfffe;
public static readonly int WM_IPC = RegisterWindowMessage("WM_IPC");
public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32.dll")]//, CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);
}
I've tried this with many permutation of using PostMessage, SendMessage, just using static int messages, actually invoking the RegisterWindowMessage. Nothing seems to work.
Additionally, I would like to not just be able to specify a specific message, but also additional dynamic details like a username and some message text.
Upvotes: 0
Views: 3605
Reputation: 17658
I thought you'll need the override, although I am not sure it exists in a WPF view:
try this:
protected override void WndProc( etc...
[UPDATE] You cannot override WndProc in the Window class of WPF this way.
How to handle WndProc messages in WPF?
Will explain that you'll need a hook:
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
Putting this together:
In your App.xml.cs you'll initialize your App startup arguments. It's easiest to create some static properties. Keep them simple, no collections to avoid multithreading collapses later on:
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public static string SomeValue { get; private set; }
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
SomeValue = e.Args[0];
}
}
Now you are able to access SomeValue
throughout your code by just calling App.SomeValue
.
Then; a WndProc has to be implemented into a window. A window has a message pump. Without the a message pump you just can't send messages (you could create your own, but that's too much)
So in a window, for example MainWindow, implement the override:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
public IntPtr WndProc(IntPtr hwnd, int msg,
IntPtr wParam, IntPtr iParam, ref bool handled)
{
if (msg == NativeMethods.HWND_IPC)
MessageBox.Show("Message Received!");
return IntPtr.Zero;
}
}
internal class NativeMethods
{
etc. etc.
The only thing left to implement is the moment to fire the message, but since it is IPC, you basically could send it from anywhere, provided you have a handle to the target window.
Combine this info with Franks remarks about WM_COPYDATA and it is ready to go. For info on WM_COPYDATA:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms649011%28v=vs.85%29.aspx
Hope it helps.
Upvotes: 1
Reputation: 432
You are sending message HWND_IPC (window handle?) instead of WM_IPC. HWND_IPC is with value 0xFFFE not in the range for user messages WM_USER+x.
You cannot transfer data in this way. There is a WM_COPYDATA which copies the given buffer from one processes private address space to that of the other...
I think you should use a named pipe to transfer data. SendMessage is so Win31 ;-)
Upvotes: 3