IsIconic返回false时显示主窗口! [英] Show Main Window when IsIconic returns false!

查看:77
本文介绍了IsIconic返回false时显示主窗口!的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这使我发疯,所以对任何可以提供任何帮助的人都非常感谢.

我有一个简单的Windows窗体应用程序,该应用程序始终在后台以隐藏的最小化状态运行.表单的"ShowInTaskbar"属性设置为false,因此没有可见的证据表明该应用程序正在运行.

该计划是,当某人运行应用程序exe时,正在运行的应用程序将恢复为与正在启动的新应用程序相对应的设置(我已经通过使用互斥锁来解决该问题,以知道该应用程序正在运行).

现在是问题所在,将"ShowInTaskbar"选项设置为false(我必须将其设置为false)会导致IsIconic()函数在进程"MainWindow"属性上返回false(或零)没有可用于还原窗口可见性的窗口句柄.

有谁知道我如何使用没有窗口句柄与之关联的流程类对象显示此窗口.我认为通过我拥有的流程对象实例向应用程序发送消息/事件将是一个合适的解决方案,但是我似乎无法在网上找到有关此操作方式的任何信息(可能是在搜索中输入了错误的信息)盒子!!!

我浏览了几页,人们似乎在试图找到一个解决方案,但是提供的所有答案似乎都与ShowWindow(),SetForegroundWindow()等一起使用interop,所有这些都需要我没有的窗口句柄.

就像我说的,非常感谢您的帮助,但是请记住您的解决方案(如果有的话)是我没有窗口句柄.非常感谢

This one is driving me insane so be very grateful for anyone who can help in any way.

I have a simple windows form application that constantly runs in the background in a hidden, minimised state. The ''ShowInTaskbar'' property of the form is set to false so that there is no visible eveidence that the application is running.

The plan is that when someone runs the applications exe the the running app will be restored as apposed to a new one being started (i have dealt with this via use of a mutex to know that the app is runing).

Now here''s the problem, setting the ''ShowInTaskbar'' option to false (which i have to set as false) causes the IsIconic() function to return false (or zero) on the processes ''MainWindow'' property resulting no window handle that i can use to restore the windows visibility.

Does anyone know how I can show this window with a process class object that has no window handle associated to it. I am thinking that sending a message/event to the application via the process object instance i have would be a suitable solution but I cannot seem to find any info on the web as to how this is done (probably typing the wrong stuff in the search box!!!)

I have come accross a few pages where people seem to be trying to find a solution this but all the answers provided seem to use interop with ShowWindow(), SetForegroundWindow() etc all of which require a window handle which I dont have.

As I said, be very grateful for any help, but please remember with your solutions (if any) that I have no window handle. Many thanks

推荐答案

您好,我过去使用此方法来通知应用程序的现有实例它需要显示自身(由于用户正在运行exe)是要发布一条唯一的广播消息,已运行的实例将提取该消息,然后继续向用户显示该消息,因此您无需依赖窗口句柄或查找进程ID.

您已经说过,您已经处理了可以使用互斥锁检测到先前实例正在运行的事实(这可能是检测到此异常的最佳方法).

本地电话定义
Hi, The method I have used in the past to notify an existing instance of an application that it needs to show itself (due to the user running the exe) is to post a unique broadcast message which the already running instance will pickup and then proceed to show itself to the user, therefore you don''t need to rely on window handles or finding process ids.

You''ve already said you''ve handled the fact you can detect a previous instance is running using a mutex (which is probably the best way to detect this).

Native Call definitions
public const int HWND_BROADCAST = 0xffff;
// Create a unique message that you will use for showing the running instance (ie change WM_SHOWME to what you want to call your message.
public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);



当您检测到前一个实例时,只需广播您的唯一消息即可.



When you''ve detected the previous instance, just broadcast your unique message.

// send a message to the currently running instance to jump on top of all the other windows
NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_SHOWME, IntPtr.Zero, IntPtr.Zero);



现在,您的主窗体需要查找并处理此消息,这是通过覆盖WinProc函数来完成的,该函数使您的应用程序可以查看应用程序的所有消息以及广播消息.



Now your main form need to look for this message and handle it, this is done by overriding the WinProc function, which allows your app to view all messages for your app as well as broadcast messages.

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);
}



然后在此函数中,只需检测您的唯一消息并执行代码以显示表单即可.



Then inside this function just detect your unique message and perform the code to show your form.

if (m.Msg == NativeMethods.WM_SHOWME)
{
    // trying to show a new instance, just bring this instance to the fore ground
    WindowState = FormWindowState.Normal;
    TopMost = true;
    TopMost = false;
}




希望这会有所帮助.

附带说明一下,您是否设法从任务切换器"(ALT + TAB)隐藏了应用程序?我只是尝试了一次快速测试,然后按照您的设置在启动时隐藏了窗口,但是它仍然显示在任务切换器中,因此在选择应用程序时就将其置于前台.




Hope this helps.

On a side note, did you manage to hide your application from the ''Task Switcher'' (ALT+TAB)? I just tried a quick test and followed your setting to hide the window on startup, which it did, but it still showed in the task switcher, so when selected the application came to the foreground.


好吧,您再也不应该假设一切都会正常进行,因此,将ShowInTaskbar设置为false时,您不会收到任何Windows消息,而会发现很多其他人也遇到了同样的问题.

但是,我能够找到一种技术,可以使用一种无​​法显示的形式来捕获消息(为希望从控制台应用程序捕获Windows消息的编码人员找到了此技术.)

首先,解决方案1中仍然采用相同的方法来检测先前的实例是否存在并向其发送唯一消息.

下一步是创建一个表单类,该类将捕获所有广播消息并通知您的主表单它需要显示自己.

这是整个类(这是此解决方案中找到的代码的修改版本http://stackoverflow.com/questions/2061167/how-to-receive-the-windows-messages-without-a-windows-form). br/> 此静态表单类将为运行窗口创建一个线程,它重写SetVisibleCore以停止显示窗口,并且当它检测到WM_SHOWME消息将事件触发到主表单时.

Hi, Ok once again you should never assume things are going to work, so with the ShowInTaskbar set to false you don’t get any windows messages, found plenty of others who run into the same issue.

However I was able to find a technique that you can use to trap the message using a none displayable form (found this for coders wanting to capture windows message from console applications).

Firstly the same method to detect if a previous instance exists and sending it a unique message still applies as in solution 1.

The next step is to create a form class that will capture all broadcast messages and notify your main form that it needs to display itself.

Here’s the entire class (it’s a modified version of the code found in this solution http://stackoverflow.com/questions/2061167/how-to-receive-the-windows-messages-without-a-windows-form).
This static form class will create a thread for the window to run in, it overrides the SetVisibleCore to stop the window being displayed, and when it detect the WM_SHOWME message fires an event to your main form.

internal class ShowWindowNotifier : Form
{
    public delegate void ShowWindowDelegate();
    public static event ShowWindowDelegate ShowNotifier = delegate { };
    private static ShowWindowNotifier mInstance;
    public static void Start()
    {
        Thread t = new Thread(runForm);
        t.SetApartmentState(ApartmentState.STA);
        t.IsBackground = true;
        t.Start();
    }
    public static void Stop()
    {
        if (mInstance == null)
            throw new InvalidOperationException("Notifier not started");
        ShowNotifier = null;
        mInstance.Invoke(new MethodInvoker(mInstance.endForm));
    }
    private static void runForm()
    {
        Application.Run(new ShowWindowNotifier());
    }
    private void endForm()
    {
        this.Close();
    }
    protected override void SetVisibleCore(bool value)
    {
        // Prevent window getting visible
        if (mInstance == null)
            CreateHandle();
        mInstance = this;
        value = false;
        base.SetVisibleCore(value);
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == NativeMethods.WM_SHOWME)
            ShowNotifier();
        base.WndProc(ref m);
    }
}



在主窗体构造函数中,您需要做的就是为消息通知者分配一个委托并启动它.



Inside the main forms constructor all you need to do is assign a delegate to the message notifier and start it.

ShowWindowNotifier.ShowNotifier += new ShowWindowNotifier.ShowWindowDelegate(this.ShowMe);
ShowWindowNotifier.Start();



为了获得良好的编码,请在关闭表单时停止通知程序.



For good coding you should stop the notifier when you close the form.

ShowWindowNotifier.Stop();



主表中的委托人必须是线程安全的,因为通知程序正在其自己的线程中运行,因此只需检查是否需要Invoke即可进行处理.



Your delegate in the main form needs to be thread safe as the notifier is running in its own thread, so just checking if an Invoke is required handles this.

delegate void ShowMeDelegate();
public void ShowMe()
{
    if (InvokeRequired)
        Invoke(new ShowMeDelegate(ShowMe));
    else
    {
        // trying to show a new instance, just bring this instance to the fore ground
        WindowState = FormWindowState.Normal;
        FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
        TopMost = true;
        TopMost = false;
    }
}



为了更好地测试此解决方案,因此确信它可以满足您的要求.

我还想出了如何从任务切换器"中删除图标(如果还没有的话),使窗体寄宿生风格为FixedToolWindow,并且没有图标出现,如果这不适合您希望实际窗口显示的方式,则可以在显示窗口时可以轻松更改此设置(如果需要将其隐藏,则可以再次更改).



Have tested this solution more so am confidant it does what you require.

I also figured out how to remove the icon from the ‘Task Switcher’ (if you haven’t already), making the form boarder style FixedToolWindow and no icon appears, if this doesn’t suit how you want the actual window displayed you can easily change this when you go to show the window (and back again if you need to hide it).


这篇关于IsIconic返回false时显示主窗口!的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆