[C#.NET][VB.NET] 用 Win32 API 控制 外部應用程式選單
1.這並不是用SendKey所組成的,所以不管應用程式是否在最上層,都能控制的到。
2.匯入 System.Runtime.InteropServices 及 System.Threading 命名空間
3.選單控制主要由下列三隻API組成
[DllImport("user32.dll", EntryPoint = "GetMenu")]
public static extern int GetMenu(
int hwnd
);
[DllImport("user32.dll", EntryPoint = "GetSubMenu")]
public static extern int GetSubMenu(
int hMenu,
int nPos
);
[DllImport("user32.dll", EntryPoint="GetMenuItemID")]
public static extern int GetMenuItemID(
int hMenu,
int nPos
);
4.GetMenu所指的就是"主選單"工具列,如下圖所示。
而GetSubMenu指的就是"主選單"內的"子選單",由下圖可看到項目有五個"子選單",分別為:檔案(F)、編輯(E)、格式(O)、檢視(V)、說明(H)。
GetMenuItemID則是"子選單"中的"項目"
5.選單API的啟始值是0,GetSubMenu(gm, 0)表示第1個選單
GetSubMenu(gm, 1)表示第2個選單
6.GetMenuItemID用法同如上所示 ,int id = GetMenuItemID(gm, 3),表示第4個項目。
7.完整範例
C#
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
namespace CS_ControlMenu
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private const int WM_COMMAND = 0x111;
[DllImport("user32.dll", EntryPoint = "FindWindow")]
public static extern int FindWindow(
string lpClassName,
string lpWindowName
);
[DllImport("user32.dll", EntryPoint = "GetMenu")]
public static extern int GetMenu(
int hwnd
);
[DllImport("user32.dll", EntryPoint = "GetSubMenu")]
public static extern int GetSubMenu(
int hMenu,
int nPos
);
[DllImport("user32.dll", EntryPoint="GetMenuItemID")]
public static extern int GetMenuItemID(
int hMenu,
int nPos
);
[DllImport("user32.dll", EntryPoint = "PostMessage")]
public static extern int PostMessage(
int hwnd,
int wMsg,
int wParam,
int lParam
);
private void button1_Click(object sender, EventArgs e)
{
//呼叫外部程式
Process.Start(@"C:\windows\system32\notepad.exe");
//等執行程式一下下
Thread.Sleep(100);
//取得外部程式的Handle
int NotepadHwnd = FindWindow("notepad", null);
//取得外部程式的選單Handle
int gm = GetMenu(NotepadHwnd);
//取得第一個子選單Handle
gm = GetSubMenu(gm, 0); //選單的句柄 改變後面的0,就可以得到不同選單的句柄
//取得子選單的ID
int id = GetMenuItemID(gm, 3); //子選單"另存新檔"的ID
//執行子選單
PostMessage (NotepadHwnd, WM_COMMAND, id, 0);
}
}
}
VB
Imports System.Runtime.InteropServices
Imports System.Threading
Public Class Form1
Private Const WM_COMMAND As Integer = &H111
<DllImport("user32.dll", EntryPoint:="FindWindow")> _
Public Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="GetMenu")> _
Public Shared Function GetMenu(ByVal hwnd As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="GetSubMenu")> _
Public Shared Function GetSubMenu(ByVal hMenu As Integer, ByVal nPos As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="GetMenuItemID")> _
Public Shared Function GetMenuItemID(ByVal hMenu As Integer, ByVal nPos As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="PostMessage")> _
Public Shared Function PostMessage(ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'呼叫外部程式
Process.Start("C:\windows\system32\notepad.exe")
'等執行程式一下下
Thread.Sleep(100)
'取得外部程式的Handle
Dim NotepadHwnd As Integer = FindWindow("notepad", Nothing)
'取得外部程式的選單Handle
Dim gm As Integer = GetMenu(NotepadHwnd)
'取得第一個子選單Handle
gm = GetSubMenu(gm, 0) '選單的句柄 改變後面的0,就可以得到不同選單的句柄
'取得子選單的ID
Dim id As Integer = GetMenuItemID(gm, 3)'子選單"另存新檔"的ID
'執行子選單
PostMessage(NotepadHwnd, WM_COMMAND, id, 0)
End Sub
End Class
範例下載:ControlMenu.rar
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET