Thảo luận mở rộng về "Useful functions - Các hàm hữu ích" của Lê Văn Duyệt (1 người xem)

Liên hệ QC

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

ndu96081631

Huyền thoại GPE
Thành viên BQT
Super Moderator
Tham gia
5/6/08
Bài viết
30,703
Được thích
53,974
Mình vào topic này:
Useful functions - Các hàm hữu ích
Của tác giả Levanduyet
Quả đúng hầu hết các hàm đều rất hửu ích. Tuy nhiên mình cảm thấy cần phải cải tiến lại rất nhiều ---> Gần 80% các hàm ấy mình nghĩ có thể rút gọn lại, thậm chí có hàm mình rút gọn lại chỉ còn đúng 1 dòng, ví dụ
PHP:
Function FileExists(fname) As Boolean
  FileExists = Dir(fname) <> ""
End Function
hoặc
PHP:
Function InRange(rng1, rng2) As Boolean
  On Error Resume Next
  InRange = Union(rng1, rng2).Address = rng2.Address
End Function
Đây chỉ là nhận định cá nhân (chưa chắc chính xác) nhưng cũng rất hào hứng, định vào viết bài trao đổi nhưng đáng tiếc topic ấy đã bị khóa
Mình nghĩ dạng bài này nên để ở dạng "mở" vì nhiều ý kiến khác nhau biết đâu sẽ tìm ra được giải pháp tốt hơn
(Chỉ với tấm lòng muốn học hỏi, nếu có gì không phải xin các bạn bỏ qua cho)
 
Khai báo các đối số cũng như sử dụng kiểu giá trị trong hàm

Việc mở mục "Trao đổi góp ý" như thế này là cần thiết để mọi người cùng trao đổi đưa ra giải pháp tốt nhất. Vừa mang tính hoạc thuật vừa mang tính thực dụng.

Em cũng xin góp ý nhỏ về việc khai báo các đối số cũng như sử dụng kiểu giá trị trong hàm.

Mã:
Function FileExists(fname) As Boolean
  FileExists = Dir(fname) <> ""
End Function

Nên khai báo như sau:
Mã:
Function FileExists([COLOR="Blue"]Byval fname As String[/COLOR]) As Boolean
  FileExists = Dir(fname) <> ""
End Function

Trong VB, nếu khai báo biến tham số (fname) như thế này
Function FileExists(fname) As Boolean

VB sẽ hiểu là (tương đương với khai báo):
Function FileExists(Byref fname As Variant) As Boolean

+ Vấn đề ByVal, ByRef:
Với khai báo Byref , biến tham số sẽ nhận giá trị khi thoát khỏi hàm, nó có thể nhận giá trị ngẫu nhiên trong vùng nhớ mà người dùng không kiểm soát được (không phải lúc nào cũng xảy ra). Sẽ rất nguy hiểm nếu chúng ta vô tình sử dụng ByRef với biến fname , và các dòng lệnh sau chúng ta sử dụng lại biến này, khi mà có thể giá trị của nó đã không còn nguyên như trước.

Như vậy, nếu biến tham số không có nhu cầu nhận giá trị trả về thì nên khai báo là ByVal

Ví dụ sau sẽ cần dùng đến ByRef

Mã:
Function GetListFiles(ByVal Path As String, ByRef ListFiles) As Long
    Dim FileName As String
    GetListFiles = 0
    FileName = Dir(Path & "\*.*", vbArchive) 'FindFirst
    While FileName <> "." And FileName <> ".." And FileName <> "" 'Test file is valid
        GetListFiles = GetListFiles + 1 'Count list
        ReDim Preserve ListFiles(GetListFiles) As String 'Increasing array
        ListFiles(GetListFiles) = FileName
        FileName = Dir 'FindNext file
    Wend
    
End Function
'-----------------------------------------------------------------
Sub Test()
    Dim ListFiles() As String
    Dim FileCount As Long, I As Long
    
    FileCount = GetListFiles("D:", ListFiles())
    If FileCount > 0 Then
        For I = 1 To FileCount
            Cells(I, 1).Value = ListFiles(I) 'Write the file name to sheet, from row 1 to FileCount
        Next I
    End If
    
End Sub

Chúng ta có thể khai báo hàm tương đương như sau:
Function GetListFiles(ByVal Path As String, ListFiles) As Long 'Không có ByRef

Nếu khai báo là
Function GetListFiles(ByVal Path As String, Byval ListFiles) As Long 'Hàm sẽ chạy lỗi, bởi ListFiles không nhận được giá trị.

Qua ví dụ về hàm GetListFiles() chúng ta thấy khi viết hàm cần sử dụng khai báo thật chuẩn: khi nào thì dùng ByVal, ByRef
Đọc qua hàm người ta phải thấy được mục đích của hàm, mục đích được thể hiện từ tên biến, tên hàm, khai báo. Cố gắng dùng đúng, dùng đủ.
Khi viết một hàm, cố gắng nhận tối đa thông tin từ nó. Thông tin được trả về từ tham số, từ hàm.

+ Vấn đề kiểu giá trị Variant
Nếu khai báo biến tham số (fname) như thế này
Function FileExists(fname) As Boolean có nghĩa là VB đã gán kiểu biến tham số là Variant. Kiểu giá trị này giúp cho người dùng đơn giản hoá vấn đề, dùng cho các trường hợp với các giá trị khác kiểu. Tuy nhiên nếu người dùng thực sự không có mục đích khai thác biến kiểu Variant mà lại dùng nó thì rất lãng phí. Ứng dụng của bạn sẽ phải sử dụng một khối hới lớn-->Tốc độ chạy chậm-->lãng phí năng lực của chip.
Các hàm trong VB, VBA các biến tham số phần lớn dùng kiểu Variant vì họ có chủ đích. Ví dụ hàm SUM, ta có thể dùng
=SUM(1,2)
=SUM(A1, A2)
=SUM(A1:A10)
Nhìn vào đối số thứ nhất, khi thì là một số, khi thì là một ô, khi thì là một vùng, bản chất, biến tham số thứ nhất là kiểu Variant.

Khai thác biến Variant chúng ta sẽ bàn sâu ở topic khác.

Trong bài viết này, tôi chỉ muốn nhấn mạnh, chúng ta không dùng Variant khi chúng ta biết chắc chỉ dùng kiểu giá trị String hay giá trị cụ thể nào đó.

Tóm lại, thay vì dùng khai báo hàm
Function FileExists(fname) As Boolean

Chúng ta nên dùng
Function FileExists(ByVal fname As String) As Boolean
 
Lần chỉnh sửa cuối:
Cảm ơn TuanVNUNI về các kiến thức byRef, byVal mà bấy lâu nay tôi vẫn còn nhiều lúng túng
Nói như vậy thì hàm:
PHP:
Function InRange(rng1, rng2) As Boolean
...
...
End Function
Có phải nên ghi thế này:
PHP:
Function InRange(byVal rng1 As Range, byVal rng2 As Range) As Boolean
...
...
End Function
hay không?
Tôi thường thấy người ta ghi thế này:
PHP:
 Function InRange(rng1 As Range, rng2 As Range) As Boolean
 ...
 ...
 End Function
Xin hỏi: Có gì không ổn? rng1rng2 đã chỉ định chính xác thuộc biến RANGE rồi còn gì?
 
Lần chỉnh sửa cuối:
Thảo luận về 1 số hàm khác:
----------------------------------------------------------------------------------------------------
1> Hàm FileNameOnly
Tôi nghĩ chỉ cần dùng InSrtRev là đủ, không cần dùng đến vòng lập chi cho mất công
----------------------------------------------------------------------------------------------------
2> Hàm RangeNameExists
Có thể kiểm tra bằng cách tìm INDEX của nó. Ví dụ:
PHP:
Function RangeNameExists(nname As String) As Boolean
  On Error Resume Next
  RangeNameExists = ActiveWorkbook.Names(nname).Index
End Function
Vậy cũng không cần dùng đến vòng lập luôn
----------------------------------------------------------------------------------------------------
3> Hàm WorkbookIsOpen
Duyệt viết hàm như sau:
PHP:
Private Function WorkbookIsOpen(wbname) As Boolean
'   Returns TRUE if the workbook is open
    Dim x As Workbook
    On Error Resume Next
    Set x = Workbooks(wbname)
    If Err = 0 Then WorkbookIsOpen = True _
        Else WorkbookIsOpen = False
End Function
Tin chắc rằng hàm này chẳng bao giờ làm việc chính xác nếu như Workbook cần kiểm tra đang khởi động trên 1 session khác ---> Vụ này cả thế giới họ cũng đăng thắc mắc mà chưa tìm thấy câu trả lời
Không biết TuanVNUNI có ý kiến gì không? Nếu dùng API liệu có thể giải quyết được vấn đề không nhỉ?
-------------------------
Nói thêm: Khi Workbook được khởi động trên 1 session khác thì trong cửa sổ TaskManager ta sẽ nhìn thấy cùng 1 lúc 2 tiến trình Excel.exe (thay vì chỉ có một)
 
To: All,

Rất cám ơn mọi người về việc góp ý.
Như topic tôi có giải thích tại sao tôi đưa ra Thư viện mã lập trình và mọi người cũng đã đồng ý.

phantuhuong đã viết:
Nếu không nhầm thì phần lớn các hàm đó đều là do bác Duyệt sưu tầm bác Tuấn ạ.
Cái này xin trả lời là sưu tầm và tổng hợp (tuỳ từng trường hợp)

Tôi muốn các đoạn mã đưa vào Thư viện mã lập trình sẽ dễ hiểu đối với người áp dụng. Chính vì vậy tôi sẽ vẫn giữ nguyên bản và sẽ đưa thêm các góp ý rút ngắn của các bạn. (Rút gọn như Anh Tuấn tôi đã biết nhưng cần phải chỉnh một tí).

Xin các bạn tiếp tục đóng góp ý kiến tại đây.
Xin cám ơn.

Lê Văn Duyệt
 
Lần chỉnh sửa cuối:
Theo tôi, nói một cách đơn giản thì như thế này:
Khai báo biến kiểu ByVal (By Value) có nghĩa là các thay đổi của biến này chỉ có giá trị sử dụng trong riêng một thủ tục. Giá trị ban đầu của biến vẫn được lưu lại, kết thúc thủ tục biến sẽ trả về giá trị ban đầu.

Khai báo biến kiểu ByRef (By Reference) thì ngược lại. Khi kết thúc thủ tục, nếu giá trị của biến bị thay đổi thì biến sẽ nhận giá trị mới này.

Thử ví dụ sau bạn sẽ thấy sự khác nhau giữa ByVal và ByRef.
Tạo hai thủ tục như sau:
PHP:
Sub Test()
Dim MyNumber As Integer
MyNumber = 10
Call IncreaseMyNumber(MyNumber)
MsgBox (MyNumber)
End Sub
PHP:
Private Sub IncreaseMyNumber(ByRef MyNumber As Integer)
MyNumber = MyNumber + 1
End Sub
Chạy thủ tục Test(), kết quả hiển thị trên MsgBox là 11
Thay đổi cách khai báo biến MyNumber trong thủ tục IncreaseMyNumber từ ByRef thành ByVal
PHP:
Private Sub IncreaseMyNumber(ByVal MyNumber As Integer)
MyNumber = MyNumber + 1
End Sub
Chạy lại thủ tục Test(), kết quả hiển thị trên MsgBox là 10

Khai báo ByRef khi kết thúc thủ tục biến MyNumber sẽ nhận giá trị mới (MyNumber + 1 = 11)
Khai báo ByVal khi kết thúc thủ tục biến MyNumber sẽ nhận giá trị cũ (MyNumber = 10)
 
Cũng tranh thử SPAM vài câu.

Mình thì điều đầu tiên viết code là tường minh.

Rất không ưa các hàm người dùng hay macro mà không có Option Explicit
Nhiều lúc thấy ngại & bỏ qua luôn.
(Kiểu Dim i As Long cũng dị ứng với mình luôn.. . .Khà, khà. . )

Thật tình cũng chưa rành rẽ lắm vê ByVal hay ByRef nên hiếm xài. Chỉ xài khi nghiền ngẫm kỹ là cần xài nó.

Mình hay xài lại biến trong 1 thủ tục thôi. Không mấy khi xài biến từ thủ tục này chuyển sang thủ tục khác.

(Giống như không dám đụng đến con dao hai lưỡi chút nào) . Mình cảm giác rằng xài thứ này còn tốn nhiều công sức để bẫy lỗi, điều kiện này nọ; Nên khai báo quách 1 biến mới xài trong thử tục đó cho rồi.

Quan trọng với mình là, vài năm sau cần đọc lại thì vẫn hiểu nhanh gần như lúc thoát thai ra nó lúc này.

Tiết kiệm thời gian với mình là ưu tiên hàng đầu; Còn mấy năm sống nữa đâu, các bạn!
 
Mình vào topic này:
Useful functions - Các hàm hữu ích
Của tác giả Levanduyet
Quả đúng hầu hết các hàm đều rất hửu ích. Tuy nhiên mình cảm thấy cần phải cải tiến lại rất nhiều ---> Gần 80% các hàm ấy mình nghĩ có thể rút gọn lại, thậm chí có hàm mình rút gọn lại chỉ còn đúng 1 dòng, ví dụ
PHP:
Function FileExists(fname) As Boolean
  FileExists = Dir(fname) <> ""
End Function

Anh ơi, nếu fname = "" thì FileExists trả về TRUE.

Lê Văn Duyệt
 
Lần chỉnh sửa cuối:
Có lẽ ta mở thêm topic tối ưu code và đưa ra 1 loạt bài toán của mình hoặc sưu tầm trên mạng để mọi người cùng thảo luận thì hợp lý hơn.
 
Cảm ơn TuanVNUNI về các kiến thức byRef, byVal mà bấy lâu nay tôi vẫn còn nhiều lúng túng
Nói như vậy thì hàm:
PHP:
Function InRange(rng1, rng2) As Boolean
...
...
End Function
Có phải nên ghi thế này:
PHP:
Function InRange(byVal rng1 As Range, byVal rng2 As Range) As Boolean
...
...
End Function
hay không?
Tôi thường thấy người ta ghi thế này:
PHP:
 Function InRange(rng1 As Range, rng2 As Range) As Boolean
 ...
 ...
 End Function
Xin hỏi: Có gì không ổn? rng1rng2 đã chỉ định chính xác thuộc biến RANGE rồi còn gì?


Vâng, có thể thay
Function InRange(rng1, rng2) As Boolean

thành
Function InRange(byVal rng1 As Range, byVal rng2 As Range) As Boolean
hoặc
Function InRange(rng1 As Range, rng2 As Range) As Boolean

Hai bến rng1, rng2 đều là biến kiểu đối tượng Object/Range nên dùng ByVal hay ByRef là không khác nhau. Biến kiểu Object là làm việc theo tham chiếu nên khi khai báo người ta hay dùng ByRef như thế này
Function InRange(rng1 As Range, rng2 As Range) As Boolean
 
Có lẽ ta mở thêm topic tối ưu code và đưa ra 1 loạt bài toán của mình hoặc sưu tầm trên mạng để mọi người cùng thảo luận thì hợp lý hơn.
Thầy ơi! Vậy mình sửa tiêu đề của Topic này cho nó mang tính tổng quát hơn có được không?
 
Thảo luận về 1 số hàm khác:
----------------------------------------------------------------------------------------------------
1> Hàm FileNameOnly
Tôi nghĩ chỉ cần dùng InSrtRev là đủ, không cần dùng đến vòng lập chi cho mất công
----------------------------------------------------------------------------------------------------
2> Hàm RangeNameExists
Có thể kiểm tra bằng cách tìm INDEX của nó. Ví dụ:
PHP:
Function RangeNameExists(nname As String) As Boolean
  On Error Resume Next
  RangeNameExists = ActiveWorkbook.Names(nname).Index
End Function
Vậy cũng không cần dùng đến vòng lập luôn
----------------------------------------------------------------------------------------------------
3> Hàm WorkbookIsOpen
Duyệt viết hàm như sau:
PHP:
Private Function WorkbookIsOpen(wbname) As Boolean
'   Returns TRUE if the workbook is open
    Dim x As Workbook
    On Error Resume Next
    Set x = Workbooks(wbname)
    If Err = 0 Then WorkbookIsOpen = True _
        Else WorkbookIsOpen = False
End Function
Tin chắc rằng hàm này chẳng bao giờ làm việc chính xác nếu như Workbook cần kiểm tra đang khởi động trên 1 session khác ---> Vụ này cả thế giới họ cũng đăng thắc mắc mà chưa tìm thấy câu trả lời
Không biết TuanVNUNI có ý kiến gì không? Nếu dùng API liệu có thể giải quyết được vấn đề không nhỉ?
-------------------------
Nói thêm: Khi Workbook được khởi động trên 1 session khác thì trong cửa sổ TaskManager ta sẽ nhìn thấy cùng 1 lúc 2 tiến trình Excel.exe (thay vì chỉ có một)

Đúng là vấn đề kiểm tra một file đang mở rất khó khi nó đã được mở ở nhiều session. Em cũng nghĩ tới phải giải quyết bởi các hàm API nhưng vẫn chưa tìm ra cách nào.
 
Đúng là vấn đề kiểm tra một file đang mở rất khó khi nó đã được mở ở nhiều session. Em cũng nghĩ tới phải giải quyết bởi các hàm API nhưng vẫn chưa tìm ra cách nào.
Liệu có thể dùng API để tìm tên của các cửa sổ đang mở hay không? ---> Lấy tiêu đề cửa sổ chẳng hạn (chỉ ác cái là lở người ta dùng code đổi tiêu đề thì chắc "tèo" luôn quá)
 
Theo tôi thật sự ra việc kiểm tra các cửa sổ đang mở, dĩ nhiên là mình làm được rồi bằng các hàm API.
Còn như Anh Tuấn nói chỉ ác cái là lở người ta dùng code đổi tiêu đề thì chắc "tèo" luôn quá ~~> Thì ai mà làm dzậy.

Lê Văn Duyệt
 
Liệu có thể dùng API để tìm tên của các cửa sổ đang mở hay không? ---> Lấy tiêu đề cửa sổ chẳng hạn (chỉ ác cái là lở người ta dùng code đổi tiêu đề thì chắc "tèo" luôn quá)

Dùng API để lấy tiêu đề của các cửa sổ đang mở là được nhưng phương pháp này không chuẩn. Em nghĩ tới giải pháp, nhận từng process "excel.exe" (làm được) rồi nhận biến đối tượng Application (có vẻ rất khó?), từ biến này ta kiểm tra workbook đang mở hay không?
 
Có lý! Vậy thêm cái IF nữa ha:
If fname <> "" Then FileExists = Dir(fname) <> ""
Em cũng tranh thủ vài hàm góp nhặt được, hi hi
PHP:
‘ Kiểm tra sự tồn tại của 1 File
Function bFileExists(rsFullPath As String) As Boolean 
  bFileExists = CBool(Len(Dir$(rsFullPath)) > 0)
End Function

 -------------------------------------------------------
‘ Kiểm tra 1 WorkBook có đang mở hay không ?
Function bWorkbookIsOpen(rsWbkName As String) As Boolean 
On Error Resume Next   
bWorkbookIsOpen = CBool(Len(Workbooks(rsWbkName).Name) > 0) 
End Function 

 --------------------------------------------------------
‘ Kiểm tra sự tồn tại của 1 Sheet
Function WksExists(wksName As String) As Boolean 
   On Error Resume Next    
WksExists = CBool(Len(Worksheets(wksName).Name) > 0)
End Function
TDN
 
Lần chỉnh sửa cuối:
Em cũng tranh thủ vài hàm góp nhặt được, hi hi
PHP:
‘ Kiểm tra sự tồn tại của 1 File
Function bFileExists(rsFullPath As String) As Boolean 
  bFileExists = CBool(Len(Dir$(rsFullPath)) > 0)
End Function

 -------------------------------------------------------
‘ Kiểm tra 1 WorkBook có đang mở hay không ?
Function bWorkbookIsOpen(rsWbkName As String) As Boolean 
On Error Resume Next   
bWorkbookIsOpen = CBool(Len(Workbooks(rsWbkName).Name) > 0) 
End Function 

 --------------------------------------------------------
‘ Kiểm tra sự tồn tại của 1 Sheet
Function WksExists(wksName As String) As Boolean 
   On Error Resume Next    
WksExists = CBool(Len(Worksheets(wksName).Name) > 0)
End Function
TDN

Hi hi hi, cái này anh đã đưa lên rồi.

Lê Văn Duyệt
PS: Chán tedaynui quá, hỏng thèm đọc luôn.
 
----------------------------------------------------------------------------------------------------
3> Hàm WorkbookIsOpen
Duyệt viết hàm như sau:
PHP:
Private Function WorkbookIsOpen(wbname) As Boolean
'   Returns TRUE if the workbook is open
    Dim x As Workbook
    On Error Resume Next
    Set x = Workbooks(wbname)
    If Err = 0 Then WorkbookIsOpen = True _
        Else WorkbookIsOpen = False
End Function
Tin chắc rằng hàm này chẳng bao giờ làm việc chính xác nếu như Workbook cần kiểm tra đang khởi động trên 1 session khác ---> Vụ này cả thế giới họ cũng đăng thắc mắc mà chưa tìm thấy câu trả lời (~~> hi hi hi, anh chưa tìm hiểu thôi...)
Không biết TuanVNUNI có ý kiến gì không? Nếu dùng API liệu có thể giải quyết được vấn đề không nhỉ?
-------------------------
Nói thêm: Khi Workbook được khởi động trên 1 session khác thì trong cửa sổ TaskManager ta sẽ nhìn thấy cùng 1 lúc 2 tiến trình Excel.exe (thay vì chỉ có một)

Anh ơi,

Em đã giới thiệu rồi (nhưng tại vì em chưa kiểm tra theo ý anh nói thôi.) Anh xem ở đây nha.

Chúc anh nghỉ lễ vui vẻ nha.

Lê Văn Duyệt
 
Anh ơi,

Em đã giới thiệu rồi (nhưng tại vì em chưa kiểm tra theo ý anh nói thôi.) Anh xem ở đây nha.

Chúc anh nghỉ lễ vui vẻ nha.

Lê Văn Duyệt
Duyệt ơi!
Việc kiểm tra 1 file có đang mở hay không hoàn toàn khác với kiểm tra 1 workbook đang mở
Với 1 file, ta cần đường dẩn đầy đủ đến file, còn người dùng khi cần kiểm tra 1 Workbook có đang mở hay không, họ đâu quan tâm đến đường dẩn ---> Chỉ cần tên của Workbook có tồn tại trong cửa sổ Task Manager thì hàm phải trả về giá trị TRUE và ngược lại thì FALSE
Minh nghĩ 2 chuyện này hoàn toàn khác nhau ---> Nói chung là KHÓ (đã tìm khắp nơi nhưng chưa thấy code nào khả thi)
 
Duyệt ơi!
Việc kiểm tra 1 file có đang mở hay không hoàn toàn khác với kiểm tra 1 workbook đang mở
Với 1 file, ta cần đường dẩn đầy đủ đến file, còn người dùng khi cần kiểm tra 1 Workbook có đang mở hay không, họ đâu quan tâm đến đường dẩn ---> Chỉ cần tên của Workbook có tồn tại trong cửa sổ Task Manager thì hàm phải trả về giá trị TRUE và ngược lại thì FALSE
Minh nghĩ 2 chuyện này hoàn toàn khác nhau ---> Nói chung là KHÓ (đã tìm khắp nơi nhưng chưa thấy code nào khả thi)
Hi Anh,
Em chưa hiểu ý anh lắm+-+-+-+

Lê Văn Duyệt
 
Hi Anh,
Em chưa hiểu ý anh lắm+-+-+-+

Lê Văn Duyệt
Tức là thế này:
- Tôi có Workbook mang tên A.xls
- Tôi cần 1 hàm theo cú pháp =WbIsOpen("A")
- Hàm này sẽ trả về giá trị = TRUE nếu Workbook A.xls đang mở và ngược lại
Thế thôi, không quan tâm đến đường dẩn (file ấy nằm ở đâu trên đĩa cứng tùy ý)
---------------
Còn vụ kiểm tra file đang mở lại hoàn toàn khác, nó cần 1 đường dẩn đầy đủ, và đây là điều mà người dùng không quan tâm!
 
Anh ơi,

Em đã giới thiệu rồi (nhưng tại vì em chưa kiểm tra theo ý anh nói thôi.) Anh xem ở đây nha.

Chúc anh nghỉ lễ vui vẻ nha.

Lê Văn Duyệt

Anh Duyệt ơi, nếu workbook đặt thuộc tính share (menu: Tools\Share Workbook...) thì hàm trả về giá trị không đúng. Bất kỳ một file nào, không cứ là Excel, nếu OpenFile với thuộc tính Share thì việc kiển tra như cách đã nêu là không đúng.

Vấn đề này có thể tìm một giải pháp tối ưu là: tìm trong Registry hay ở đâu đó, Microsoft Excel lưu thông tin về những file đang mở. Em cũng đang tìm nhưng chưa ra.
 
Nói tóm lại câu trả lời mình cần tìm là: Viết một hàm với tham số là tên của workbook, và kiểm tra xem workbook này có đang mở hay không? (kiểm tra trong tất cả các session Excel đang mở)

Lê Văn Duyệt
 
Lần chỉnh sửa cuối:
Đây là một ý tưởng từ ZVI

Mã:
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Dim hwnd As Long, IsOpen As Boolean, WbName As String
' Testing subrotine
Sub Test()
    Const Wb = "Book1.xls"
    MsgBox "IsWorkbookOpen = " & IsWorkbookOpen(Wb) & vbLf & WbName, , Wb
End Sub
' IsFileOpen= True if WorkbookName is found in text of any Excel window
Function IsWorkbookOpen(WorkbookName As String) As Boolean
    hwnd = 0: IsOpen = False: WbName = UCase(WorkbookName)
    EnumChildWindows hwnd, AddressOf EnumChildProc, ByVal 0&
    If IsOpen Then IsWorkbookOpen = True Else WbName = ""
End Function
' Aux function for API callback
Private Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long

    Dim s$
    s = Space$(GetWindowTextLength(hwnd) + 1)
    GetWindowText hwnd, s, Len(s)
    s = Left$(s, Len(s) - 1)
    Debug.Print s
    If UCase(s) Like "*MICROSOFT EXCEL *" & WbName & "*" Then
        WbName = s
        IsOpen = True
        Exit Function
    End If
    EnumChildProc = 1
End Function

(Em chưa kiểm tra)
 
Đây là một ý tưởng từ ZVI

Mã:
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Dim hwnd As Long, IsOpen As Boolean, WbName As String
' Testing subrotine
Sub Test()
    Const Wb = "Book1.xls"
    MsgBox "IsWorkbookOpen = " & IsWorkbookOpen(Wb) & vbLf & WbName, , Wb
End Sub
' IsFileOpen= True if WorkbookName is found in text of any Excel window
Function IsWorkbookOpen(WorkbookName As String) As Boolean
    hwnd = 0: IsOpen = False: WbName = UCase(WorkbookName)
    EnumChildWindows hwnd, AddressOf EnumChildProc, ByVal 0&
    If IsOpen Then IsWorkbookOpen = True Else WbName = ""
End Function
' Aux function for API callback
Private Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long

    Dim s$
    s = Space$(GetWindowTextLength(hwnd) + 1)
    GetWindowText hwnd, s, Len(s)
    s = Left$(s, Len(s) - 1)
    Debug.Print s
    If UCase(s) Like "*MICROSOFT EXCEL *" & WbName & "*" Then
        WbName = s
        IsOpen = True
        Exit Function
    End If
    EnumChildProc = 1
End Function
(Em chưa kiểm tra)
Đang test... Duyệt đưa thiếu 1 hàm API
PHP:
Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Kết quả chính xác nhưng còn.. thiếu tí nữa thôi, đó là:
- Kiểm tra workbook trên 1 session khác ---> Kết quả CHÍNH XÁC
- Kiểm tra workbook trên cùng 1 session ---> Kết quả SAI
Hic... Mình nghĩ trục trặc này Duyệt thừa sức khắc phục!
---------------------------------------------
Anh Duyệt ơi, nếu workbook đặt thuộc tính share (menu: Tools\Share Workbook...) thì hàm trả về giá trị không đúng. Bất kỳ một file nào, không cứ là Excel, nếu OpenFile với thuộc tính Share thì việc kiển tra như cách đã nêu là không đúng.
.
Đã thử với share workbook ---> Kết quả chính xác luôn
 
Lần chỉnh sửa cuối:
Đây là một ý tưởng từ ZVI

Mã:
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Dim hwnd As Long, IsOpen As Boolean, WbName As String
' Testing subrotine
Sub Test()
    Const Wb = "Book1.xls"
    MsgBox "IsWorkbookOpen = " & IsWorkbookOpen(Wb) & vbLf & WbName, , Wb
End Sub
' IsFileOpen= True if WorkbookName is found in text of any Excel window
Function IsWorkbookOpen(WorkbookName As String) As Boolean
    hwnd = 0: IsOpen = False: WbName = UCase(WorkbookName)
    EnumChildWindows hwnd, AddressOf EnumChildProc, ByVal 0&
    If IsOpen Then IsWorkbookOpen = True Else WbName = ""
End Function
' Aux function for API callback
Private Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long

    Dim s$
    s = Space$(GetWindowTextLength(hwnd) + 1)
    GetWindowText hwnd, s, Len(s)
    s = Left$(s, Len(s) - 1)
    Debug.Print s
    If UCase(s) Like "*MICROSOFT EXCEL *" & WbName & "*" Then
        WbName = s
        IsOpen = True
        Exit Function
    End If
    EnumChildProc = 1
End Function

(Em chưa kiểm tra)

Kết quả không đúng anh ạ. Như em đã nói bài trên là dùng các hàm API để kiển tra text/caption của các window đang mở với tên một workbook rồi kết luận nó mở hay không là không chuẩn.

Hàm trên sẽ bị sai khi xảy ra một trong 3 trường hợp dưới đây,
+ Excel đang mở ít nhất 2 file (thực tế người dùng Excel ít khi chỉ mở một file). Giả sử ta cần kiểm tra file book1.xls, nhưng ta đang làm viẹc với book2.xls (ActiveWorkbook) thì kêys quả không đúng.
Việc trả kết quả không đúng vì khi ta đa làm với một workbook thì Window của chương trình sẽ luôn hiện tên của workbook đó, còn các workbooks khác đang mở vẫn chạy âm thầm nhưng không có tên trên window của chương trình.
+ Người dùng khi viết một ứng dụng VBA, thường thay đổi caption/text của window chương trình bằng cách Application.Caption = "Chương trình kiểm kho", khi đó đương nhiên hàm kiểm tra trên là sai.
+ Nếu tên workbook là tên có dấu, ví dụ "kế toán nhập xuất tồn.xls" thì hàm trên đương nhiên sai, vì chúng không hõ trợ Unicode. Tuy nhiên vấn đề này là chuyện nhỏ vì ta có thể unicode được.

Việc sai của hàm IsWorkbookOpen trên là vì ta chỉ dựa vòa một manh mối mong manh là WindowText, mà giá trị này thường bị thay đổi bởi ứng dụng, của người dùng. Việc đặt workbook share hay không không liên quan tời hàm này.

Hy vọng chúng ta sẽ tìm được giải pháp chuẩn cho hàm IsWorkbookOpen.
 
Lần chỉnh sửa cuối:
Theo tôi thì việc kiểm tra trạng thái 1 workbook có đang được mở hay không thì kiểm tra trên 1 Session của Excel là đủ rồi, tôi chưa thấy có nhu cầu nào cần phải kiểm tra trên tất cả các session Excel đang chạy cả. Không rõ có bác nào gặp phải tình huống cần phải kiểm tra trên toàn bộ các session của Excel hay chưa???
 
Theo tôi thì việc kiểm tra trạng thái 1 workbook có đang được mở hay không thì kiểm tra trên 1 Session của Excel là đủ rồi, tôi chưa thấy có nhu cầu nào cần phải kiểm tra trên tất cả các session Excel đang chạy cả. Không rõ có bác nào gặp phải tình huống cần phải kiểm tra trên toàn bộ các session của Excel hay chưa???

Với các loại database khác thì có lẽ không thực sự cần thiết vì nếu là file có thể share cho nhiều người dùng thì nó luôn được mở ở trạng thái share, khi đó nhiều người đều có thể ghi vào file này khi nó đang mở. Nhưng với Excel, khi file đã mở ở một session, nếu mở một lần nữa trên session khác thì nó luôn là trạng thái ReadOnly - Chỉ đọc mà không ghi được, khi đó các lệnh ghi dữ liệu trên file này sẽ xảy ra lỗi. Trừ khi file này người dùng đặt thuộc tính "Share Workbook".
 
Với các loại database khác thì có lẽ không thực sự cần thiết vì nếu là file có thể share cho nhiều người dùng thì nó luôn được mở ở trạng thái share, khi đó nhiều người đều có thể ghi vào file này khi nó đang mở. Nhưng với Excel, khi file đã mở ở một session, nếu mở một lần nữa trên session khác thì nó luôn là trạng thái ReadOnly - Chỉ đọc mà không ghi được, khi đó các lệnh ghi dữ liệu trên file này sẽ xảy ra lỗi. Trừ khi file này người dùng đặt thuộc tính "Share Workbook".
Nếu để phục vụ yêu cầu này theo tôi không không phải kiểm tra tên Workbook đang mở mà phải kiểm tra Tên file đầy đủ mới đúng. Vì nếu tôi có 2 file cùng tên nhưng đặt ở 2 thư mục khác nhau, như vậy khi mở ra nó sẽ có cùng tên Workbook(mở trên 2 session của excel), việc kiểm tra để phục vụ yêu cầu này sẽ không chính xác. Mặt khác việc mở cùng 1 file thì về mặt người dùng sẽ nhận được cảnh báo file in use. Còn về mặt người xử lý dưới code thì cần quan tâm tới trạng thái ReadOnly của file đang xử lý.
 
Nếu để phục vụ yêu cầu này theo tôi không không phải kiểm tra tên Workbook đang mở mà phải kiểm tra Tên file đầy đủ mới đúng. Vì nếu tôi có 2 file cùng tên nhưng đặt ở 2 thư mục khác nhau, như vậy khi mở ra nó sẽ có cùng tên Workbook(mở trên 2 session của excel), việc kiểm tra để phục vụ yêu cầu này sẽ không chính xác. Mặt khác việc mở cùng 1 file thì về mặt người dùng sẽ nhận được cảnh báo file in use. Còn về mặt người xử lý dưới code thì cần quan tâm tới trạng thái ReadOnly của file đang xử lý.

Trước khi open file thì kiểm tra xem tên của Workbook đã tồn tại hay chưa. Nếu đã có thì không mở nữa hoặc làm gì đấy...
Vấn đề kiểm tra trạng thái đã mở hay chưa mới là khó. Khi viết ứng dụng, người ta kiểm tra file trước khi mở nó ra, chứ mở rồi mới kiểm tra thì không ổn.
 
Trước khi open file thì kiểm tra xem tên của Workbook đã tồn tại hay chưa. Nếu đã có thì không mở nữa hoặc làm gì đấy...
Vấn đề kiểm tra trạng thái đã mở hay chưa mới là khó. Khi viết ứng dụng, người ta kiểm tra file trước khi mở nó ra, chứ mở rồi mới kiểm tra thì không ổn.
Thế thì vấn đề chuyển sang là kiểm tra 1 file đã được mở hay chưa(in use), chứ không phải kiểm tra Workbook có tên cụ thể có đang được mở hay không. Tên Workbook có thể đang mở nhưng chắc gì đã phải là cái file mà ta đang định mở??? Để kiểm tra file hiện có được mở hay không thì phải kiểm tra Fullname của file đó mới xác định được. Bạn thử dùng hàm này kiểm tra tình trạng file đang được mở hay không xem có vấn đề gì không nhé
Mã:
Function IsOpen(strFullname As String) As Boolean
    Dim iFile As Integer
    iFile = FreeFile
    On Error Resume Next
    Open strFullname For Binary Access Read Write Lock Read Write As #iFile
    Close #iFile
    If Err.Number <> 0 Then
        IsOpen = True
        Err.Clear
    Else
        IsOpen = False
    End If
End Function
 
Thế thì vấn đề chuyển sang là kiểm tra 1 file đã được mở hay chưa(in use), chứ không phải kiểm tra Workbook có tên cụ thể có đang được mở hay không. Tên Workbook có thể đang mở nhưng chắc gì đã phải là cái file mà ta đang định mở??? Để kiểm tra file hiện có được mở hay không thì phải kiểm tra Fullname của file đó mới xác định được. Bạn thử dùng hàm này kiểm tra tình trạng file đang được mở hay không xem có vấn đề gì không nhé
Có tính huống thế này:
- Người dùng có file A.xls nằm đâu đó trên đĩa cứng
- File A.xls này đôi lúc bị thay đổi vị trí (tức thay đổi đường dẩn)
- Khi làm việc gì đó, người ta chỉ muốn biết file A.xls này đã mở hay chưa (chỉ cần biết tên file)
Thế thì không thể xác định file đã mở bằng vào đường dẩn được (Mà thực chất người dùng cũng không quan tâm đến đường dẩn luôn)
Vói người dùng Excel có kinh nghiệm sẽ luôn "tránh né" vấn đề này, nhưng trên thực tế nhu cầu trên là có thật
(Thế mới khoai... chứ để xác định 1 file có đường dẩn cụ thể đã mở hay chưa thì ta đã không bàn luận gì nữa rồi)
 
Có tính huống thế này:
- Người dùng có file A.xls nằm đâu đó trên đĩa cứng
- File A.xls này đôi lúc bị thay đổi vị trí (tức thay đổi đường dẩn)
- Khi làm việc gì đó, người ta chỉ muốn biết file A.xls này đã mở hay chưa (chỉ cần biết tên file)
Thế thì không thể xác định file đã mở bằng vào đường dẩn được (Mà thực chất người dùng cũng không quan tâm đến đường dẩn luôn)
Vói người dùng Excel có kinh nghiệm sẽ luôn "tránh né" vấn đề này, nhưng trên thực tế nhu cầu trên là có thật
(Thế mới khoai... chứ để xác định 1 file có đường dẩn cụ thể đã mở hay chưa thì ta đã không bàn luận gì nữa rồi)
Tôi thấy đây vẫn chỉ là giả thuyết để rồi lại dẫn dắt tới việc thực hiện cái yêu cầu ban đâu chứ chưa phải là 1 trường hợp cụ thể cần cái nhu cầu này(vẫn ở đâu đó với làm việc gì đó), còn nhu cầu thực tế tôi thấy nó vẫn không cần thiết, bản thân excel cũng không hề quan tâm tới việc 1 Workbook có tên cụ thể đã được mở trên session khác hay chưa. Còn nếu bác nào thực sự có nhu cầu này thật thì có thể can thiệp để khi mở 1 workbook bất kỳ thì lưu tạm tên workbook vào đâu đó(có thể là regitry), khi close workbook thì lại xóa nó đi, như vậy khi cần kiểm tra có thể kiểm tra tại đó. Còn tôi thì thực sự chưa thấy có nhu cầu nào để thực hiện yêu cầu này cả.
 
Thế thì vấn đề chuyển sang là kiểm tra 1 file đã được mở hay chưa(in use), chứ không phải kiểm tra Workbook có tên cụ thể có đang được mở hay không. Tên Workbook có thể đang mở nhưng chắc gì đã phải là cái file mà ta đang định mở??? Để kiểm tra file hiện có được mở hay không thì phải kiểm tra Fullname của file đó mới xác định được. Bạn thử dùng hàm này kiểm tra tình trạng file đang được mở hay không xem có vấn đề gì không nhé
Mã:
Function IsOpen(strFullname As String) As Boolean
    Dim iFile As Integer
    iFile = FreeFile
    On Error Resume Next
    Open strFullname For Binary Access Read Write Lock Read Write As #iFile
    Close #iFile
    If Err.Number <> 0 Then
        IsOpen = True
        Err.Clear
    Else
        IsOpen = False
    End If
End Function

Cái hàm này cũng như cái hàm bác Duyệt đã giới thiệu thôi. Nó sai khi workbook đặt thuộc tính share (Tools\Share Workbook...).
Vấn đề tôi quan tâm thực sự là file đó đã được mở hay chưa mà thôi (kiểm tra fullname), chứ tên workbook là một chuyện khác.

Về ý tưởng lưu file mở vào registry để lấy chỗ để kiểm tra thì không được đâu. Một file Excel thuần túy (không có VBA) người ta có thể mở một cách thông thường là nhấp đúp chuột từ "My Computer"

Vấn của tôi là thực tế. Tôi quan tâm tới kết quả trả về của hàm phải đúng.
 
Lần chỉnh sửa cuối:
Cái hàm này cũng như cái hàm bác Duyệt đã giới thiệu thôi. Nó sai khi workbook đặt thuộc tính share (Tools\Share Workbook...).
Vấn đề tôi quan tâm thực sự là file đó đã được mở hay chưa mà thôi (kiểm tra fullname), chứ tên workbook là một chuyện khác.

Về ý tưởng lưu file mở vào registry để lấy chỗ để kiểm tra thì không được đâu. Một file Excel thuần túy (không có VBA) người ta có thể mở một cách thông thường là nhấp đúp chuột từ "My Computer"

Vấn của tôi là thực tế. Tôi quan tâm tới kết quả trả về của hàm phải đúng.
Có bị lộn gì ở đây không? Tôi thấy mọi người đang bàn đến chuyện kiểm tra tên 1 Workbook có được mở trên bất kỳ 1 session nào hay không, và tôi thấy chỉ cần check trên 1 session hiện tại mà code chạy là đủ. Còn code kiểm tra file có đang mở hay không thì hàm đó trả về kết quả đúng. Riêng trường hợp Share Workbook thì khi 1 Workbook đã được share thì cơ chế làm việc của nó khác hoàn toàn, nếu ai đã dùng các phần mềm quản lý SourceSafe sẽ hiểu là khi đó thì file đó sẽ không được mở thực sự, khi 1 người dùng mở file đó thì thực chất nó tạo ra 1 bản sao của file đó trên local và làm việc trên bản đó, chỉ khi nào thực sự ghi lại thì nó mới làm việc với file thực sự đó. Như vậy tôi thấy yêu cầu mà bạn đang quan tâm có vẻ đang không giống như yêu cầu mà bác NDU đang quan tâm thì phải. Còn nhu cầu bạn muốn kiểm tra 1 file đã share workbook rồi có thực sự được mở hay không thì tôi đang không rõ trường hợp cụ thể nào dẫn đến nhu cầu này???
 
Có bị lộn gì ở đây không? Tôi thấy mọi người đang bàn đến chuyện kiểm tra tên 1 Workbook có được mở trên bất kỳ 1 session nào hay không, và tôi thấy chỉ cần check trên 1 session hiện tại mà code chạy là đủ. Còn code kiểm tra file có đang mở hay không thì hàm đó trả về kết quả đúng. Riêng trường hợp Share Workbook thì khi 1 Workbook đã được share thì cơ chế làm việc của nó khác hoàn toàn, nếu ai đã dùng các phần mềm quản lý SourceSafe sẽ hiểu là khi đó thì file đó sẽ không được mở thực sự, khi 1 người dùng mở file đó thì thực chất nó tạo ra 1 bản sao của file đó trên local và làm việc trên bản đó, chỉ khi nào thực sự ghi lại thì nó mới làm việc với file thực sự đó. Như vậy tôi thấy yêu cầu mà bạn đang quan tâm có vẻ đang không giống như yêu cầu mà bác NDU đang quan tâm thì phải. Còn nhu cầu bạn muốn kiểm tra 1 file đã share workbook rồi có thực sự được mở hay không thì tôi đang không rõ trường hợp cụ thể nào dẫn đến nhu cầu này???

Vấn đề bác NDU quan tâm là tên workbook, còn tôi quan tâm tới file (fullname). Tôi quan tâm tới IsOpen() phải trả về đúng, dù file đó đặt thuộc tính gì, cơ chế gì. Còn nếu chúng ta không làm được thì thôi tạm bỏ qua hàm này. Vấn đề này trên mạng hình như cũng chưa có ai làm được thì phải?

Còn nhu cầu bạn muốn kiểm tra 1 file đã share workbook rồi có thực sự được mở hay không thì tôi đang không rõ trường hợp cụ thể nào dẫn đến nhu cầu này???

Một file, do tính chất công việc phải hợp tác, chia sẻ dữ liệu với nhiều người, người ta share nó trong mạng LAN (đương nhiên phải đặt Share Workbook). Từ một chương trình người ta có hàm IsOpen(...) để kiểm tra.
 
Lần chỉnh sửa cuối:
Vấn đề bác NDU quan tâm là tên workbook, còn tôi quan tâm tới file (fullname). Tôi quan tâm tới IsOpen() phải trả về đúng, dù file đó đặt thuộc tính gì, cơ chế gì. Còn nếu chúng ta không làm được thì thôi tạm bỏ qua hàm này. Vấn đề này trên mạng hình như cũng chưa có ai làm được thì phải?



Một file, do tính chất công việc phải hợp tác, chia sẻ dữ liệu với nhiều người, người ta share nó trong mạng LAN (đương nhiên phải đặt Share Workbook). Từ một chương trình người ta có hàm IsOpen(...) để kiểm tra.
Sở dĩ tôi hỏi trường hợp cụ thể nhu cầu vì đôi khi có thể không dùng cách này thì dùng cách khác. Còn hàm IsOpen nếu đối với 1 file không share thì chắc không còn vấn đề gì phải bàn. Trường hợp Share thì tôi không rõ code từ 1 nơi khác(không phải file cần kiểm tra) có kiểm tra được file đó có phải share hay không? do đó việc kiểm tra IsOpen khó mà thực hiện được, tuy nhiên nếu code tại file đó ta hoàn toàn có thể kiểm tra file đó có được share hay không, nếu được share thì hiện tại có bao nhiêu người đang mở file đó. Từ đây tôi nghĩ chắc cũng đủ dùng cho 1 số trường hợp rồi, tuy nhiên tôi không rõ trường hợp cụ thể của bạn là gì nên không rõ nó có đáp ứng được yêu cầu của bạn hay không.
 
Sở dĩ tôi hỏi trường hợp cụ thể nhu cầu vì đôi khi có thể không dùng cách này thì dùng cách khác. Còn hàm IsOpen nếu đối với 1 file không share thì chắc không còn vấn đề gì phải bàn. Trường hợp Share thì tôi không rõ code từ 1 nơi khác(không phải file cần kiểm tra) có kiểm tra được file đó có phải share hay không? do đó việc kiểm tra IsOpen khó mà thực hiện được, tuy nhiên nếu code tại file đó ta hoàn toàn có thể kiểm tra file đó có được share hay không, nếu được share thì hiện tại có bao nhiêu người đang mở file đó. Từ đây tôi nghĩ chắc cũng đủ dùng cho 1 số trường hợp rồi, tuy nhiên tôi không rõ trường hợp cụ thể của bạn là gì nên không rõ nó có đáp ứng được yêu cầu của bạn hay không.
Hi rollover79,

Vậy theo bạn có cách nào, hàm nào để kiểm tra việc workbook trong tình trạng shared và đang mở hay đóng không?

Lê Văn Duyệt
 
Hi rollover79,

Vậy theo bạn có cách nào, hàm nào để kiểm tra việc workbook trong tình trạng shared và đang mở hay đóng không?

Lê Văn Duyệt
Nếu ở tại workbook đó thì ta có thể dùng thuộc tính MultiUserEditing hoặc UserStatus của workbook để kiểm tra, ví dụ sau sẽ liệt kê danh sách User đang mở workbook và tình trạng share
Mã:
Sub ShowUsers()
    On Error Resume Next
    Dim arrUsers()
    Dim strMsg As String
    Dim i As Integer
    arrUsers = ThisWorkbook.UserStatus
    For i = 1 To UBound(arrUsers)
        strMsg = strMsg & arrUsers(i, 1) & " Opened: " & arrUsers(i, 2) & ", " & IIf(arrUsers(i, 3) = 2, "Shared", "Not Shared") & vbNewLine
    Next
    MsgBox strMsg
End Sub
 
Nếu ở tại workbook đó thì ta có thể dùng thuộc tính MultiUserEditing hoặc UserStatus của workbook để kiểm tra, ví dụ sau sẽ liệt kê danh sách User đang mở workbook và tình trạng share
Mã:
Sub ShowUsers()
    On Error Resume Next
    Dim arrUsers()
    Dim strMsg As String
    Dim i As Integer
    arrUsers = ThisWorkbook.UserStatus
    For i = 1 To UBound(arrUsers)
        strMsg = strMsg & arrUsers(i, 1) & " Opened: " & arrUsers(i, 2) & ", " & IIf(arrUsers(i, 3) = 2, "Shared", "Not Shared") & vbNewLine
    Next
    MsgBox strMsg
End Sub
Cám ơn rollover79, nhưng nếu mình không ở workbook đó thì làm thế nào để kiểm tra? (Đây cũng là vấn đề các bạn khác quan tâm)

Lê Văn Duyệt
 
Cám ơn rollover79, nhưng nếu mình không ở workbook đó thì làm thế nào để kiểm tra? (Đây cũng là vấn đề các bạn khác quan tâm)

Lê Văn Duyệt
Theo như đã thảo luận từ những bài trước thì tôi thấy thế này. Nếu đứng ở ngoài file đó mà muốn kiểm tra, đầu tiên ta dùng hàm IsOpen để kiểm tra, nếu trả về True thì chắc chắn file không Share và đã có người khác đang mở, còn nếu trả về False thì tôi tiến hành mở file đó, kiểm tra tình trạng share của file và số lượng user đang mở file đó(điều này có thể làm được), rồi từ đó sẽ quyết định làm gì tiếp theo(cần thiết thì lại đóng file đó lại). Vấn đề ở đây vẫn là kiểm tra để rồi làm gì tiếp theo, do đó tùy từng trường hợp để xử lý.
 

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

Back
Top Bottom