Cách đóng hộp MsgBox tự động? (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

PhanTuHuong

VBA & VB.NET for Excel & AutoCad
Thành viên danh dự
Tham gia
13/6/06
Bài viết
7,186
Được thích
24,644
Tôi muốn hộp thông báo tự động đóng sau một khoảng thời gian nhất định, không biết có thực hiện được không?

Tôi đã làm đối với UserForm thì ổn. Còn anh MsgBox thì chưa biết thế nào?
 
Có nghĩa là handle trên win 64bits vẫn phụ thuộc vào excel là 32 bít hay 64bits ý anh.

Handle là ID của các thành phần
Có nghĩa là handle trên win 64bits vẫn phụ thuộc vào excel là 32 bít hay 64bits ý anh.

Handle là ID do hệ điều hành tạo ra để nó quản lý. Hệ điều hành 64-bit thì sẽ sinh ra giá trị của Handle lớn trong miền giá trị của LongPtr. Excel hay các phần khác chỉ là khai báo biến có đủ khả năng nhận giá trị Handle thôi. Việc khai báo Long ở môi trường Excel 32, 64-bit vẫn có thể chạy được trong môi trường Windows 64-bit. Nhưng khả năng lỗi sẽ xảy ra nếu Windows 64 ngẫu nhiên sinh một giá trị Hangle lớn hơn khả năng lưu trữ của Long. Vì Excel 2010 trở lên có 2 phiên bản 32,64-bit nên Microsoft định hướng người lập trình VBA dùng LongPtr cho cả phiên bản 32, 64-bit để có khả năng đón nhận Handle nếu cài trên Windows 64-bit mà không bị Overfloat.

GIải thích thêm: mặc dù trong Excel 32-bit bạn tạo Userform nhưng thực chất Excel dùng hàm API của Windows để tạo, vú dụ
FormHandle = CreateWindowEx("ClassName",...)
Như vậy Windows 32-bit thì Handle sinh ra chắc chắn trong phạm vi biến kiểu Long, Windows 64-bit thì Handle sinh ra nằm trong phạm vi LongPtr (LongLong).
Windows 64-bit cho phép cài ứng dụng - Excel 32 hoặc 64-bit. Nên kiểu dữ liệu để nhận Handle nên khai báo LongPtr (LongPtr xét cho cùng chỉ là cái tên kiểu, giá trị của nó/handle như thế nào phụ thuộc vào nơi sinh ra giá trị trong nó - Hệ điều hành).
 
Upvote 0
Nói rõ ra thì rất dài, phức tạp, nên Cu Anh em nói nôm na thế này:
Với ứng dụng 32 bit chạy trên Windows 64 bit, handle và pointer của app dài 32bit vẫn hợp lệ. WOW64 làm nhiệm vụ như 1 layer transparent cho ứng dụng 32 bit.
VD app 32 bit gọi API CreateWindow, lời gọi này không nhảy thẳng đến user32.dll, 1 dll core 64bit của Windows trong System32, mà nó được chuyển hướng tới user32.dll 32bit trong thư mục SysWOW64. Tại user32.dll 32bit, lời gọi CreateWindow sẽ được các dll core của Wow64 chuyển hướng sau khi modify các tham số input, làm tùm lum bà lằng, rồi switch OS mode từ 32 sang 64bit, rồi make call to CreateWindow trong user32.dll 64bit.
Sau khi CreateWindow thành công và swich mode từ 64 về lại 32, WOW64 DLLs sẽ làm nhiệm vụ map internal handle 64bit này sang 1 handle 32bit và return về cho app 32bit.
Còn nhiều, phức tạp lắm, nên em có post cho em gái Ngọc Huyền cái link về WOW64 đó, bà con rãnh thì đọc, hơi nổ đầu nếu chưa có kn, kiến thức về System Coding trong Windows.
Em thì bị gặp mấy vấn đề porting này nhiều rồi, từ thời DOS, qua Win16, rồi Win32. Giờ thì port tiếp qua Win64. Không biết mai mốt còn sống tới Win128 bit hay không, hehe :')
 
Upvote 0
Win 64 tạo handle 64bits thì em nghe và đọc nhiều rồi, và cũng tin phần nào. Nhưng có một điều làm mâu thuẫn nên em hỏi cho rõ hơn thôi.

Một mặt khẳng định là handle là 64bit.
Một mắt khác là khi khai báo api ta dùng longptr. Mà longptr sẽ là 32bits với excel32 bít chạy trên win64. Vậy khác nào lại khẳng định là handle là 32bit.

Nghe cách giải thích về cái wow64 không hiểu hết nghĩa, nhưng phần nào cũng thấy hợp lý cho 2 điều mâu thuẫn ở trên.


Cũng có thể, em đoán thôi. bin gết chế ra win64 , theo lya thuyết là handle sez có giải giá trị vượt long. Nhưng ông ta vẫn khống chế handle trong khoảng long, để có thể tương thích với các phần mềm cũ. bao giờ 2007, 2003 chết thật sự, hay đến khi không còn excel32bit nữa thì handle mới chính thức vượt ra khỏi long.
 
Upvote 0
Tội Bill quá, mấy cái này kêu Excel Team, Office Team ra chứ, Bill có còn code ciếc, quản lý gì nữa đâu :)
 
Upvote 0
Win 64 tạo handle 64bits thì em nghe và đọc nhiều rồi, và cũng tin phần nào. Nhưng có một điều làm mâu thuẫn nên em hỏi cho rõ hơn thôi.

Một mặt khẳng định là handle là 64bit.
Một mắt khác là khi khai báo api ta dùng longptr. Mà longptr sẽ là 32bits với excel32 bít chạy trên win64. Vậy khác nào lại khẳng định là handle là 32bit.

Nghe cách giải thích về cái wow64 không hiểu hết nghĩa, nhưng phần nào cũng thấy hợp lý cho 2 điều mâu thuẫn ở trên.


Cũng có thể, em đoán thôi. bin gết chế ra win64 , theo lya thuyết là handle sez có giải giá trị vượt long. Nhưng ông ta vẫn khống chế handle trong khoảng long, để có thể tương thích với các phần mềm cũ. bao giờ 2007, 2003 chết thật sự, hay đến khi không còn excel32bit nữa thì handle mới chính thức vượt ra khỏi long.

Chính xác là Application 32-bit thì gọi các DLL, OCX 32-bit nên cùng một kiểu giá trị nhé.
 
Upvote 0
Thì dùng phiên bản W (phục vụ unicobe) thay cho phien bản A thôi. Tức dùng MessageBoxTimeoutW
Cho code sau vào 1 Modele riêng, vd. Module3
Mã:
#If VBA7 Then
    Public Declare PtrSafe Function MessageBoxTimeoutW Lib "user32" (ByVal hWnd As LongPtr, _
                                                        ByVal lpText As String, ByVal lpCaption As String, _
                                                        ByVal uType As Long, ByVal wLanguageId As Integer, _
                                                        ByVal dwMilliseconds As Long) As Long
#Else
    Public Declare Function MessageBoxTimeoutW Lib "user32" (ByVal hWnd As Long, _
                                                        ByVal lpText As String, ByVal lpCaption As String, _
                                                        ByVal uType As Long, ByVal wLanguageId As Integer, _
                                                        ByVal dwMilliseconds As Long) As Long
#End If

Function MsgBoxTimeout(ByVal message As String, ByVal timeout As Long, Optional ByVal Title As String = "Message", Optional ByVal flags As VbMsgBoxStyle = vbOKOnly) As VbMsgBoxResult
    MsgBoxTimeout = MessageBoxTimeoutW(0, StrConv(message, vbUnicode), StrConv(Title, vbUnicode), flags, 0, timeout)
End Function

hoặc

Mã:
#If VBA7 Then
    Public Declare PtrSafe Function MessageBoxTimeoutW Lib "user32" (ByVal hWnd As LongPtr, _
                                                        ByVal lpText As LongPtr, ByVal lpCaption As LongPtr, _
                                                        ByVal uType As Long, ByVal wLanguageId As Integer, _
                                                        ByVal dwMilliseconds As Long) As Long
#Else
    Public Declare Function MessageBoxTimeoutW Lib "user32" (ByVal hWnd As Long, _
                                                        ByVal lpText As Long, ByVal lpCaption As Long, _
                                                        ByVal uType As Long, ByVal wLanguageId As Integer, _
                                                        ByVal dwMilliseconds As Long) As Long
#End If

Function MsgBoxTimeout(ByVal message As String, ByVal timeout As Long, Optional ByVal Title As String = "Message", Optional ByVal flags As VbMsgBoxStyle = vbOKOnly) As VbMsgBoxResult
    MsgBoxTimeout = MessageBoxTimeoutW(0, StrPtr(message), StrPtr(Title), flags, 0, timeout)
End Function

Code trong UserForm1 (xóa khai báo các hàm API đang có)
Mã:
Private Sub CommandButton1_Click()
    MsgBoxTimeout "Ch" & ChrW(7841) & "y th" & ChrW(7917) & Chr(10) & _
                    "N" & ChrW(7871) & "u " & ChrW(273) & ChrW(432) & ChrW(7907) & "c s" & _
                    ChrW(7869) & " t" & ChrW(7921) & " t" & ChrW(7855) & "t", _
                    4000, "Thông báo", vbInformation
End Sub
Có cách nào phải chờ hoặc nhấn thoát "MsgBoxTimeout" mới sử dụng được bên ngoài trang tính ,form như "MsgBox" thông thường hay dùng không bác?
 
Upvote 0
Cái flags truyền vào Or thêm cho nó vbSystemModal (0x1000, tương đượng MB_SYSTEMMODAL) hoặc 0x2000 = MB_TASKMODAL (không có hằng VB(A) tương ứng)
 
Upvote 0
Có cách nào phải chờ hoặc nhấn thoát "MsgBoxTimeout" mới sử dụng được bên ngoài trang tính ,form như "MsgBox" thông thường hay dùng không bác?
Nếu bạn kích hoạt MsgBoxTimeout từ UserForm1 như trong tập tin ví dụ thì đương nhiên bạn không thể làm được gì trên trang tính, y như dùng MsgBox.

Nếu bạn kích hoạt MsgBoxTimeout từ 1 code khác vd. từ Button1 đặt trên trang tính thì sửa và thêm vbSystemModal cũng vô ích. Vì nó không có tác dụng. Tại sao? Vì MB_APPLMODAL hay MB_SYSTEMMODAL chỉ có tác dụng khi bạn truyền handle vào thông số đầu tiên hWnd. Hiện nay ta đang truyền 0.

Vậy đơn giản chỉ thay thông số đầu. Vd. thay
Mã:
MsgBoxTimeout = MessageBoxTimeOutW(0, StrPtr(message), StrPtr(Title), flags, 0, timeout)
thành
Mã:
MsgBoxTimeout = MessageBoxTimeOutW(Application.hWnd, StrPtr(message), StrPtr(Title), flags, 0, timeout)

Một khi đã có Application.hWnd thay cho 0 thì chả cần thêm gì cả. Vì lúc đó thì MB_APPLMODAL (vbApplicationModal) là mặc định.
 
Upvote 0
Nếu bạn kích hoạt MsgBoxTimeout từ UserForm1 như trong tập tin ví dụ thì đương nhiên bạn không thể làm được gì trên trang tính, y như dùng MsgBox.

Nếu bạn kích hoạt MsgBoxTimeout từ 1 code khác vd. từ Button1 đặt trên trang tính thì sửa và thêm vbSystemModal cũng vô ích. Vì nó không có tác dụng. Tại sao? Vì MB_APPLMODAL hay MB_SYSTEMMODAL chỉ có tác dụng khi bạn truyền handle vào thông số đầu tiên hWnd. Hiện nay ta đang truyền 0.

Vậy đơn giản chỉ thay thông số đầu. Vd. thay
Mã:
MsgBoxTimeout = MessageBoxTimeOutW(0, StrPtr(message), StrPtr(Title), flags, 0, timeout)
thành
Mã:
MsgBoxTimeout = MessageBoxTimeOutW(Application.hWnd, StrPtr(message), StrPtr(Title), flags, 0, timeout)

Một khi đã có Application.hWnd thay cho 0 thì chả cần thêm gì cả. Vì lúc đó thì MB_APPLMODAL (vbApplicationModal) là mặc định.
Trong trang tính đã được rùi bác, còn trên form khi hiện thông báo mình click vào form thì thông báo lại ẩn vẫn sử dụng được form khi chưa tắt thông báo! Có cách nào khi thông báo bắt buộc phải tắt đi mới sử dụng được form không bác?
 
Upvote 0
Hì hì, thì cậu cứ thử với 1 trong 2 cái value vbSystemModal hay H2000& đi :)
UserForm1.Show thì show UserForm1 với style modal (vbModal), chứ show modeless thì vẫn rờ chạm em Excel thỏa mái, hì hì
 
Lần chỉnh sửa cuối:
Upvote 0
Trong trang tính đã được rùi bác, còn trên form khi hiện thông báo mình click vào form thì thông báo lại ẩn vẫn sử dụng được form khi chưa tắt thông báo! Có cách nào khi thông báo bắt buộc phải tắt đi mới sử dụng được form không bác?
Thôi, làm khác
1. Trong Module trước #If VBA7 Then thì thêm
Mã:
Private Const MB_TASKMODAL = &H2000
2. Sửa thành
Mã:
MsgBoxTimeout = MessageBoxTimeOutW(0, StrPtr(message), StrPtr(Title), flags Or MB_TASKMODAL, 0, timeout)
Tức không dùng Application.hWnd nữa mà thêm MB_TASKMODAL vào flags
 
Upvote 0
Hì hì, thì cậu cứ thử với 1 trong 2 cái value vbSystemModal hay H2000& đi :)
UserForm1.Show thì show UserForm1 với style modal (vbModal), chứ show modeless thì vẫn rờ chạm em Excel thỏa mái, hì hì
Nếu bạn viết: 0x2000 = MB_TASKMODAL thì không nói làm gì.
Nhưng bạn viết
Cái flags truyền vào Or thêm cho nó vbSystemModal (0x1000, tương đượng MB_SYSTEMMODAL) hoặc 0x2000 = MB_TASKMODAL
Mà vbSystemModal không có tác dụng nếu thông số đầu vẫn là 0.
 
Upvote 0
Thì tôi đã nói cậu gì đó thử mà, có chết thằng Tây nào đâu mà đi bắt bẽ ha :)
À, mà còn 1 đống flags của MessageBoxXXXX nữa, ưn đồ cú mèn, tối về em lục lại post lên cho. Sẵng RE xem cái ông MsgBox của Vờ Bờ Ờ này làm cái gì internal
 
Upvote 0
Thôi, làm khác
1. Trong Module trước #If VBA7 Then thì thêm
Mã:
Private Const MB_TASKMODAL = &H2000
2. Sửa thành
Mã:
MsgBoxTimeout = MessageBoxTimeOutW(0, StrPtr(message), StrPtr(Title), flags Or MB_TASKMODAL, 0, timeout)
Tức không dùng Application.hWnd nữa mà thêm MB_TASKMODAL vào flags
Được rồi cám ơn bác nha.
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom