Launching IE from winforms, can I close IE when my winforms closes? - winforms

I have a winforms application, that why someone clicks on a button I need to open up IE to a specific URL.
When someone closes the winforms app, I then need to close IE.
Is this possible? If yes, how?

If you dont have the reference to the old process you used for launching IE, you have to search through the process array returned by System.Diagnostics.Process.GetProcessesByName("IEXPLORE") and kill the specific process.
some samples here.

It would be possible to do that, but it might be a better idea to simply embed Internet Explorer into your application using the WebBrowser control. That way when you close the website you have no chance of closing the whole window when your website opened in a new tab in an existing IE window.
Edit: If you're going to do it anyway, look at the MSDN page on System.Diagnostics.Process.Close

Yes it is possible,
When you call System.Diagnostics.Process.Start() to start the browser, use a specifically created process object. You can later use the process information to kill the process.
However, as Dan Walker mentioned, it might be a better idea to just use the Web Browser control, unless you have specific navigation needs, then it might be more effective to just start and kill IE.

Not sure how you are launching IE, but if you keep a reference to the launched process (or the window handle that was created), you can kill the process (or close the window) when you app exits.
EDIT:
Code to close a window handle is like
Utilities.Utilities.SendMessage(mTestPanelHandle, WM_COMMAND, WM_CLOSE, 0);
if you have a P/Invoke
public const int WM_COMMAND = 0x0112;
public const int WM_CLOSE = 0xF060;
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int SendMessage(IntPtr hwnd, uint Msg, int wParam, int lParam)

Try this (assuming by WinForms you are using .NET)
Process ieProcess = Process.Start("iexplore", #"http://www.website.com");
// Do work, etc
ieProcess.Kill();
This will only kill the instance you started.

Related

Application does not appear in taskbar when launched & stays behind main Application

I am launching a WPF application from a MFC Application. Sometimes it happens that when I Launch the WPF Applciation, the applciation does get launched but it does not appear in the taskbar. And stays behind the main application. So I keep waiting that the application has not yet launched. When I minimize the main Application, I see it was already launched. Can anyone please identify whats going on?
Thanks
You are using ShellExecute incorrectly. Please have a look here. The last parameter, nShowCmd, is:
The flags that specify how an application is to be displayed when it is opened. If lpFile specifies a document file, the flag is simply passed to the associated application. It is up to the application to decide how to handle it. These values are defined in Winuser.h.
Therefore, you need to specify the desired ShowWindow flag. I recommend using either SW_SHOWNORMAL or SW_MAXIMIZE:
int nResult = (int)::ShellExecute(NULL, _T("open"), sExePath, NULL, NULL, SW_SHOWNORMAL);
or
int nResult = (int)::ShellExecute(NULL, _T("open"), sExePath, NULL, NULL, SW_MAXIMIZE);
It is also a good idea to check the return code of the function. If it succeeds the value in nReturn should be greater than 32.

WindowInteropHelper.Handle — do I need to release it?

In WPF I'm getting IntPtr handle using this code:
IntPtr mainWindowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle
When I finish using this handle, do I need to release it in anyway (e.g. using Marshal.FreeHGlobal() method) ?
EDIT: I was thinking about Marshal.FreeHGlobal(), not Marshal.Release(), sorry!
This is not in any way related to COM, Marshal.Release() does not apply. You simply get a copy of the native window handle, it does not have to be released. You need to stop using the handle when the window is destroyed. Signaled by the Window.Close event.

How do I gracefully exit an X11 event loop?

Almost every tutorial I find tells me to do this for my event loop:
XEvent event;
while (true)
{
XNextEvent(display, &event);
switch (event.type)
{
case Expose:
printf("Expose\n");
break;
default:
break;
}
}
However, clicking the X to close the program results in this message.
XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 10 requests (10 known processed) with 0 events remaining.
It is indeed strange to me that the examples suggest using an infinite loop. That doesn't sound natural, and my other X11 programs don't do that. So I searched around. I found out how to capture the window close event.
Atom wmDeleteMessage = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &wmDeleteMessage, 1);
XEvent event;
bool running = true;
while (running)
{
XNextEvent(display, &event);
switch (event.type)
{
case Expose:
printf("Expose\n");
break;
case ClientMessage:
if (event.xclient.data.l[0] == wmDeleteMessage)
running = false;
break;
default:
break;
}
}
That works. It exits without errors. ... But I refuse to believe this is the normal way to do things. I mean, is this the only way to properly exit an X11 app? It seems like a lot of work just to capture the close event. How do I make a 'proper' event loop? Why is the close event so deeply buried? What am I missing?
The problem lays in the communication between X Server and the Window Manager.
When you call XCreateWindow or XCreateSimpleWindow, the X Server creates your window (not showing it until you explicitly map it on the screen by calling XMapWindow), and then the Window Manager is responsible for attaching all the decorations and buttons and system menu around your window.
You can call XDestroyWindow on your own to remove the window, and this usually means it just disappears from the screen, but your program is still running and the connection to the X Server is still open, so you can send it some more requests.
The problem begins when the user clicks that little X button attached to your window by the Window Manager, because it is not created by the X Server and it is not his business to decide what to do then. Now it's all in hands of Window Manager.
If the Window Manager simply called XDestroyWindow on your window, it would cause a problem if your application wanted to capture the closing event to do something before the window gets destroyed. So the convention has been established between the X Server and the Window Managers to handle this process.
The default behavior of most Window Managers is to destroy the window and close the connection with the X server, because this is what most users of Window Managers would expect: that when they close the window, the program will end (and the connection to the X Server will close with the closed window). And then, when you try to call XCloseDisplay(display), it will cause the IO error you've mentioned, because the connection to the server is already closed and the display structure is invalid.
Here's an excerpt from the Xlib documentation which explains this:
Clients that choose not to include WM_DELETE_WINDOW in the WM_PROTOCOLS property may be disconnected from the server if the user asks for one of the client's top-level windows to be deleted.
Yeah, it would be great if they didn't hide it so deep in their docs, though :-P
But when you already find it, fortunately it also hints for the solution.
If you want a different behavior (that is, to capture the closing event from the Window Manager), you need to use the WM_DESTROY_WINDOW protocol.
Another excerpt from the docs:
Clients, usually those with multiple top-level windows, whose server connection must survive the deletion of some of their top-level windows, should include the atom WM_DELETE_WINDOW in the WM_PROTOCOLS property on each such window. They will receive a ClientMessage event as described above whose data[0] field is WM_DELETE_WINDOW.
I had the same error and I wanted to know exactly what causes it and why. It took me some time to figure it out and find the proper explanation in the doc, so I put my explanation here to save the time of others uninformed.
There are no such things as "exit button" or "application" or "close event" in X11. This is by design.
Window decorations, exit buttons and many the other things we depend upon are not built into X11. They are implemented on top of the core X11 instead. The name of the particular set of conventions responsible for wmDeleteMessage is ICCCM, look it up.
Xlib only deals with the core X11 protocol. No built-in close event there.
There are toolkits that make dealing with ICCCM and all other things that are not built into X11 easier (GTK, wxWindows, Qt, ...) You probably want to use one of those.

Creating hidden processes (window not visible)

I'm using CreateProcess() with startup flags set to STARTF_USESHOWWINDOW and SW_HIDE to start an application in the background with its window hidden.
I'm doing this to run a scheduled maintenance tasks and i don't want to be bothered with windows.
In most cases the windows are hidden but there are cases where the program's window pops right out in front of you (for example Google's Chrome - i started testing with different apps to see whether this was a once time problem but nope...).
This happens less in Windows XP, but it happens a lot on Vista.
Is there a flag that I am missing? Is there any other way to create a process with its window hidden?
Thanks!
my sample code is:
char *ProgramName
STARTUPINFO StartupInfoF;
PROCESS_INFORMATION ProcessInfoF;
memset(&StartupInfoF, 0, sizeof(StartupInfoF));
memset(&ProcessInfoF, 0, sizeof(ProcessInfoF));
StartupInfoF.cb = sizeof(StartupInfoF);
StartupInfoF.wShowWindow = SW_HIDE;
StartupInfoF.dwFlags = STARTF_USESHOWWINDOW;
if (CreateProcess(ProgramName,
"",
0,
0,
FALSE,
DETACHED_PROCESS,
0,
0,
&StartupInfoF,
&ProcessInfoF) == FALSE)
{
// error
}
else
{
// OK
}
You can start the process on another desktop, using the lpDesktop member of the STARTUPINFO structure passed to CreateProcess. This way the process will have all its windows shown, but on another desktop, so you (or your users) won't be bothered with it.
I've never worked with multiple desktops so I can't say what would be the side effects, but I think it's doable. Start by looking into CreateDesktop and move onward.
I don't remember the answer to your question, but I'd like to suggest that maybe you shouldn't keep the window totally hidden? If you want the window out of the way, minimizing it will suffice; hiding it completely only removes the ability to check on your scheduled maintenance tasks.
Some programs could ignore/override SW_HIDE flag. You could try to hide window after child process started.
Another option is to try to use CreateProcessAsUser to run processes in Session 0 which has isolated desktop (starting from Vista version).
I'd suggest making it a service. For one thing, that will allow it to run your scheduled maintanence even when nobody is logged in. For another, it is fairly easy to set services up so that they don't have access to the desktop.

Generic GDI+ Error

I have a Form being launched from another form on a different thread. Most of the time it works perfectly, but I get the below error from time to time. Can anyone help?
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height)
at System.Drawing.Icon.ToBitmap()
at System.Windows.Forms.ThreadExceptionDialog..ctor(Exception t)
at System.Windows.Forms.Application.ThreadContext.OnThreadException(Exception t)
at System.Windows.Forms.Control.WndProcException(Exception e)
at System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(Exception e)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Form.ShowDialog(IWin32Window owner)
at System.Windows.Forms.Form.ShowDialog()
The user has to be able to see multiple open accounts simultaneously, right? So you need multiple instances of a form?
Unless I'm misreading something, I don't think you need threads for this scenario, and I think you are just introducing yourself to a world of hurt (like these exceptions) as a result.
Assuming your account form is called AccountForm, I'd do this instead:
Dim acctForm As New AccountForm()
acctForm.Show()
(Of course you'll have your own logic for that ... ) I might even put it in the ShowForm method so that I could just update my caller thusly:
ShowForm()
And be done. Now all of this assumes that you've encapsulated the AccountForm nicely so that each instance has its own data, and they don't share anything between instances.
Using threads for this is not only overkill, but likely to introduce bugs like the exception at the top. And my experience in debugging multi-threaded WinForms apps has shown that these bugs are often very difficult to replicate, and extremely tricky to find and fix. Oftentimes, the best fix is to not multithread unless you absolutely, positively have to.
Can you elaborate what you are trying to do here?
If you are trying to show a Form from a different thread than the UI thread then refer to this question:
My form doesn't properly display when it is launched from another thread
The application is an Explorer-Type customer management system. An account form is launched from the "Main" explorer form on a separate background thread. We do this because the user needs to be able to have multiple accounts open at the same time.
We launch the form using this code:
Thread = New Thread(AddressOf ShowForm)
Thread.SetApartmentState(ApartmentState.STA)
Thread.IsBackground = True

Resources