How to make form topmost to the application only? - c#

I am making excel add-in in which clicking on menu item or toolbar button, Form opened. I have set form's topmost to true but it remain topmost to all applications of windows xp. I just need to remain topmost to Microsoft Excel only.
I have choosed project in Visual Studio 2008, in Excel ->2003.
Please tell me how to do that with any way ........

You can set your Form's owner to be the Microsoft Excel window. In Windows owned windows are always displayed above their owner. Dialogs and things like the search box in Excel are owned windows, which is what keeps them displayed above their owner.
There are a couple of ways you can set a Form's parent:
The Form.Owner property (although the owner has to be another form)
Use the Form.Show(IWin32Window owner) overload. (See this blog post for how translate an window handle to an IWin32Window).
Use SetWindowLong() with the GWLP_HWNDPARENT parameter.
Use ShowDialog() as Mikael Svenson suggested.
This does require you to know the Excel applications window handle.

[Edit - changed code]
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
void func()
{
Form1 f = new Form1();
SetParent(f.Handle, (IntPtr)ThisAddIn.ExcelApplication.Hwnd);
f.Show();
}

Related

SetForegroundWindow method sometimes does not hide start menu

I have a Windows form with no border that is set to maximized in order to make it look "fullscreen". When I open my fullscreen form in my C# app I call the following code...
[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(int hWnd);
With the handle I get from the Windows forms api by calling...
ScreenScrape.SetForegroundWindow(Handle.ToInt32());
When the "Shown" event is raised.
The only problem is sometimes I get the expected result (a fullscreen app with nothing in front of it) and sometimes I get this...
If i click anywhere on my Windows form and its embedded browser I see this...
Another developer suggested programmatically clicking at a known location Say 10,10 but that seems like a hack. Any idea what might be happening here?

Hide parent window, but show child window

I'm working on an application that should do the following on start-up:
Connect to an external application using COM (AutoCAD).
Send message to the application to run some DLL code (opens a window).
Hide AutoCAD's window, but keep the DLL's window visible.
I've successfully completed the first 2 steps, but the third is giving me some issues.
I do not know if it is possible to make a child window visible while it's parent is not visible. Every time that I make the child visible or make it the top most window, AutoCAD becomes visible as well.
My objective is to run my DLL code, but keep AutoCAD running in the background, completely invisible to my users. The DLL must be loaded, through AutoCAD, because it allows me to work with AutoCAD's .NET interface as opposed to COM.
In any case, I'm curious if what I'm trying to do is possible, perhaps through some Windows API calls or perhaps something in .NET.
PS: I'm unsure if this window relationship is really a parent-child one. I'm assuming it is though because my window belongs to the AutoCAD application instance due to the DLL loading.
Any help is greatly appreciated. Thanks! :)
EDIT:
DLL Code to create a window.
//CommandMethod is an AutoCAD attribute for entering into the DLL. This code is called
//when the user attempts the command "AUTOCADCOMMANDNAME" or can be done by simulating
//the command programmatically.
[CommandMethod("AUTOCADCOMMANDNAME", CommandFlags.Session)]
public void CommandEntry()
{
MainWindow mainWin = new MainWindow();
mainWin.ShowDialog();
}
Main Application Code
public static void Main()
{ //Use a utility class to create a connection to AutoCAD via COM
AcadApplication acadApp = ACUtil.GetAcadInstance(out createdNewInstance);
acadApp.Visible = false;
//Irrelevant code omitted...
acadApp.ActiveDocument.SendCommand("AUTOCADCOMMANDNAME");
acadApp.Quit(); //Exit AutoCAD application
//Note: doesn't quit until mainWin closes because of ShowDialog()
}
Can't be done. Parent windows control child window visibility.
Your best alternative is to make the DLL window a top-level window (but owned by the AutoCAD window).
Note that the DLL window will still be part of the AutoCAD thread.
What you want can be achieved, despite what others may think. You just need to think about the problem in a different way. Don't think about parent and child Windows... instead, think about a splash screen Window.
Typically, splash screens appear before the main application Window, but does that make them the parent? No, it doesn't. Normally, they'd be closed after the main Window has opened, but there is no reason why you couldn't hide it instead of closing it.
To find out how to do this in WPF, please refer to my answer from the How to open a child Window like a splash screen before MainWindow in WPF? question, here on Stack Overflow. Extending that answer a little bit, I should point out that you won't need to use a Timer. Instead of the code from the linked page, you could do something like this:
private void OpenMainWindow()
{
autoCadWindow.Visiblity = Visibility.Collapsed;
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
Haha! I found it!
So, I ended up calling the SetWindowPos function in the Windows API and supplied the handle for AutoCAD window. I did this inside my main application:
[DllImport("User32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int w, int h, uint flags);
public const int SWP_HIDEWINDOW = 0x0080;
public static void Main()
{
//...Setup AutoCAD...
//Change window size and hide it before calling to open mainWin inside the DLL.
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 0, 0, 0, 0, SWP_HIDEWINDOW);
//Display mainWin by entering the DLL.
acadApp.ActiveDocument.SendCommand("AUTOCADCOMMANDNAME");
//Terminate application as before...
}
Basically I'm telling the AutoCAD window to hide by modifying the HWND directly. I also set the dimensions to width=0 and height=0 which causes the window to take up the minimum size possible. Unfortunately, the window will flicker once, but for my purposes, that is negligible. If anyone can find a way to remove the flicker, that would be great! :)
EDIT: When using SetWindowPos, Windows tends to remember the values entered for the next time that application window is shown. This means that if not restored properly, then the next time the user opens AutoCAD manually, it will have the coordinates of 0,0 and the minimum width/height.
To change that behavior, it is necessary to obtain the window information. For my program, I used GetWindowRect obtain the original settings. Before closing my program, I restored those settings using SetWindowPos. See the code below for details:
First, import necessary WINAPI functions and structs:
[DllImport("User32.dll")]
static extern bool GetWindowRect(IntPtr hwnd, out RECT rect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Obtain original settings before modifying window:
RECT originalRect;
GetWindowRect(new IntPtr(acadApp.HWND), out originalRect);
Modify the window to hide (and resize):
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 0, 0, 0, 0, SWP_HIDEWINDOW);
Restore original settings before quitting:
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1),
originalRect.Left,
originalRect.Top,
originalRect.Right - originalRect.Left,
originalRect.Bottom - originalRect.Top, 0);

this.TopMost = true not working?

I'm very new to C# and still trying to get my head round it (with help of some very patient friends).
I have an issue with setting a new windows form's TopMost property to true. I have two (almost) identical forms; 1 which works OK and one which doesn't.
Both of the forms have the TopMost property set to true.
Form1 shows the window and when I try to click behind it, the form flashes a few times and issues a windows beep.
Form2 also shows the form but when I click behind it, the form greys out (or loses focus) and I can click away on the main form.
I've searched for an answer to this issue and found an answer which suggested putting this.TopMost = true; in the form's load event but that didn't work.
The only thing I have changed which may or may not have had an effect is that Form1 was created with .NET 4.5 set in the properties and before creating Form2, I changed this to .NET 3.5 (client profile). I've tried changing it back but it hasn't helped. Before I delete and create Form2 again, does anyone have any ideas?
Many thanks in advance.
(If you need any more information, please just let me know)
TopMost is a property that is used to make sure one window is always shown above all others within an application. Microsofts example was a find and replace tool.
The difference you are finding is that Form1 was created as a modal dialog through the use of ShowDialog. Show dialog makes sure that your form must be closed before all other windows in the application can be used again. For example; using a form to gain user data to enter into a parent forms database.
Show is used when you don't mind if your user has finished with their dialog or not, such as allowing your user the chance to use some utility (e.g timer, stopwatch) that will assist within the main function of a program.
The only visual difference I can think of when using different .Net frameworks, is different windows dialogs such as the OpenFileDialog, that have been updated throughout the framework
It may help you;
frm.TopLevel = true;
frm.TopMost = true;
This link from Microsoft confirm that could be a Bug in Windows 7 and Windows Server 2008 R2 I've faced it in a Windows 7 Embedded system and the provided patch fix the problem so please consider to take a look :)
http://support.microsoft.com/kb/2587473/en-us
Hope it help!
The DIY-way to do it - works 100%!
public static class User32
{
public const int SW_HIDE = 0;
public const int SW_SHOW = 5;
public const int SW_SHOWNORMAL = 1;
public const int SW_SHOWMAXIMIZED = 3;
public const int SW_RESTORE = 9;
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool AllowSetForegroundWindow(uint dwProcessId);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
User32.AllowSetForegroundWindow((uint)Process.GetCurrentProcess().Id);
User32.SetForegroundWindow(Handle);
User32.ShowWindow(Handle, User32.SW_SHOWNORMAL);
I hat a similar problem in my solution. After using the overloaded Show-function it worked:
frm.TopLevel = true;
frm.TopMost = true;
frm.Show(this)
Add the following code in the Shown event:
this.TopMost = true;
this.Focus();
this.TopMost = true;

C# screensaver: configuration dialog modal to provided HWND

I am working on a C# XNA screensaver kit and so far, everything is in place except for the configuration dialog which must be modal to the Screen Saver Settings dialog provided by windows ("/c:<hwnd>" argument).
My benchmark is Vistas builtin 3D Text screensaver - my code shall provide the same features and regarding the configuration dialog, 3D Text displays fully modal to the Screen Saver Settings dialog and when clicking Screen Saver Settings dialog, the dialogs blink without accepting the click.
I have tried the method of wrapping the HWND with a IWin32Window as suggested by Ryan Farley, but even though my dialog displays on top of the Screen Saver Settings dialog, the controls in Screen Saver Settings dialog still can be clicked.
So do I need some exotic Win32API calls to inform the parent dialog that it has been modalized or does a more clean solution exist?
Try calling the SetParent API function.
Actually, it turned out that the HWND provided by windows to the screensaver is a child of the settings dialog, so by calling GetParent on the HWND, I get an HWND that represents the dialog.
Today is the day that I wrote my first question on stackoverflow.com and answered the first question.
I had the same problem. Additionally I was not able to directly hook a dialog to a foreign window with .NET. Therefore I supply a work around to hook a dialog to the parent of a given window handle:
public class CHelpWindow : Form
{ // this class hooks to a foreign window handle and then it starts a
// modal dialog to this form; .NET seems not to be able to hook a dialog
// to a foreign window handle directly: therefore this solution
// retrieves the parent window of the passed child
[DllImport("user32.dll")]
private static extern IntPtr GetParent (IntPtr hWndChild);
// changes the parent window of the passed child
[DllImport("user32.dll")]
private static extern IntPtr SetParent
(IntPtr hWndChild, IntPtr hWndNewParent);
// --------------------------------------------------------------------
public CHelpWindow (long liHandle)
// this constructor initializes this form and hooks this form to the parent
// of the passed window handle; then it prepares the call to create the
// dialog after this form window is first shown in the screen.
{
// removing the system title of the window
FormBorderStyle = FormBorderStyle.None;
// the dialog will be created when this form is first shown
Shown += new EventHandler (HelpWindow_Shown);
// hooking to the parent of the passed handle: that is the control, not
// the tab of the screen saver dialog
IntPtr oParent = GetParent (new IntPtr (liHandle));
SetParent (Handle, oParent);
}
// --------------------------------------------------------------------
private void HelpWindow_Shown (object oSender, EventArgs oEventArgs)
// this function is called when the form is first shown; now is the right
// time to start our configuration dialog
{
// positioning this window outside the parent area
Location = new Point (-100, -100);
// reducing the size
Size = new Size (1, 1);
ClientSize = new Size (1, 1);
// creating the dialog
CKonfiguration oConfiguration = new CKonfiguration ();
// starting this dialog with the owner of this object; because this
// form is hooked to the screen saver dialog, the startet dialog is
// then indirectly hooked to that dialog
oConfiguration.ShowDialog (this);
// we don not need this object any longer
Close ();
}
}
After extracting your handle from the command line
/c:####
you create your Dialog by
CHelpWindow oHelpWindow = new CHelpWindow (liHandle);
oHelpWindow.ShowDialog ();
Reimer

Determine Whether Program is the Active Window in .NET

I have a C#/.NET app and I want to implement the following behavior:
I have a popup menu. Whenever the user clicks on anything within the application that is not the popup menu, I want the popup menu to close.
However, whenever a user is not in the application I don't want anything to happen.
I'm trying to manage this through the LostFocus event, but I'm having trouble determining whether my application is the active window. The code looks something like this.
private void Button_LostFocus(object sender, System.EventArgs e)
{
if (InActiveWindow()) {
CloseMenu()
}
else {
// not in active window, do nothing
}
}
What I need to know is how to implement the InActiveWindow() method.
You could P/Invoke into GetForegroundWindow(), and compare the HWND returned to the application's form.Handle property.
Once you have the handle, you can also P/Invoke GetAncestor() to get the root owner window. This should be the handle of your application's main, startup window, if this is in your application.
I stumbled upon your question while working on a project and based on Reed Copsey's answer, I wrote this quick code which seems to do the job well.
Here's the code:
Public Class Form1
'''<summary>
'''Returns a handle to the foreground window.
'''</summary>
<Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetForegroundWindow() As IntPtr
End Function
'''<summary>
'''Gets a value indicating whether this instance is foreground window.
'''</summary>
'''<value>
'''<c>true</c> if this is the foreground window; otherwise, <c>false</c>.
'''</value>
Private ReadOnly Property IsForegroundWindow As Boolean
Get
Dim foreWnd = GetForegroundWindow()
Return ((From f In Me.MdiChildren Select f.Handle).Union(
From f In Me.OwnedForms Select f.Handle).Union(
{Me.Handle})).Contains(foreWnd)
End Get
End Property
End Class
I didn't have too much time to convert it to C# as I'm working on a project with a deadline in 2 days but I believe you can quickly do the conversion.
Here is the C# version of the VB.NET code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
///<summary>Gets a value indicating whether this instance is foreground window.</summary>
///<value><c>true</c> if this is the foreground window; otherwise, <c>false</c>.</value>
private bool IsForegroundWindow
{
get
{
var foreWnd = GetForegroundWindow();
return ((from f in this.MdiChildren select f.Handle)
.Union(from f in this.OwnedForms select f.Handle)
.Union(new IntPtr[] { this.Handle })).Contains(foreWnd);
}
}
}
It seems like the biggest reason this is tricky is because the popup loses focus before the main form is deactivated, so the active window will always be in the application at the time of this event. Really, you want to know whether it will still be the active window after the event is over.
You could set up some kind of scheme where you remember that a popup is losing focus, set aside the fact that you will need to close it, and in the LostFocus or Deactivate event of the application's main form cancel the note that tells you you need to close it; but the problem is when will you process the note?
I'm thinking it might be easier, at least if the popup is a direct child of the main form (which I suspect in your case it may be) to hook the Focus or maybe even Click event of the main form and use it close the popup if it is open (perhaps by scanning its list of child forms for any that implement an ICloseOnLostFocus interface, so that the popup will have a chance to participate in the decision and do anything else it needs to do).
I wish I knew of a better document explaining what all these events actually mean and how they are sequenced with respect to one another, MSDN leaves a lot to be desired in describing them.

Categories

Resources