PDA

View Full Version : سوال: فراخوانی Handle از آیتم ها منوی سیستمی



ROSTAM2
چهارشنبه 16 آذر 1401, 22:48 عصر
سلام.

من با توابع API و این کد همین کد آی.دی آیتم منو رو گرفتم ولی تابع GetSubMenu (https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsubmenu)درست عمل نمی کنه!
مشکل کد من کجاست؟!

توابع API:

Declare Function GetMenuItemCount Lib "user32" (hMenu As IntPtr) As Integer
Declare Function GetMenuItemID Lib "user32" (hMenu As IntPtr, nPos As Integer) As Integer
Declare Function GetSubMenu Lib "user32" Alias "GetSubMenu" (
ByVal hMenu As IntPtr,
ByVal nPos As Integer) As Integer


کدهای من:

Dim Count As Integer = GetMenuItemCount(hMenu)
Dim MenuID As Integer = 0
Dim MenuHandle As Integer = 0
For i = 0 To Count - 1
MenuID = GetMenuItemID(hMenu, i)
MenuHandle = GetSubMenu(hMenu, i)
Dim Expr As String = String.Format("{0}) {1}/{2}", hMenu, MenuHandle, MenuID)
Debug.Print(Expr)
Next

ROSTAM2
پنج شنبه 17 آذر 1401, 07:51 صبح
سلام.

این منویی که من Handle اون رو می گیرم (hMenu) یک منو از MainMenu در ریسورس dll هست و بصورت Popup یا همون ContextMenu فراخوانی می شه.
154335

ROSTAM2
پنج شنبه 17 آذر 1401, 19:21 عصر
سلام مجدد.
من از طریق WndProc برای PopupMenu به نتیجه نرسیدم و از روشی که بصورت اصولی هست استفاده کردم (متاسفانه :لبخند:)

برای نمایش منو بصورت Popup یا همون ContextMenu از تابع TrackPopupMenu از توابع API استفاده می شه:

Private Declare Function TrackPopupMenu Lib "user32" (
ByVal hMenu As Long,
ByVal wFlags As Long,
ByVal X As Long,
ByVal Y As Long,
ByVal nReserved As Long,
ByVal hwnd As Long,
ByVal lprc As Long) As Integer


حالا منو از هرکجا اومده باشه چه ریسورس یک DLL یا از خود پروژه Handle از اون نیاز هست و برای برگردوندن آی.دی آیتم کلیک شده پارامتر ورودی wFlags باید TPM_RETURNCMD ست بشه که آی.دی رو برگردونه:

Private Const TPM_RETURNCMD = &H100&


برای استفاده از تابع TrackPopupMenu من یک تابع دیگه ساختم که اون ورودی رو بصورت پیشفرض داره و با کلیک روی آیتم های منو آی.دی آیتم رو بر می گردونه و اگر آیتمی انتخاب نشده باشه 0 بر می گردونه و می شه بعد از استفاده از این تابع مشروط بر اینکه آی.دی بیشتر از صفر باشه رویداد یا دستورات ما اجرا بشه:

Public Function TrackPopupMenu(hMenu As IntPtr,
ByVal p As System.Drawing.Point,
ByVal hwnd As Long) As Integer
Return TrackPopupMenu(hMenu, TPM_RETURNCMD, p.X, p.Y, 0, hwnd, 0)
End Function


این هم برای استفاده از تابع و اجرای دستور بعد از کلیک آیتم های منو که طبق آی.دی مد نظرتون می تونید براش دستور بنویسید:
در رویداد MouseUp از شیء:

Private Sub Parent_MouseUp(sender As Object, e As MouseEventArgs) Handles Parent.MouseUp
Dim MenuID As Integer = 0
If e.Button = MouseButtons.Right Then
MenuID = rs.TrackPopupMenu(PopupMenu, Control.MousePosition, CType(sender, Control).Handle)
If MenuID > 0 Then
MsgBox(MenuID.ToString)
End If
End If
End Sub

ROSTAM2
جمعه 18 آذر 1401, 09:34 صبح
سلام.
و بالاخره Finally:

گرفتن آی.دی آیتم منوی کلیک شده توسط WndProc بدون خطا:

Public Const WM_MENUSELECT = &H11F

Protected Overrides Sub WndProc(ByRef m As Message)
Static a As Integer = 0
Static MenuID As Long = 0
If m.Msg = WM_MENUSELECT And m.LParam <> hSysMenu Then
If m.LParam Then
MenuID = m.WParam.ToInt64 And &HFFFF&
RaiseEvent Selected(MenuID)
Else
If MenuID > 0 Then
RaiseEvent Clicked(MenuID)
MenuID = 0
End If
End If
ElseIf m.Msg = WM_MENUSELECT Then
MenuID = 0
End If
MyBase.WndProc(m)
End Sub


hSysMenu منوی سیستمی فرم هست که از طریق تابع GetSystemMenu از API مقداردهی شده است.

Declare Function GetSystemMenu Lib "user32" Alias "GetSystemMenu" (
ByVal hwnd As Long,
ByVal bRevert As Boolean) As Long


154338