2013-02-28 131 views
3

我试图在我的WinForms UI中显示来自不同进程的系统菜单(包含最小化,还原等)。我知道我需要像GetSystemMenu和TrackPopupMenuEx这样的interop调用,但是我没能使它工作。有人可以提供一个示例代码如何做到这一点?从另一个进程显示系统菜单(使用WinForms,c#)

我发现(对WPF)这个代码片段: Open another application's System Menu

我把它修改成这样的:

const uint TPM_LEFTBUTTON = 0x0000; 
    const uint TPM_RETURNCMD = 0x0100; 
    const uint WM_SYSCOMMAND = 0x0112; 

    [DllImport("user32.dll")] 
    static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); 

    [DllImport("user32.dll")] 
    static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); 

    [return: MarshalAs(UnmanagedType.Bool)] 
    [DllImport("user32.dll", SetLastError = true)] 
    static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

    public void ShowContextMenu() 
    { 
     IntPtr wMenu = GetSystemMenu(ExternalWindowHandle, false); 
     // Display the menu 
     uint command = TrackPopupMenuEx(wMenu, TPM_LEFTBUTTON | TPM_RETURNCMD, 10, 10, ExternalWindowHandle, IntPtr.Zero); 
     if (command == 0) 
      return; 
     PostMessage(ExternalWindowHandle, WM_SYSCOMMAND, new IntPtr(command), IntPtr.Zero); 
    } 

正如在问题的标题所说,我不希望尽量减少一个窗口到系统托盘,我想显示一个系统菜单从另一个进程(窗口)在我选择的位置。几乎和Windows任务栏一样。任务栏(资源管理器)似乎可以在任务栏上右键单击时显示系统菜单。

感谢, 斯特凡

+0

而你发布的代码是...? – Brian 2013-02-28 06:49:24

+0

对不起,我错过了提及,它不起作用。 TrackPopupMenuEx返回0. – 2013-02-28 07:27:32

回答

5

我的代码的工作版本还我检查了MSDN库,我发现,为了使TrackPopupMenuEx方法来工作“ExternalWindowHandle”变量,您通过即窗口该句柄表示需要位于桌面的前台。

MSDN库说以下内容:

“要为通知图标显示上下文菜单,应用程序调用TrackPopupMenu或TrackPopupMenuEx之前当前窗口必须是前景窗口,否则,菜单会。当用户点击菜单或创建菜单的窗口(如果它是可见的)时,不会消失。如果当前窗口是子窗口,则必须将(顶层)父窗口设置为前景窗口。http://msdn.microsoft.com/en-us/library/windows/desktop/ms648003(v=vs.85).aspx

因此,这意味着,当你的窗口是活动之一,因为窗口是不是一个在前台它仅会工作,并在前台,如果你是在Visual Studio将无法正常工作实例调试即视觉工作室不是你的应用程序。

请参阅附上的工作代码示例,请记住,它只会在应用程序窗口是焦点/前景中的应用程序窗口时才起作用。即当您正在调试或使用其他窗口时,TrackPopupMenuEx将始终返回0。

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace WindowsFormsApplication2 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     const uint TPM_LEFTBUTTON = 0x0000; 
     const uint TPM_RETURNCMD = 0x0100; 
     const uint WM_SYSCOMMAND = 0x0112; 

     [DllImport("user32.dll")] 
     static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); 

     [DllImport("user32.dll")] 
     static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); 

     [return: MarshalAs(UnmanagedType.Bool)] 
     [DllImport("user32.dll", SetLastError = true)] 
     static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

     public static void ShowContextMenu(IntPtr appWindow, IntPtr myWindow, Point point) 
     { 
      IntPtr wMenu = GetSystemMenu(appWindow, false); 
      // Display the menu 
      uint command = TrackPopupMenuEx(wMenu, 
       TPM_LEFTBUTTON | TPM_RETURNCMD, (int)point.X, (int)point.Y, myWindow, IntPtr.Zero); 
      if (command == 0) 
       return; 

      PostMessage(appWindow, WM_SYSCOMMAND, new IntPtr(command), IntPtr.Zero); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      ShowContextMenu(new IntPtr(<<put your target window handle here>>), this.Handle, new Point(0, 0)); 
     } 
    } 
} 
+1

感谢您的帮助! – 2013-03-06 10:14:44

相关问题