How to make Internet Explorer ActiveX dialog visible - c#

I have an ActiveX control written in C# which operates a scanner from the browser using WIA. Everything works fine except the WIA CommonDialog pops under the browser window. How can I get it to show up on top of the browser?
wiaDialog = new WIA.CommonDialog();
wiaImage = wiaDialog.ShowAcquireImage(WiaDeviceType.ScannerDeviceType, WiaImageIntent.UnspecifiedIntent, WiaImageBias.MaximizeQuality, wiaFormatJPEG, false, false, false);
[Edit]
Thanks very much to Noseratio for putting me onto the right track. The suggestion to use BringWindowToTop invoked via a timer before popping up the dialog does not quite work. Instead the function to use is SetForegroundWindow. The code is as follows (invoked from a System.Timer.Timer prior to opening the scan dialog):
public static void scanDialogToTop(Object caller, EventArgs theArgs) {
scanner.theTimer.Stop();
foreach (Process p in Process.GetProcesses()) {
if (p.MainWindowTitle.StartsWith("Scan using")) {
SetForegroundWindow(p.MainWindowHandle);
break;
}
}
}
See this article for a more complete discussion.

It does not look like you can specify a parent window for ShowAcquireImage. If the caption of the popup window is static, you could use FindWindow to find the popup's handle. If ShowAcquireImage is a blocking call (doesn't return until the popup window is closed), before calling it you'd need to setup a timer and call FindWindow upon a timer event. I also suspect the WIA popup is created on a different thread (you could check that with Spy++). If that's the case, you could use the following hack to give the WIA popup window focus. Otherwise you just do BringWindowToTop.

Related

C# ChromiumWebBrowser: Prevent control from stealing focus

I'm making a program that has a Form with a ChromiumWebBrowser in it. The navigation is done automatically. When webbrowser complete it's task, I'll dispose it, create a new webbrowser, add it to form, and load a new address.
But, when the new webbrowser was created and added to form, the program jumps in front of what ever other program is in the top with focus. Example: I start my program, press the button to start its task, open notepad to type some text and my program jumps in front of it when navigating to a new site.
Even when the window is minimized, it still steals focus from other open programs.
How do I prevent it stealing focus after it is created?
As #amaitland said, this looks like a bug.
Workarounds I've used are:
1) disable the browser. This will prevent the browser from receiving mouse/keyboard input, but it won't "grey-out" the control.
Browser1 = New CefSharp.WinForms.ChromiumWebBrowser(url)
Browser1.Enabled = False
2) Pass a callback .net function for when the page loads where you simply put the focus back to winforms by focusing on a label of your choice.
Label1.Focus()
Your Form need set: this.Topmost = false;
AND just set: this.BringToFront();
Add new browser to the form just like the function as follow:
private ChromiumWebBrowser AddNewBrowser(FATabStripItem tabStrip, String url)
{
if (url == "")
{
url = OpenUrl;
txtUrl.Select();
txtUrl.Focus();
}
else
{
tabStrip.Select();
tabStrip.Focus();
}
// ...
}
Hope has help to you. Thanks !

How to keep window visible at all times, but not force it to be on top

I'm creating a "desktop gadget" of sorts, I've disabled manual minimizing of the window, but now there is another problem: the system can still hide the window if the user presses Windows+D, for example.
When hidden that way, no usual minimize/resize/visibility events are fired.
I want to do something almost like TopMost, but without forcing the window order.
Maybe it's possible to install a global shortcut event using win32 API, and briefly set TopMost to true, but that sounds very hackish.
I found one solution, but it does not seem to work on Windows 10: Keeping window visible through "Show Desktop"/Win+D
The other common option, which would be writing an actual desktop gadget, is not possible on Windows 10, given their deprecation.
Are there any other methods to keep a window visible (but not on top of the screen) at all moments?
This function is working for me:
BOOL FixShowDesktop(HWND hWnd)
{
HWND hWndTmp = FindWindowEx(NULL, NULL, L"Progman", NULL);
if (hWndTmp)
{
hWndTmp = FindWindowEx(hWndTmp, NULL, L"SHELLDLL_DefView", NULL);
if (hWndTmp)
{
SetWindowLongPtr(hWnd, -8, (LONG_PTR)hWndTmp);
return TRUE;
}
}
return FALSE;
}
Note, this code is a bit better then from Keeping window visible through "Show Desktop"/Win+D because the window can be overflowed by other windows (like any other window). Using SetParent places window under all other windows.

C# WinForms Wait on form to proceed

I'm tired and hungry, so I might of missed it, but from what I can see no existing post covers this...
I'm writing a plugin for an application. My plugin loads a form to get some data specifically, it uses the webcam to scan for a barcode. Once it's found a barcode, the form hides itself (incase it's needed again later). This is how I currently call the form that does the barcode work:
string readData = null;
if (eye == null)
{
System.Windows.Forms.Application.EnableVisualStyles();
eye = new CamView();
}
eye.Show();
if (eye.found)
{
readData = eye.readData;
}
return readData;
So, my problem is that eye.show() doesn't block. It makes the form appear and carries right on before there's a chance for the barcode to appear. I imagine I need to use some form of threading or locking, but my crude attempts to do so have just frozen the interface completely.
The "eye" form is basically just a viewfinder for the webcam, and relies on the camera_OnImageCapture event to make it do it's image checks for the barcode.
Is there an elegant way to make the application calling the plugin wait for the form to finish? Or do I just need to add an accept button to the "eye form?"
Cheers. And humble apologies if this is in anyway a repost.
.ShowDialog();
http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx
"You can use this method to display a modal dialog box in your application. When this method is called, the code following it is not executed until after the dialog box is closed."
You are on the right track. You change the code to show CamView as a modal dialog but do no add an Accept button. Instead change camera_OnImageCapture to close the dialog.

Webbrowser steals focus

I'm using webbrowser control in my winforms app (c#). And when it is doing automation things, I'm losing focus control from the window I was working with. Webbrowsers' form doesn't show up also, I just lose focus from the contol. I now writing this message I have to click into textbox again and again...
How to disable such behaviour in webbrowser?
I create invisible webbrowser like that:
var br = new WebBrowser();
br.Visible = false;
br.ScriptErrorsSuppressed = true;
Please advise.
I had the same problem:
The Webbrowser Control stole focus from the application once the URL is loaded.
This worked for me:
Before Webbrowser.Navigate() method call, set the parent control of the Webbrowser to Enabled = false.
At the DocumentCompleted event of the Webbrowser, reset parent control of the Webbrowser to Enabled = true.
You can't do it directly on Webbrowser because WebBrowserBase.Enabled is not supported.
Let me know if it works for you.
You could try disabling it globally via the SystemParametersInfo api. Use SPI_SETFOREGROUNDLOCKTIMEOUT. Setting foreground lockout is a global settings, so you will want to clear this setting when you're done. A more permanent solution is to change HKCU\Control Panel\Desktop\ForegroundLockTimeout registry key. See also this discussion on social.msdn (specifically, billb08's answer).
I guess WebBrowser acquires the focus after a page is loaded by calling Navigate (or the Click method of an HtmlElement, which causes navigation). The focus could be given back to the control on the window (the TextBox) in the DocumentComplete event handler of the WebBrowser, but this is very difficult:
When would you determine which control owned the focus
originally? Before calling Navigate? This is not enough, because the
user can move to another control after calling Navigate, but before
handling DocumentComplete.
AFAIK setting the focus to a TextBox will select its whole
content, so you will have to put the cursor back to its original
position. But when would you store the original position? Same problem.
There can be more than one DocumentComplete event after a single
Navigate (or Click).
A possible solution would be to create a separate application for your hidden WebBrowser. This second application would be invisible, and could communicate with the original GUI application using some InterProcess Communication (IPC) technique. Because the WebBrowser in this case would run in a different process, you would have a better chance not to lose lose the focus and bother the user.
it's a very complex problem to fix, and should be revised by microsoft, an app just stealing the focus is not logical, it does depend on what the website is doing though. I had to resort to a CBT filter, see http://msdn.microsoft.com/en-us/magazine/cc188966.aspx, and filter out unwanted HCBT_ACTIVATE and HCBT_SETFOCUS (return 1;). You can use GetWindowClass(wParam) to see what's going on.
Even above didn't entirely work, the app window would still pop to the front temporarily so worked around that using SetWindowPos HWND_TOPMOST and HWND_NOTOPMOST on the window currently in foreground. The HCBT_SETFOCUS gets hit 2 or 3 times so on 1st set HWND_TOPMOST and last set HWND_NOTOPMOST. Count how many classname == "Internet Explorer_Server" which should be 2 (or possibly depends on website?), the other is "Shell Embedding" but doesn't always occur. Hope it helps.
I was looking at all the other answers to this question and they weren't working for me, but i saw the one about settings Browser.Parent.Enabled = false; i tried so and got an error, so i tried this instead it just came to mind.
Browser.Parent = new Control();
Browser.Parent.Enabled = false;
And now the problem is completely gone, it does not take away focus anymore.
I am using the web browser class as a variable, it is not on my form.
well this worked for me try it, this seemed to be a 100% solution.
Most of the methods won't work for me on more than one web browser. This method is work with any amount of web browsers;
1. Put web browser into a panel and set panel enabled to false, then navigate;
webBrowser.Parent = panelBottom;
panelWebBrowser.Enabled = false;
webBrowser.Navigate("http://www.google.com");
2. Define a navigated event to web browser and delay panels enabling for a second;
private void webBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((obj) =>
{
panelWebBrowser.Enabled = true;
timer.Dispose();
},null, 1000, Timeout.Infinite);
}
My solution for sending the focus back to a form:
Private Sub Web_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles Web.DocumentCompleted
If Me.Visible = False Then
For Each f As Form In My.Application.OpenForms
If TypeOf f Is frmLogin Then
Dim fl As frmLogin = DirectCast(f, frmLogin)
If fl.Visible = True Then
fl.Focus()
Exit For
End If
End If
Next
End If
End Sub

Should Form.ShowDialog(IWin32Window) work with any window handle?

When using System.Windows.Forms.ShowDialog(IWin32Window), should I be able to pass in an IWin32Window representing any window handle and have it be modal with respect to that window?
As part of an Internet Explorer 7 extension I'm trying to open a window modal with respect to an Internet Explorer tab. It's not the currently selected tab, but I can get the hwnd of the tab OK. However, when I pass this to ShowDialog my Form is shown, but it's not modal with respect to anything: I can still do things in Internet Explorer, including in the tab that's supposed to be the owner. My form is shown floating above the Internet Explorer windows and it stays on top, so it's not like it's just opened as a normal form, but it's not correctly modal.
Using Spy++, I can find my form and it's owner handle is correctly set.
Does this mean that something has gone wrong, or I'm doing something wrong? How do I make my form correctly modal?
FYI, I'm using this wrapper class to create an IWin32Window from a hwnd (thanks Ryan!):
/// <summary>
/// Wrapper class so that we can return an IWin32Window given a hwnd
/// </summary>
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
UPDATE: Using Internet Explorer 7 & .NET 2.0
UPDATE: Playing around some more with Spy++ and the handles it exposes, I find that if I use a different hwnd then I can make my window modal to the tab:
I was using the tab's hwnd as suggested by the IWebBrowser2.HWND doc, which in Spy++ appears as class TabWindowClass. It has a child of class Shell DocObject View, which has a child of Internet_Explorer_Server. If I use the hwnd of the Internet Explorer_Server then it works correctly, for example, when I click with the mouse on other tabs, Internet Explorer reacts normally. When I click with the mouse on the tab of interest, it plays the windows d'oh sound and doesn't do anything.
I don't yet know how to programatically get the Internet_Explorer_Server hwnd, but it should be possible.
Also, for what it's worth, while playing with other window handles I was generally able to make my form modal to other applications and dialogs. So I guess the answer to my question is 'many but not all handles'... possibly it depends on the application?
UPDATE: Another side-note: The original reason I wanted to make my form modal to the tab instead of the whole window is that when opening a MessageBox from my form, passing the form as owner, the MessageBox would not always open on top of my form. If a new Internet Explorer tab had just been opened but wasn't active then the MessageBox would be hidden and that tab would start flashing. However, since Internet Explorer was disabled with my form opened modal it wasn't possible to switch to that tab, so Internet Explorer would be frozen. I thought that opening my form modal to the tab would solve this, but I've found another solution is to avoid using MessageBox: if I use a second form and ShowDialog(this) from my first form then the second form correctly opens to the front. So it seems that Form.ShowDialog() works better than MessageBox.Show() in some cases. More discussion in Problems with modal dialogs and messageboxes.
ShowDialog() does two important things. It starts pumping a message loop so it acts modally to the calling code. And it disables any other windows in the application with a EnableWindow(false) API call. The latter is what is not happening in your case. Not entirely surprising, considering that the window that needs to be disabled is not a WF window.
You may need to call EnableWindow() yourself. Be sure to re-enable it in before the dialog closes or Windows will go hunting for another app's window to give the focus to.
Your code is correct. The problem you are likely running into though is that IE has a threading model related to its tabs. I don't know the exact details but the short version is that each tab can and likely is running on a different thread than other tabs.
The Modal'ness of a dialog is specific to the thread where the dialog is running. UI on other threads will be unaffected by a model dialog on another thread. It's entirely possible you are able to access tabs which are running on a different thread for this reason.
Here's a more concise version of Ryan/Rory's WindowWrapper code:
internal class WindowWrapper : IWin32Window
{
public IntPtr Handle { get; private set; }
public WindowWrapper(IntPtr hwnd) { Handle = hwnd; }
}
I have never tried this from an IE extension, but I have a hunch that IE may not "respect" a Win32-style modal window the same way it does a modal window raised from Javascript using window.open().
Have you tested this code against something other than IE, just to confirm it works the way it should for other applications?
here is a build in solution in .NET:
public static NativeWindow FromHandle(IntPtr handle)

Categories