I use PostMessage to send message to my application if another instance is trying to open:
(CUSTOMTEXT replaced with my appname)
NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_CUSTOMTEXT_SHOWME, IntPtr.Zero, IntPtr.Zero);
And in WndProc I receive the message:
protected override void WndProc(ref Message m)
{
if (m.Msg == NativeMethods.WM_CUSTOMTEXT_SHOWME)
{
MessageBox.Show("Message received");
}
base.WndProc(ref m);
}
And NativeMethods class:
class NativeMethods
{
public const int HWND_BROADCAST = 0xffff;
public static readonly int WM_CUSTOMTEXT_SHOWME = RegisterWindowMessage("WM_CUSTOMTEXT_SHOWME");
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);
}
Everything works fine, but when I hide my application from taskbar (this.ShowInTaskbar = false;) my application stops receiving that message.
Why? Is there any workaround for this?
Found alternative solution: I replaced PostMessage (asyncronous) with SendMessage (syncronous). For some reason, SendMessage gets through while PostMessage does not.
In this application it does not matter which one I use, because when the message is being sent, application just exits. If it takes little time to Windows to process this message, no harm done. Point is only that older instance of application receives this message.
Related
I'm trying to get window messages in a WPF app to be able to use the Win32 API; the problem is that every time the app goes out of focus/is minimized I'm unable to receive any more messages. I tried doing this but my implementation of it in WPF (which I'm not entirely sure of how correct it is, see code below) converts the window to a read-only window after which I can't interact with the GUI at all, it's not even there in the taskbar anymore (Not to mention how this only works if I minimize the window, it doesn't help when the app is still on the screen but out of focus).
public partial class MainWindow : Window
{
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
private int SC_MONITORPOWER = 0xF170;
private int WM_SYSCOMMAND = 0x0112;
private int SC_MINIMIZE = 0xF020;
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)
{
if (msg == WM_SYSCOMMAND) //Intercept System Command
{
if ((wParam.ToInt32() & 0xFFF0) == SC_MONITORPOWER)
{ //Intercept Monitor Power Message
MessageBox.Show("WORKING");
}
if ((wParam.ToInt32() & 0xFFF0) == SC_MINIMIZE)
{
ChangeToMessageOnlyWindow();
}
}
return IntPtr.Zero;
}
private void ChangeToMessageOnlyWindow()
{
IntPtr HWND_MESSAGE = new IntPtr(-3);
SetParent(new WindowInteropHelper(this).Handle, HWND_MESSAGE);
}
}
My issue is PostMessage windows API is not working properly as it works when running from console application.
Working code:
I have 2 application [1] is console application [2] Windows Forms application.
Requirement is I want to send message to all the running instances of application.
console application code:
class Program
{
#region Dll Imports
public const int HWND_BROADCAST = 0xFFFF;
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);
#endregion Dll Imports
public static readonly int WM_ACTIVATEAPP = RegisterWindowMessage("CLOSE");
static void Main(string[] args)
{
//we tried to create a mutex, but there's already one (createdNew = false - another app created it before)
//so there's another instance of this application running
Process currentProcess = Process.GetCurrentProcess();
//get the process that has the same name as the current one but a different ID
foreach (Process process in Process.GetProcessesByName("ClientApp1"))
{
if (process.Id != currentProcess.Id)
{
IntPtr handle = process.MainWindowHandle;
//if the handle is non-zero then the main window is visible (but maybe somewhere in the background, that's the reason the user started a new instance)
//so just bring the window to front
//if (handle != IntPtr.Zero)
//SetForegroundWindow(handle);
//else
//tough luck, can't activate the window, it's not visible and we can't get its handle
//so instead notify the process that it has to show it's window
PostMessage((IntPtr)HWND_BROADCAST, WM_ACTIVATEAPP, IntPtr.Zero, IntPtr.Zero);//this message will be sent to MainForm
break;
}
}
}
}
Windows Forms application code:
public partial class Form1 : Form
{
#region Dll Imports
public const int HWND_BROADCAST = 0xFFFF;
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);
#endregion Dll Imports
public static readonly int WM_ACTIVATEAPP = RegisterWindowMessage("CLOSE");
public Form1()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
//someone (another process) said that we should show the window (WM_ACTIVATEAPP)
if (m.Msg == WM_ACTIVATEAPP)
this.Close();
}
}
Above code is working as expected.
My issues start from here. I want to run the same code from windows service instead of console application. Need immediate guidance.
It seems when I run this code from windows service its not getting hold of the process or service runs in different account so message is not getting delivered.
Most probably you run your service as Local System account in session 0 and it is rather isolated for good reasons. For example you don't have access to other desktops/sessions.
You have to implement a different IPC method, e.g. pipes or memory mapped files.
I need to write an auto click C# application for Bluestack in background.
I tried using Autoit api and I can click or sendkey, but it does not support drag & drop.
I found a solution using "user32.dll" PostMessage on C#, but it doesn't seem to work in window 10 anymore.
Anyone have other solutions. Please help. Thanks a lot!
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
PostMessage(handle, (uint)WMessages.WM_LBUTTONDOWN, 0, MAKELPARAM(400, 400));
Make Sure you are using correct window handle for sending click. It is with name BlueStacks Android PluginAndroid{X} {X=>instance of android running}
I tries sending message to that handle of window and it worked like charm on win10.
Win32.SendMessage(0x00060714, Win32.WM_LBUTTONDOWN, 0x00000001, 0x1E5025B);
Here is the winapi class I picked from here
public class Win32
{
// The WM_COMMAND message is sent when the user selects a command item from
// a menu, when a control sends a notification message to its parent window,
// or when an accelerator keystroke is translated.
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_COMMAND = 0x111;
public const int WM_LBUTTONDOWN = 0x201;
public const int WM_LBUTTONUP = 0x202;
public const int WM_LBUTTONDBLCLK = 0x203;
public const int WM_RBUTTONDOWN = 0x204;
public const int WM_RBUTTONUP = 0x205;
public const int WM_RBUTTONDBLCLK = 0x206;
// The FindWindow function retrieves a handle to the top-level window whose
// class name and window name match the specified strings.
// This function does not search child windows.
// This function does not perform a case-sensitive search.
[DllImport("User32.dll")]
public static extern int FindWindow(string strClassName, string strWindowName);
// The FindWindowEx function retrieves a handle to a window whose class name
// and window name match the specified strings.
// The function searches child windows, beginning with the one following the
// specified child window.
// This function does not perform a case-sensitive search.
[DllImport("User32.dll")]
public static extern int FindWindowEx(
int hwndParent,
int hwndChildAfter,
string strClassName,
string strWindowName);
// The SendMessage function sends the specified message to a window or windows.
// It calls the window procedure for the specified window and does not return
// until the window procedure has processed the message.
[DllImport("User32.dll")]
public static extern Int32 SendMessage(
int hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
[MarshalAs(UnmanagedType.LPStr)] string lParam); // second message parameter
[DllImport("User32.dll")]
public static extern Int32 SendMessage(
int hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
int lParam); // second message parameter
}
I have set a viewer which is the current process and want to recive a message WM_DRAWCLIPBOARD.
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
var result = WinapiClipboard.SetClipboardViewer(Process.GetCurrentProcess().Handle);
It says right here that i should use an-application defined function to parse that message. But it never hits the function/method.
private static IntPtr WndProc(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam)
{
var hdc = Process.GetCurrentProcess().Handle;
var clipboard = new WinClipboard();
switch (message)
{
case WinapiClipboard.WM_DRAWCLIPBOARD:
var result = clipboard.GetUnicodeTextAsync().Result;
return IntPtr.Zero;
default:
break;
}
return WinapiClipboard.DefWindowProc(hWnd, message, wParam, lParam);
}
How i should get this message? Am i even subscribing correctly?
UPDATE:
I'm not using WinForms/WPF or any of those .NET classic framework features. All i have is .net standard 2.0 or .net core.
This is all pretty straight foward from a winforms app
Note : you cant do this from a console app (with any ease)
Declare this
[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
In your form constructor
// this.handle is your forms handle
_ClipboardViewerNext = SetClipboardViewer(this.Handle);
You will then receive the WM_DRAWCLIPBOARD messages in your form by overriding WndProc
In your form
protected override void WndProc(ref Message m)
{
switch ((Win32.Msgs)m.Msg)
{
case Win32.Msgs.WM_DRAWCLIPBOARD:
// Handle clipboard changed
break;
// ...
}
// we call this so we to pass the message along
base.WndProc(ref m);
}
Another way to do this and maybe a more modern approach
Declare this
public const int WM_CLIPBOARDUPDATE = 0x031D;
public static IntPtr HWND_MESSAGE = new IntPtr(-3);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
In your form constructor
SetParent(Handle, HWND_MESSAGE);
AddClipboardFormatListener(Handle);
In your form
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CLIPBOARDUPDATE)
{
// handle message
}
base.WndProc(ref m);
}
if you are using a class library you'll have to create an hidden from and pass back an action or event
private class HiddenForm : Form
{
public HiddenForm()
{
SetParent(Handle, HWND_MESSAGE);
AddClipboardFormatListener(Handle);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_CLIPBOARDUPDATE)
{
// do stuff here like call event
}
base.WndProc(ref m);
}
}
Note : None of this is tested however should get you started
Update 1
SetClipboardViewer expects a window handle, not a process handle. If
you don't have a window handle, create a message-only window for the
sole purpose of receiving clipboard messages - thanks to IInspectable
Update 2
This will only ever work on the kind of machine that also always has
the full framework available. - thanks to Hans Passant
Since you are doing a winforms project override the existing Control.WndProc rather than provide a static.
protected override void WndProc(ref Message m)
{
if(WM_DRAWCLIPBOARD == msg.Msg)
{ ... }
else
base.WndProc(ref msg);
}
I am trying to override the window procedure for the winmobile taskbar (in order to catch and block pressed buttons) by using SetWindowLong. I have created a class with one method for overriding and one for restoring the window procedure. The MessageReceived method is the one I use to replace the taskbar window procedure with. My class looks the following way:
class ButtonBlocker
{
public delegate IntPtr WindowProc(IntPtr hwnd, uint uMsg, IntPtr wParam, IntPtr lParam);
public static WindowProc newWindowDeleg;
private static IntPtr oldWindowProc;
[DllImport("coredll.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("coredll.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("coredll.dll")]
static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("coredll.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
private static IntPtr MessageReceived(IntPtr hwnd, uint uMsg, IntPtr wParam, IntPtr lParam)
{
Debug.WriteLine("Message received");
return CallWindowProc(oldWindowProc, hwnd, uMsg, wParam, lParam);
}
public static void OverrideWindowProc()
{
newWindowDeleg = MessageReceived;
IntPtr taskBarHandle = FindWindow("HHTaskBar", null);
int newWndProc = Marshal.GetFunctionPointerForDelegate(newWindowDeleg).ToInt32();
int result = SetWindowLong(taskBarHandle, -4, newWndProc);
oldWindowProc = (IntPtr)result;
if (result == 0)
{
MessageBox.Show("Failed to SetWindowLong");
}
}
public static void RestoreWindowProc()
{
IntPtr taskBarHandle = FindWindow("HHTaskBar", null);
int result = SetWindowLong(taskBarHandle, -4, oldWindowProc.ToInt32());
}
}
The behavior in the mobile emulator is the following - after I press a button, "Message received" is displayed in the Debug output, but the program crashes and offers to send a crash report to Microsoft. The visual studio debugger hangs and doesn't react to the stop command. It unfreezes only after an emulator reset.
The problem seems to be with the CallWindowProc at the end of the MessageReceived method. Most probably, there is some issue with the old windowproc address.
If I try to execute the RestoreWindowProc code immediately after the OverrideWindowProc code (with no messages being intercepted by my function), the application exits okay and the debugger does not freeze.
Any ideas on how to get this to work would be appreciated.
I am using Visual Studio 2008 SP1. The project targets .NET framework v3.5, Windows Mobile 6 Professional.
You cannot replace the window procedure of a window that is owned by another process. The address of the replacement function is only valid in your process. It causes an immediate bomb in the other process. You would have to inject a DLL into the target process to work around this problem. You can't inject DLLs written in a managed language, the CLR isn't initialized.