PDA

View Full Version : làm sao làm mất tác dụng nút X của Form



ducminh002
18-03-2005, 13:13
Mình đang bị vắn đề này, mình ko muốn cho User tác động vào nút X của Form nên mình gán thuộc tính Cancel = 1 trong sự kiện Form_Unload (Cancel AS Integer), nhưng lại bị vắn đề này nữa. Số là trong Project của mình, vì 1 số lý do nên mình ko muốn gán thuộc tính MDI Chirld cho 1 số Form. Như vậy, khi mình gán thuộc tính Cancel = 1 cho 1 Form bất kỳ nào đó thì dẩn đến vắn đề là khi mình tắt (click vào nút X) form chính (MDI FORM) đáng lý ra toàn bộ các Form phải được Unload hết (mình có gán các Sự kiện Unload cho tất cả các Form trong nút X của MDI FORM rồi) nhưng khi mình nhấn Ctrl + Alt + Del thì mình thấy CT của mình vẩn còn đang chạy, thế mới chết cơ chứ. Điều đó chứng tỏ cái Form mình gán thuộc tính Cancel = 1 vẩn cồn bị ME.HIDE. Nên chỉ có Form MDI là UNLOAD thôi, còn cái đó vẩn còn tồn tại nên CT vẩn còn tồn tại Trong Windows.
Mình muốn hỏi là có cách nào ko cho User tắt 1 Form bằng nút X mà khi mình nhấn nút X của Form MDI thì CT của mình được UNLOAD hêt ko?
Rất mopng tin các bạn

dienbaquan
19-03-2005, 22:33
Tui cũng như U, chưa tìm ra API để disable cái nút [X] đó nên phải xài thêm 1 biến đặt trong class: bUnload as boolean
trong Sub Form_UnLoad:
if bUnload = True then
...
else
...
endif

paulsteigel
19-03-2005, 23:06
Tớ mượn tạm code của người khác nhé:
Option Explicit

Private Const SC_CLOSE As Long = &HF060&
Private Const MIIM_STATE As Long = &H1&
Private Const MIIM_ID As Long = &H2&
Private Const MFS_GRAYED As Long = &H3&
Private Const WM_NCACTIVATE As Long = &H86

Private Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type

Private Declare Function GetSystemMenu Lib "user32" ( _
ByVal hWnd As Long, ByVal bRevert As Long) As Long

Private Declare Function GetMenuItemInfo Lib "user32" Alias _
"GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, _
ByVal b As Boolean, lpMenuItemInfo As MENUITEMINFO) As Long

Private Declare Function SetMenuItemInfo Lib "user32" Alias _
"SetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, _
ByVal bool As Boolean, lpcMenuItemInfo As MENUITEMINFO) As Long

Private Declare Function SendMessage Lib "user32" Alias _
"SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long

Private Declare Function IsWindow Lib "user32" _
(ByVal hWnd As Long) As Long

'************************************************* ******************************
' Enables / Disables the close button on the titlebar and in the system menu
' of the form window passed.
'-------------------------------------------------------------------------------
' Return Values:
'
' 0 Close button state changed succesfully / nothing to do.
' -1 Invalid Window Handle (hWnd argument) Passed to the function
' -2 Failed to switch command ID of Close menu item in system menu
' -3 Failed to switch enabled state of Close menu item in system menu
'
'-------------------------------------------------------------------------------
' Parameters:
'
' hWnd The window handle of the form whose close button is to be enabled/
' disabled / greyed out.
'
' Enable True if the close button is to be enabled, or False if it is to
' be disabled / greyed out.
'
'-------------------------------------------------------------------------------
' Example:
'
' Add a form window to your project, and place a button on the form. Add the
' following in the form's code window:
'
' Option Explicit
'
' Private m_blnCloseEnabled As Boolean
'
' Private Sub Form_Load()
' m_blnCloseEnabled = True
' Command1.Caption = "Disable"
' End Sub
'
' Private Sub Command1_Click()
' m_blnCloseEnabled = Not m_blnCloseEnabled
' EnableCloseButton Me.hwnd, m_blnCloseEnabled
'
' If m_blnCloseEnabled Then
' Command1.Caption = "Disable"
' Else
' Command1.Caption = "Enable"
' End If
' End Sub
'
'-------------------------------------------------------------------------------

Public Function EnableCloseButton(ByVal hWnd As Long, Enable As Boolean) _
As Integer
Const xSC_CLOSE As Long = -10

' Check that the window handle passed is valid

EnableCloseButton = -1
If IsWindow(hWnd) = 0 Then Exit Function

' Retrieve a handle to the window's system menu

Dim hMenu As Long
hMenu = GetSystemMenu(hWnd, 0)

' Retrieve the menu item information for the close menu item/button

Dim MII As MENUITEMINFO
MII.cbSize = Len(MII)
MII.dwTypeData = String(80, 0)
MII.cch = Len(MII.dwTypeData)
MII.fMask = MIIM_STATE

If Enable Then
MII.wID = xSC_CLOSE
Else
MII.wID = SC_CLOSE
End If

EnableCloseButton = -0
If GetMenuItemInfo(hMenu, MII.wID, False, MII) = 0 Then Exit Function

' Switch the ID of the menu item so that VB can not undo the action itself

Dim lngMenuID As Long
lngMenuID = MII.wID

If Enable Then
MII.wID = SC_CLOSE
Else
MII.wID = xSC_CLOSE
End If

MII.fMask = MIIM_ID
EnableCloseButton = -2
If SetMenuItemInfo(hMenu, lngMenuID, False, MII) = 0 Then Exit Function

' Set the enabled / disabled state of the menu item

If Enable Then
MII.fState = (MII.fState Or MFS_GRAYED)
MII.fState = MII.fState - MFS_GRAYED
Else
MII.fState = (MII.fState Or MFS_GRAYED)
End If

MII.fMask = MIIM_STATE
EnableCloseButton = -3
If SetMenuItemInfo(hMenu, MII.wID, False, MII) = 0 Then Exit Function

' Activate the non-client area of the window to update the titlebar, and
' draw the close button in its new state.

SendMessage hWnd, WM_NCACTIVATE, True, 0

EnableCloseButton = 0

End Function

'************************************************* ******************************
'
'-------------------------------------------------------------------------------

usermember
20-03-2005, 21:15
Mời bạn ghé thăm Hackforum.org, ở đó có mấy chương trình vừa vô hiệu hóa nút Close, kể cả Alt+F4 nữa, vừa hiển thi tiếng việt trên menu luôn

ducminh002
21-03-2005, 13:49
Đoạn Code này đảm bảo chạy tốt hết trong các trường hợp ko bạn.Minhf sợ bị debug tầm bậy thì mệt à.
1 form mà phải viết biết bao nhiêu đó Code thì căng quá

paulsteigel
21-03-2005, 14:10
Biết trả lời bạn sao giờ!
Bạn chưa lập trình API bao giờ thì phải....
Nếu bạn không dùng API để can thiệp vào System message thì chẳng có cách nào để disable cái nút đó cả.
Bạn đọc lần lượt các chú thích của tác giả thì sẽ hiểu. Tôi không giải thích thêm, vì cái này dùng nhiều trong các dự án của tôi và chưa bao giờ sao (cái này đơn thuần là kỹ thuật Msghook).
Tiểu bối biết thế thôi ạ.

tapsu
22-03-2005, 07:02
Chào,

nếu bạn ngại code trên qúa dài dòng thì có thể làm như sau:

1. Mở 1 Modul và cho đoạn code sau vào
Private Declare Function GetSystemMenu Lib "user32" (ByVal hwnd As Long, ByVal bRevert As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
Private Const MF_BYPOSITION = &H400&
Private Const MF_DISABLED = &H2&

Public Sub DisableX(Frm As Form)
Dim hMenu As Long
Dim nCount As Long
hMenu = GetSystemMenu(Frm.hwnd, 0)
nCount = GetMenuItemCount(hMenu)
Call RemoveMenu(hMenu, nCount - 1, MF_DISABLED Or MF_BYPOSITION)
DrawMenuBar Frm.hwnd
End Sub

2. Gọi Sub trên từ Form bạn muốn bỏ X
Private Sub Form_Load()
DisableX Me
End Sub

chúc thành công

bye

nnh
29-03-2005, 09:07
chỉ có cách dùng api bạn mới có thể vô hiệu hóa nút x đó, tức là gỡ bỏ menu close trên menu hệ thống khi bạn kích chuột phải lên thanh tiêu đề. Ngoài ra khi bạn muốn unload toàn bộ form con trong ứng dụng mdi chỉ cần khai báo một biến đối tượng kiểu form, sau đó cho nó quét qua hết tất cả các form trong thuộc tính form của mdi form, sau đó gọi lệnh unload thông qua một vòng lặp. thế là tất cả form đều được unload.