C# WebBrowser Control FileUpload Dialog Not Closing all the Time - c#

I am using a WebBrowser control for some automated testing. The problem is that occasionally - not all the time - when I am testing uploading images, the file upload dialog box does not close and the the program just "hangs" and waits for manual input, which defeats the purpose of the whole automated process. What I want to do is to "force" a close of the dialog box, but have been unable to figure this out. Any help or direction would be much appreciated.
The thing to realize is that this code works some of the time, but NOT all of the time. I need help figuring out how to make this code work ALL of the time.
Here is the code:
async Task PopulateInputFile(System.Windows.Forms.HtmlElement file, string fname)
{
file.Focus();
// delay the execution of SendKey 500ms to let the Choose File dialog show up
var sendKeyTask = Task.Delay(5000).ContinueWith((_) =>
{
// this gets executed when the dialog is visible
//SendKeys.Send(fname + "{ENTER}");
//PressKey(Keys.Space, false);
SendKeys.SendWait(fname);
PressKey(Keys.Enter, false);
}, TaskScheduler.FromCurrentSynchronizationContext());
file.InvokeMember("Click"); // this shows up the dialog
await sendKeyTask;
// delay continuation 500ms to let the Choose File dialog hide
await Task.Delay(5000);
}
async Task Populate(string fname)
{
var elements = webBrowser.Document.GetElementsByTagName("input");
foreach (System.Windows.Forms.HtmlElement file in elements)
{
if (file.GetAttribute("name") == "file")
{
this.Activate();
this.BringToFront();
file.Focus();
await PopulateInputFile(file, fname);
file.RemoveFocus();
}
}
}

Ok, so here is the solution. You have to use the WIN API to close the window. I found the class name of the "Choose File to Upload" dialog by using SPY++, which turns out to be: #32770.
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName,string lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
int iHandle = FindWindow("#32770", "Choose File to Upload");
if (iHandle > 0)
{
// close the window using API
SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
}

Not really an answer, but it may turn into an answer later. Are use sure the focus is inside the IE "Choose File to Upload" dialog, when you do SendKeys? Use the following to verify that, put the code from below Task.Delay(4000) into your ContinueWith and check the output from Debug.Print.
static class Win32
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
private async void Form1_Load(object sender, EventArgs ev)
{
await Task.Delay(4000);
var currentWindow = new System.Text.StringBuilder(1024);
Win32.GetWindowText(Win32.GetForegroundWindow(), currentWindow, currentWindow.Capacity);
Debug.Print("Currently focused window: \"{0}\"", currentWindow);
}

Related

wpf how to get program focus form windows

i made program it work in background, i want this program only work on program i select it
example : i created Auto clicker and i want to use this program just in games if the user go to any other program it doesn't work
this way i hope it is there
if(Windows.Focus.NameProgram.ToString() == "Call of Duty Cold War")
{
// here all commands i will put it later.
}
here i mean what windows focus it now if it is Call of Duty Cold War then work, if not dont work (of course still running in the background)
Use a function called GetForegroundWindow from Windows API.
The implementation further down gets the current focused window.
Documentation: GetForegroundWindow | MS Docs
public class GetFocusedWindow
{
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private static string GetActiveWindowTitle()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
static void Main(string[] args)
{
while (true)
{
Thread.Sleep(2000);
Console.WriteLine(GetActiveWindowTitle());
}
}
}

Maximize/Minimize other applications

Been a while since I did any program so alil rusty. I was researching on code to maximize and minimize other applications. So I found something basic and here is what I have, slightly modified from the original. It wanted me to generate some FindWindow method which I did. Now everything looks good and I tried to run it, getting a message. Not sure where to go from here. The original thread where I found it didn't mention this.
private const int SW_SHOWNORMAL = 1;
private const int SW_SHOWMINIMIZED = 2;
private const int SW_SHOWMAXIMIZED = 3;
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
static void Main(string[] args)
{
// retrieve Notepad main window handle
IntPtr hWnd = FindWindow("Notepad", "Untitled - Notepad");
if (!hWnd.Equals(IntPtr.Zero))
{
// SW_SHOWMAXIMIZED to maximize the window
// SW_SHOWMINIMIZED to minimize the window
// SW_SHOWNORMAL to make the window be normal size
ShowWindowAsync(hWnd, SW_SHOWMAXIMIZED);
}
}
private static IntPtr FindWindow(string p, string p_2)
{
throw new NotImplementedException();
}
First, with your method FindWindow(), when a method has a throw you need to catch it in the method where it is invoked in this case the Main().
Now NotImplementedExceptionis a class, here I post you the inheritance hierarchy
System.Object
System.Exception
System.SystemException
System.NotImplementedException
As say the error, you just need to implement the method and delete de line: `throw new NotImplementedException();
Finally I post an implementation option, just need the title of the in the window application.
public static IntPtr FindWindow(string titleName)
{
Process[] pros = Process.GetProcesses(".");
foreach (Process p in pros)
if (p.MainWindowTitle.ToUpper().Contains(titleName.ToUpper()))
return p.MainWindowHandle;
return new IntPtr();
}
By the way, here is another question about Maximize/Minimize other applications

Closing Personalization window using c#

I have written a program that change the windows theme but after changing the theme personalization window remains open and I want to close it. I tried using process.kill() with familiar process name but it didn't work. Thank you.
The code for what I am doing is as below:
ProcessStartInfo theinfo = new ProcessStartInfo(themepath + "aero.theme");
theinfo.CreateNoWindow = true;
Process thepr = new Process();
thepr.StartInfo = theinfo;
thepr.Start();
where "themepath" is String location to aero.theme.
I have even enabled CreateNoWindow to true then also it opens up Personalization to change theme but didn't close it automatically.
First use find window to get the window from their name by Using FindWindow..
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName,string lpWindowName);
It returns you the handle of the window you want now you can use send message to close it..
[DllImport("User32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
private void closeWindow()
{
// retrieve the handler of the window
int iHandle = FindWindow("CabinetWClass", "Personalization");
if (iHandle > 0)
{
SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
}
}
You need to obtain the window handle by it's name and then send it a close message. This prevents having to kill any processes. See this article for information on obtaining the windows. See this one for closing windows from the handle.
After seeing the code and doing a little digging, you can accomplish this with two registry edits. You should read this article and just have your program edit the two registry keys in question.

Prevent Revit window from opening

I'm trying to intercept Revit and keep a window from opening. Specifically, I'm trying to apply a keynote to an object and then let the user create a keynote tag, however any way I do it it lets them place the keynote but then immediately gives them the dialog to select a keynote, but I don't want that dialog to come up because I already know what the selection should be. However every way I can think of isn't able to interrupt the process to apply the keynote before the user gets the dialog. Is it possible to perhaps monitor for the window to appear then close it via Windows API? or even better intercept when it's going to be shown and stop it from showing?
you can always delete warrnings with:failuresAccessor.DeleteWarning(fma);
this is what i use for my code
public class FloorPreProcessor : IFailuresPreprocessor
{
FailureProcessingResult
IFailuresPreprocessor.PreprocessFailures(
FailuresAccessor failuresAccessor)
{
IList<FailureMessageAccessor> fmas
= failuresAccessor.GetFailureMessages();
if (fmas.Count == 0)
{
return FailureProcessingResult.Continue;
}
// We already know the transaction name.
if (fmas.Count != 0)
{
foreach (FailureMessageAccessor fma in fmas)
{
// DeleteWarning mimics clicking 'Ok' button.
failuresAccessor.DeleteWarning(fma);
}
return FailureProcessingResult
.ProceedWithCommit;
}
return FailureProcessingResult.Continue;
}
}
I hope it will help
Try the following, it searches for a window name, button name, then clicks this button:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
private const uint BM_CLICK = 0x00F5;
public static bool clickButton (string popUpTitle, string ButtonName)
{
// Get the handle of the window
IntPtr windowHandle = FindWindow((string)null, popUpTitle);
if (windowHandle.ToInt32() == 0)
{
return false;
}
// Get button handle
IntPtr buttonHandle = FindWindowEx(windowHandle, IntPtr.Zero, (string)null, ButtonName);
if (buttonHandle.ToInt32() == 0)
{
return false;
}
// Send click to the button
SendMessage(buttonHandle, BM_CLICK, 0, 0);
return true;
}
You should set the popUpTitle (window name) and the ButtonName to click.
Call this into a timer event that waits for a window to pop-up.
Timer timer = new Timer();
timer.Start();
timer.Tick += new EventHandler(timer_Tick);
//when done call timer.Stop();
private void timer_Tick(object sender, EventArgs e)
{
//set your code to clickButton("","")
}
Try it and let me know.
Ok well since there was a new comment I will make this an official answer. The best I came up with is that you can call OverrideResult() on the dialog even though you can't cancel it. It sill flashes the dialog which isn't ideal but it's better than it was... If anyone has a better way I'd love to hear it :)

How to put background window/process on top

I want to create a software like a virtualkeyboard, you have a AlwaysTop Window and use this to put some data on another process/windows. In this case I will record all data on clipboard and compare if this data is compatible with a pattern (A### is the patern and A123 is compatible with the patern), if yes the application will put it in a listbox and the user can paste it on another process/windows (already open) clicking on item on list.
My question is about how to put this information on the last application/process used, I already started a prototype of code but the line indicated is wrong, on my code it's the currentprocess and need to be the last used before click on my form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")]
static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("User32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
private void button2_Click(object sender, EventArgs e)
{
Process currentProcess = Process.GetCurrentProcess(); //this line is wrong
IntPtr hWnd = currentProcess.MainWindowHandle; //this line is wrong
if (hWnd != IntPtr.Zero)
{
SetForegroundWindow(hWnd);
ShowWindow(hWnd, 9);
SendKeys.Send("A123");
}
}
}
}
I get on simple solution, instead of get the process I just send the combination ALT+TAB and work for all cases that I need. Below the solution if anyone need in the future:
string old_clipboard = Clipboard.GetText();
Clipboard.SetText("A123");
SendKeys.SendWait("%{Tab}");
SendKeys.SendWait("^V");
Thread.Sleep(100);
Clipboard.SetText(old_clipboard);
Ps.: I put one delay because the SendWait works only on caller windows, as the target of ^V is another process it´s don´t work well.
Best regards. =)

Categories