So, I did search google and SO prior to asking this question. Basically I have a DLL that has a form compiled into it. The form will be used to display information to the screen. Eventually it will be asynchronous and expose a lot of customization in the dll. For now I just want it to display properly. The problem that I am having is that I use the dll by loading it in a Powershell session. So when I try to display the form and get it to come to the top and have focus, It has no problem with displaying over all the other apps, but I can't for the life of me get it to display over the Powershell window. Here is the code that I am currently using to try and get it to display. I am sure that the majority of it won't be required once I figure it out, this just represents all the things that I found via google.
CLass Blah { [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni); [DllImport("user32.dll", EntryPoint = "SetForegroundWindow")] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("User32.dll", EntryPoint = "ShowWindowAsync")] private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow); private const int WS_SHOWNORMAL = 1; public void ShowMessage(string msg) { MessageForm msgFrm = new MessageForm(); msgFrm.lblMessage.Text = "FOO"; msgFrm.ShowDialog(); msgFrm.BringToFront(); msgFrm.TopMost = true; msgFrm.Activate(); SystemParametersInfo((uint)0x2001, 0, 0, 0x0002 | 0x0001); ShowWindowAsync(msgFrm.Handle, WS_SHOWNORMAL); SetForegroundWindow(msgFrm.Handle); SystemParametersInfo((uint)0x2001, 200000, 200000, 0x0002 | 0x0001); } }
As I say I'm sure that most of that is either not needed or even flat out wrong, I just wanted to show the things that I had tried. Also, as I mentioned, I plan to have this be asynchronously displayed at some point which I suspect will wind up requiring a separate thread. Would splitting the form out into it's own thread make it easier to cause it to get focus over the Powershell session?
@Joel, thanks for the info. Here is what I tried based on your suggestion:
msgFrm.ShowDialog(); msgFrm.BringToFront(); msgFrm.Focus(); Application.DoEvents();
The form still comes up under the Powershell session. I'll proceed with working out the threading. I've spawned threads before but never where the parent thread needed to talk to the child thread, so we'll see how it goes.
Thnks for all the ideas so far folks.
Ok, threading it took care of the problem. @Quarrelsome, I did try both of those. Neither (nor both together) worked. I am curious as to what is evil about using threading? I am not using Application.Run and I have yet to have a problem. I am using a mediator class that both the parent thread and the child thread have access to. In that object I am using a ReaderWriterLock to lock one property that represents the message that I want displayed on the form that the child thread creates. The parent locks the property then writes what should be displayed. The child thread locks the property and reads what it should change the label on the form to. The child has to do this on a polling interval (I default it to 500ms) which I'm not real happy about, but I could not find an event driven way to let the child thread know that the proerty had changed, so I'm stuck with polling.
I also had trouble activating and bringing a window to the foreground. Here is the code that eventually worked for me. I'm not sure if it will solve your problem.
Basically, call ShowWindow() then SetForegroundWindow().
using System.Diagnostics; using System.Runtime.InteropServices; // Sets the window to be foreground [DllImport("User32")] private static extern int SetForegroundWindow(IntPtr hwnd); // Activate or minimize a window [DllImportAttribute("User32.DLL")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); private const int SW_SHOW = 5; private const int SW_MINIMIZE = 6; private const int SW_RESTORE = 9; private void ActivateApplication(string briefAppName) { Process[] procList = Process.GetProcessesByName(briefAppName); if (procList.Length > 0) { ShowWindow(procList[0].MainWindowHandle, SW_RESTORE); SetForegroundWindow(procList[0].MainWindowHandle); } }
Here is some code that I've used on one form or another for a few years. There are a few gotchas to making a window in another app pop up. Once you have the window handle do this:
if (IsIconic(hWnd)) ShowWindowAsync(hWnd, SW_RESTORE); ShowWindowAsync(hWnd, SW_SHOW); SetForegroundWindow(hWnd); // Code from Karl E. Peterson, www.mvps.org/vb/sample.htm // Converted to Delphi by Ray Lischner // Published in The Delphi Magazine 55, page 16 // Converted to C# by Kevin Gale IntPtr foregroundWindow = GetForegroundWindow(); IntPtr Dummy = IntPtr.Zero; uint foregroundThreadId = GetWindowThreadProcessId(foregroundWindow, Dummy); uint thisThreadId = GetWindowThreadProcessId(hWnd, Dummy); if (AttachThreadInput(thisThreadId, foregroundThreadId, true)) { BringWindowToTop(hWnd); // IE 5.5 related hack SetForegroundWindow(hWnd); AttachThreadInput(thisThreadId, foregroundThreadId, false); } if (GetForegroundWindow() != hWnd) { // Code by Daniel P. Stasinski // Converted to C# by Kevin Gale IntPtr Timeout = IntPtr.Zero; SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, Timeout, 0); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Dummy, SPIF_SENDCHANGE); BringWindowToTop(hWnd); // IE 5.5 related hack SetForegroundWindow(hWnd); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Timeout, SPIF_SENDCHANGE); }
I won't post the whole unit since since it does other things that aren't relevant but here are the constants and imports for the above code.
//Win32 API calls necesary to raise an unowned processs main window [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] private static extern bool IsIconic(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni); [DllImport("user32.dll", SetLastError = true)] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId); [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); [DllImport("user32.dll")] static extern bool BringWindowToTop(IntPtr hWnd); [DllImport("user32.dll")] private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, Int32 nMaxCount); [DllImport("user32.dll")] private static extern int GetWindowThreadProcessId(IntPtr hWnd, ref Int32 lpdwProcessId); [DllImport("User32.dll")] public static extern IntPtr GetParent(IntPtr hWnd); private const int SW_HIDE = 0; private const int SW_SHOWNORMAL = 1; private const int SW_NORMAL = 1; private const int SW_SHOWMINIMIZED = 2; private const int SW_SHOWMAXIMIZED = 3; private const int SW_MAXIMIZE = 3; private const int SW_SHOWNOACTIVATE = 4; private const int SW_SHOW = 5; private const int SW_MINIMIZE = 6; private const int SW_SHOWMINNOACTIVE = 7; private const int SW_SHOWNA = 8; private const int SW_RESTORE = 9; private const int SW_SHOWDEFAULT = 10; private const int SW_MAX = 10; private const uint SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000; private const uint SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001; private const int SPIF_SENDCHANGE = 0x2;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With