Click on 'OK' button of message box using WINAPI in c# - c#

I am trying to click on 'OK' button on a message box of C# windows form using winapi. Below is the code that I am working on.
private const int WM_CLOSE = 16;
private const int BN_CLICKED = 245;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
//this works
hwnd = FindWindow(null, "Message");
if(hwnd!=0)
SendMessage(hwnd, WM_CLOSE, 0, IntPtr.Zero);
//this doesn't work.
hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "Button", "ok");
SendMessage((int)hwndChild, BN_CLICKED, 0, IntPtr.Zero);
Though i get a value in hwndChild, it is not recognising BN_CLICKED.
I am not sure what am I missing. any help?
I am trying to close the message box button of another application and this is what I am doing. But, I m still missing something.
IntPtr hwndChild = IntPtr.Zero;
hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero,' '"Button", "OK");
SendMessage((int)hwndChild, WM_COMMAND, (BN_CLICKED '<<16) | IDOK, hwndChild);

BN_CLICKED is not a message. You need to send a WM_COMMAND message containing the BN_CLICKED notification and the button ID in the wParam and the button handle in lParam.
The parent window of the button receives this notification code
through the WM_COMMAND message.
private const uint WM_COMMAND = 0x0111;
private const int BN_CLICKED = 245;
private const int IDOK = 1;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
SendMessage(hwndChild, WM_COMMAND, (BN_CLICKED << 16) | IDOK, hwndChild);

Finallu, this works for me.
First click probably activates the window and second click clicks the button.
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);

Related

click button on a dialog opened by p/invoke

This code opens a Dialog by clicking a Button on a Form
IntPtr m = FindWindow("TForm1", "Smart Design");
IntPtr b = FindWindowEx(m, IntPtr.Zero, "TButton", "Update List");
SendMessage(b, BM_CLICK, 0, 0);
How to click OK button on the opened dialog?
I tried this code but it fails:
IntPtr d = FindWindow("TDialog4", "Information");
IntPtr k = FindWindowEx(d, IntPtr.Zero, "TButton7", "OK");
SendMessage(k, BM_CLICK, 0, 0);
I'd try sending the dialog a WM_COMMAND instead.
private const uint WM_COMMAND = 0x0111;
private const int BM_CLICKED = 245;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, uint msg,
int wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle,
IntPtr childAfter, string className, string windowTitle);
SendMessage(k, WM_COMMAND, (BM_CLICKED << 16) | 1, k);

The handle to window is not found just after showing MessageBox but after 1 second it is found

I show MessageBox and close it after 1 second by finding it by FindWindow function and then sending const UInt32 WM_CLOSE = 0x0010; to this MessageBox. The closing is success, but before I close it I try to move it to the upperright corner of the screen, but just after creating MessageBox by MessageBox.Show() it cannot be found.
[DllImport("user32.dll", SetLastError = true, PreserveSig = true)]
static extern IntPtr FindWindow(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.Dll")]
static extern int PostMessage(IntPtr hWnd, UInt32 msg, int wParam, int lParam);
[DllImport("user32.Dll")]
static extern int MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
const UInt32 WM_CLOSE = 0x0010;
static Thread thread;
static void CloseMessageBox() {
IntPtr hWnd = FindWindow(IntPtr.Zero, "Success!");
if (hWnd != IntPtr.Zero) {//ALWAYS FALSE DOES NOT FIND THE MESSAGEBOX
MoveWindow(hWnd, 0, 0, 300, 300, true);
// PostMessage(hWnd, WM_CLOSE, 0, 0);
Debug.WriteLine("HERE 1");
}
}
static void ShowMessageBox() {
MessageBox.Show("Data has been loaded!", "Success!");
IntPtr hWnd = FindWindow(IntPtr.Zero, "Success!");
if (hWnd != IntPtr.Zero) {//ALWAYS FALSE DOES NOT FIND THE MESSAGEBOX
Debug.WriteLine("HERE 2");
MoveWindow(hWnd, 0, 0, 300, 300, true);
}
}
public static void Seed() {
thread = new Thread(ShowMessageBox);
new Thread(() => {
thread.Start();
Thread.Sleep(1000);
CloseMessageBox();
}).Start();
}
I doubt .NET world MessageBox.Show message box can be found or controlled by native API calls. Better try with MessageBox API itself. Also ensure that API import and string are both Unicode. I have had problems with FindWindow also when searching by caption!
I would suggest to give Spy++ tool a try on how windows are placed, and if they can be found. Z-order, parent/child relationship also matters.

Simulate "Key Press" on NON Foreground Window

I am currently developing a program that will send a "key press" (the letter A or 0x41 in virtual key codes) to another program (notepad) every X seconds.
The problem is that for it to work I need the other program (notepad) to be in the FOREGROUND, example :
Process[] processes = Process.GetProcessesByName("notepad");
foreach (Process proc in processes) {
SetForegroundWindow(proc.MainWindowHandle);
// Do Whatever
}
Thread.Sleep(1000);
Is there a way to do that WITHOUT notepad having to be in the foreground ?
Like something that could run in the background ?
You could do it via winApi. Try to use SendMessage
According to this link you can do following:
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public static void sendKeystroke(ushort k)
{
const uint WM_KEYDOWN = 0x100;
const uint WM_SYSCOMMAND = 0x018;
const uint SC_CLOSE = 0x053;
IntPtr WindowToFind = FindWindow(null, "Untitled1 - Notepad++");
IntPtr result3 = SendMessage(WindowToFind, WM_KEYDOWN, ((IntPtr)k), (IntPtr)0);
//IntPtr result3 = SendMessage(WindowToFind, WM_KEYUP, ((IntPtr)c), (IntPtr)0);
}

How to handle Message Boxes while using webbrowser in C#?

I'm using this webbrowswer feature of C#. Trying to log in a website through my application. Everything goes fine, except when a wrong ID or password is entered there's little message box (that is set on the webpage itself) which pops up and blocks everything until "Ok" is clicked.
So the question is: Is there any possible way to manage this little window (like reading the text inside of it)? If it is then great!
But if there's no way to do that then is there anyway to simply make this message box go away programatically?
You can "manage" the message box dialog by importing some window functions from user32.dll and getting the messagebox dialog's handle by it's class name and window name. For example to click its OK button:
public class Foo
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private void ClickOKButton()
{
IntPtr hwnd = FindWindow("#32770", "Message from webpage");
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Button", "OK");
uint message = 0xf5;
SendMessage(hwnd, message, IntPtr.Zero, IntPtr.Zero);
}
}
Some reading material from MSDN.
Copy paste from Sires anwser: https://stackoverflow.com/a/251524/954225
private void InjectAlertBlocker() {
HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0];
HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
string alertBlocker = "window.alert = function () { }";
element.text = alertBlocker;
head.AppendChild(scriptEl);
}
here is refined version of Saeb's answer. Saeb's code was not working for me, I added one more step to activate the button and then clicking on it.
using System;
using System.Runtime.InteropServices;
namespace IE_Automation
{
public class IEPoppupWindowClicker
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private const int BM_CLICK = 0xF5;
private const uint WM_ACTIVATE = 0x6;
private const int WA_ACTIVE = 1;
public void ActivateAndClickOkButton()
{
// find dialog window with titlebar text of "Message from webpage"
var hwnd = FindWindow("#32770", "Message from webpage");
if (hwnd != IntPtr.Zero)
{
// find button on dialog window: classname = "Button", text = "OK"
var btn = FindWindowEx(hwnd, IntPtr.Zero, "Button", "OK");
if (btn != IntPtr.Zero)
{
// activate the button on dialog first or it may not acknowledge a click msg on first try
SendMessage(btn, WM_ACTIVATE, WA_ACTIVE, 0);
// send button a click message
SendMessage(btn, BM_CLICK, 0, 0);
}
else
{
//Interaction.MsgBox("button not found!");
}
}
else
{
//Interaction.MsgBox("window not found!");
}
}
}
}

Press save button of "File download dialog" of internet explorer via c#

I am working on internet explorer automation and part of it involves downloading files from a site whcih is hosted on asp 2.0 and uses forms based authentication, so to create end to end automation I used browser automation.
I was able to reach to the step where I can get to click on a URL which brings the "File Download" dialog of the browser, then I was trying to make use of SendKeys to click on the save button but to no avail it was not working.
Here is the code where I make use of FindWindow method to get the hWnd pointer of the File Download Dialog, and then using setActiveWindow I make it the active window so that the SendKeys commands works on it and then using SendKeys I tried to send Alt + S but it didn't work. I observed that, Tab, Escape and Enter works, but then Enter on Save button doesn't work.
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
private void Form1_Load(object sender, EventArgs e)
{
IntPtr hwnd = FindWindow(null, "File Download");
IntPtr nullptr = (IntPtr)0;
if (hwnd != nullptr)
{
SetActiveWindow(hwnd);
SendKeys.SendWait("%S");
}
}
Using the same code I was able to access notepad by changing the value in FindWindow to "Untitled - Notepad".
Do I need to do something different as it is a dialog and now a window? I am using IE8.
This is the alternate code I tried after the answer.
IntPtr hwnd = FindWindow(null, "File Download");
IntPtr hokBtn = IntPtr.Zero;
hokBtn = FindWindowEx(hwnd, hokBtn, "Button", IntPtr.Zero);
hokBtn = FindWindowEx(hwnd, hokBtn, "Button", IntPtr.Zero);
uint id = GetDlgCtrlID(hokBtn);
SetActiveWindow(hwnd);
IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
if (res.ToInt32() == 1)
MessageBox.Show("success");
For clarity I am adding the screen of the dialog.
alt text http://www.freeimagehosting.net/uploads/4f23586401.png
Try the following which seemed to work for me:
IntPtr hwnd = FindWindow(null, "File Download");
IntPtr hokBtn = FindWindowEx(hwnd, null, "Button", "Cancel");
uint id = GetDlgCtrlID(hokBtn);
SetActiveWindow(hwnd);
IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
if (res.ToInt32() == 1)
MessageBox.Show("success");
I would suggest you check the returns from each function though.
This works in C++
Note that the 'Save' button is named '&Save' not 'Save'
CString Title;
Title=_T("File Download");
HWND FEX = ::FindWindowEx( NULL,NULL,NULL,Title);
if (FEX != NULL)
{
//press the Save button on the dialog.
HWND hokBtn = ::FindWindowEx(FEX, NULL, L"Button", L"&Save");
if (hokBtn != NULL)
{
UINT id = ::GetDlgCtrlID(hokBtn);
::SetActiveWindow(hokBtn);
::PostMessage(hokBtn, WM_KEYDOWN, 0x20, 0);
::PostMessage(hokBtn, WM_KEYUP, 0x20, 0);
}
}
well, you have to find window with title of downloading dialog. and than you have to find window with title of download button/ and then send to that window click message
BM_CLICK = 0x00F5
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr next, string sClassName, IntPtr sWindowTitle);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern uint GetDlgCtrlID(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
//hDialog - handle of dialog window. idBtn - Id of button
public static bool ClickButtonOnDialog(IntPtr hDialog, UInt32 idBtn)
{
IntPtr res = IntPtr.Zero;
uint id;
IntPtr hOkBtn = IntPtr.Zero;
int attempt = 0;
do
{
Thread.Sleep(300);
//searching for button
hOkBtn = User32.FindWindowEx(hDialog, hOkBtn, "Button", IntPtr.Zero);
id = User32.GetDlgCtrlID(hOkBtn);
attempt++;
} while (id != idBtn && attempt < 20);
if (!hOkBtn.Equals(IntPtr.Zero))
{
//click the button
res = User32.SendMessage(hOkBtn, (int)WindowsMessages.BM_CLICK, 1, IntPtr.Zero);
}
if (res.ToInt32() == 1)
return true;
return false;
}
and you can use winspector (analog of spy++). it's very useful utility. You can discovery many things about windows;)
I found a way to do this with Internet Explorer 6 in Windows XP.
(Sorry, VBA code)
'ButtonHwnd is the pointer to the Save button
Private Declare Function SetCursorPos Lib "user32" (ByVal X As Integer, ByVal Y As Integer) As Long
Private Declare Sub mouse_event Lib "user32.dll" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Private Const MOUSEEVENTF_LEFTDOWN As Long = &H2
Private Const MOUSEEVENTF_LEFTUP As Long = &H4
Dim pos As RECT
' We get the button position
GetWindowRect ButtonHwnd, pos
' We simulate an entering of the cursor in the button. IE think this is a human :-).
' We need three steps: out, entering and in.
' Out
SetCursorPos (pos.Left - 10), (pos.Top - 10)
Sleep 100
' Entering
SetCursorPos pos.Left, pos.Top
Sleep 100
' In
SetCursorPos (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2
' We do clic with the left button. You can use SendInput instead
' With 400 miliseconds it works.
mouse_event MOUSEEVENTF_LEFTDOWN, (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2, 0, 0
Sleep 400
mouse_event MOUSEEVENTF_LEFTUP, (pos.Left + pos.Right) / 2, (pos.Top + pos.Bottom) / 2, 0, 0
Please, tell if it works for you.
I found most of this on StackOverflow: How to handle Message Boxes while using webbrowser in C#?
and i modified it for me
using System.Runtime.InteropServices; //for the dll import (to press a key)
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private async void downloadstuff()
{
await Task.Delay(40000); //i need this delay, but you might not :)
{
IntPtr hwnd = FindWindow("#32770", "File Download"); //this is the window it finds
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Button", "&Save"); //this is the button to pres
uint message = 0xf5;
SendMessage(hwnd, message, IntPtr.Zero, IntPtr.Zero);
}
await Task.Delay(1000);
{
IntPtr hwnd2 = FindWindow("#32770", "Save As");
hwnd2 = FindWindowEx(hwnd2, IntPtr.Zero, "Button", "&Save");
uint message2 = 0xf5;
SendMessage(hwnd2, message2, IntPtr.Zero, IntPtr.Zero);
}
await Task.Delay(1000); //i press it anyway, just in case :)
{ //this is the download complete box (if its checked it doesn't show up)
IntPtr hwnd3 = FindWindow("#32770", "Download complete");
hwnd3 = FindWindowEx(hwnd3, IntPtr.Zero, "Button", "Close");
uint message3 = 0xf5;
SendMessage(hwnd3, message3, IntPtr.Zero, IntPtr.Zero);
}
}
IntPtr hwnd = FindWindow(null, "File Download");
IntPtr hokBtn = FindWindowEx(hwnd, null, "Button", "Cancel");
uint id = GetDlgCtrlID(hokBtn);
SetActiveWindow(hwnd);
IntPtr res = SendMessage(hokBtn, (int)0x00F5, 0, IntPtr.Zero);
if (res.ToInt32() == 1)
MessageBox.Show("success");
That was actually a false positive if I'm not wrong; the default behaviour seemingly as a failsafe appears to be to close the dialog box. Rather, it was a positive that the cancel button can be clicked, but attempting to click Open or Save will generate the same yet in that context unwanted response...
It seems that this is a dialog box we're just going to have to deal with unless someone else could gratefully confirm otherwise?
None of the code suggested worked, I ended up to use AutoIt script to close a Print Dialog, the code follows:
Local $hWnd = WinWait("[CLASS:#32770]", "Print", 20)
WinActivate($hWnd)
WinWaitActive("[CLASS:#32770]", "Print", 10)
Sleep(100)
Send("{ENTER}")

Categories

Resources