Listview và Listbox - Hỏi về ưu khuyết.

Liên hệ QC

cantl

!!! Giải thoát !!!
Thành viên bị đình chỉ hoạt động
Tham gia
6/8/08
Bài viết
1,631
Được thích
1,034
Giới tính
Nam
Chào các bác,
Các bác cho em hỏi giữa Listview và Listbox thì nên chọn cái nào lên form cho hoành tráng ạ?
Em không muốn dùng theo kiểu tùy trường hợp, mà chỉ có thể chọn 1 mà thôi.
Ưu, khuyết là gì ạ?
 
Các bác cho em hỏi giữa Listview và Listbox thì nên chọn cái nào lên form cho hoành tráng ạ?
Vấn đề không phải là hoành tráng mà cái nào hỗ trợ tùy biến nhiều hơn cho người lập trình, viết giao diện.
Tôi thì chọn Listview. (Nếu bên Access thì khỏi lăn tăn vụ này vì Form Access có công cụ mạnh là SubForm/SubReport)
Điểm bất tiện của Listview chỉ có một, là phải đăng ký MSCOMCTL.OCX để sử dụng.
 
Upvote 0
Upvote 0
Listview như anh @ongke0711 nói là phải đăng ký, mặc dù Listview có đường lưới(grid) đẹp, nhưng mang qua máy khác không đăng ký là không hiện. Dùng Listbox thì không sao. Em chỉ biết có vậy.
 
Upvote 0
Việc chọn ListView (control trong MSCOMCTL.OCX) hay ListBox trong MSForms thì cần xem nhu cầu thực sự chức năng mà mình thiết kế. Mỗi cái có ưu điểm nổi bật riêng:
ListView của MS
- Chỉ chạy trong môi trường 32-bit. Nếu ứng dụng bạn viết không khắt khe về môi trường, người dùng chấp nhận chỉ cài Office 32-bit thì điều này chấp nhận được.
- Không hỗ trợ unicode. Về khoản này thì điểm trừ nhiều nhất với ứng dụng dùng font unicode.
- Tùy biến hiển thị (định dạng font, màu sắc, hình ảnh giữa các dòng) gần giống với cách hiển thị của Windows Explorer (cũ). Trình độ lập trình càng cao thì càng có khả năng tùy biến hiển thị nó phong phú.

ListBox trong MSForms
- Là control thuộc MSForms được cài đặt kèm theo bộ Office nên đương nhiên hỗ trợ cả 32 và 64-bit.
- Hỗ trợ unicode
- Với số lượng dữ liệu khá lớn tốc độ load nhanh.
- Hạn chế duy nhất là hiển thị rất giản đơn, không tùy biến định dạng màu sắc, font các dòng, không đính kèm hình ảnh được.
 
Upvote 0
Bác Tuân nói đúng đó. Tôi cũng quên vụ Unicode. Nếu đã cài OCX thì cài cái OCX của bác Tuân luôn là ngon lành cành đào. Tôi cũng có dùng BSAC OCX.
 
Upvote 0
Đã "nhiều quá không nhớ hết" thì hỏi làm gì?
Cứ thử đi thử lại nhiều lần. Kinh nghiệm sẽ dạy cho biết ưu/khuyết điểm.

Bạn có khuynh hướng giống nhiều người xin code ở đây. Đã không tự viết code được mà còn đòi "tối ưu". Đòi vậy tưởng là hoành tráng, nhưng gặp thằng cắc cớ nó hỏi: "chỗ này làm gì vậy?" thì muối mặt.
 
Upvote 0
Trao đổi với bác @cantl là vui nhất.
Listbox, listview bỏ qua bên đi, nó nằm ngoài tầm với của mình rồi.
Hiện mình chỉ quan tâm, là làm cách nào để xử lý được dữ liệu luôn trên nền web. Có thể giao diện là nhập liệu, truyền dữ liệu vè máy chủ xử lý và trả lại kết quả trên giao diện web.
Đang đau đầu đây
 
Upvote 0
Upvote 0
Anh có tệp nào ví dụ không, đưa em thử chuyển thành Unicode.
Trước đây tôi có dùng Listview trong mấy bài này.
https://www.giaiphapexcel.com/diendan/threads/tải-dữ-liệu-từ-excel-sang-dbf.161020/#post-1077114
https://www.giaiphapexcel.com/diendan/threads/lấy-dữ-liệu-từ-sql-đưa-vào-listview.161131/#post-1076436

Nếu tôi dùng font .vni và listview cũng dùng font này thì hiển thị được tiếng Việt.

File đính kèm bên dưới.

Còn về vụ 32bit, 64bit thì tôi vẫn sử dụng bình thường.
- 32bit thì copy và đăng ký OCX vào "C:\Windows\System32\".
- 64 bit thì copy và đăng ký OCX vào "C:\Windows\SysWOW64\".

Screenshot at Jan 16 20-35-29.png

Hình này là tôi dùng BSAC.OCX
1705412665751.png
 

File đính kèm

  • KetNoiExcel_Access_Listview.zip
    48.7 KB · Đọc: 6
Lần chỉnh sửa cuối:
Upvote 0
Anh có tệp nào ví dụ không, đưa em thử chuyển thành Unicode.


ListView và TreeView chạy ổn trong môi trường Window và Office 64bit, không biết anh có nhầm gì không?


Mình đang nói ListView trong bộ ActiveX MSCOMCTL.OCX đấy nhé. API tạo control thì không tính vì ní không dễ áp dụng cho số đông người lập trình VBA.
 
Upvote 0
Nên dẫn các bạn thích lập trình đi vào chuyên nghiệp sớm anh @Nguyễn Duy Tuân, nếu như đang tuổi 23 hiểu sớm còn hơn chờ 30 mới biết "chuyện". API tính ra chỉ như trò chơi mới, chơi nhiều sẽ quen tay.

Lập trình mà không đi đến chuyên nghiệp, tức là đi nữa đường gặp ánh hào quang, mừng rỡ nên dừng bước.

Các ứng dụng API thường là đã có người viết sẵn cả, còn lại là do cách mình thừa kế chúng như thế nào. Khi chúng đã đi vào một góc của não bộ rồi, thì chúng như một tài sản.
 
Upvote 0
Dưới đây là một đoạn mã mà một lập trình viên API khao khát làm được, cho dù là ngôn ngữ lập trình nào, HĐH Window hay Linux.
Đoạn mã này là đoạn mã mà VBA tạo lệnh chạy ở cấp thấp nhất trong máy tính.
Để viết đoạn mã này cần có nhiều năm học tập và nhiều năm kinh nghiệm.
Các phần cần học như: Ngôn ngữ Assembly, học dịch ngược, API Win32.
Các bạn biết đó, API có các hàm rất "nguy hiểm", viết mã "sai một li là đi một dặm". Nên nhiều năm kinh nghiệm là rất quý giá.

(Đoạn mã này chỉ thực hiện một mục đích duy nhất là chóng ứng dụng Office sụp khi sử dụng hàm API SetTimer. )
Đoạn mã này cũng có thể áp dụng cho phát triển ListView API, ngon lành là đằng khác.

JavaScript:
' //
' // 64/32 bit timer class for VBA
' // by The trick 2019
' //

Option Explicit

#If VBA7 = 0 Then
  Private Enum LongLong:[_]:End Enum
  Private Enum LongPtr:[_]:End Enum
#End If
Private Const FADF_AUTO                     As Long = 1
Private Const HEAP_CREATE_ENABLE_EXECUTE    As Long = &H40000
Private Const HEAP_NO_SERIALIZE             As Long = &H1
Private Const HEAP_ZERO_MEMORY              As Long = &H8
Private Const PROCESS_HEAP_ENTRY_BUSY       As Long = &H4
Private Const WNDPROCINDEX                  As Long = 8
Private Const HEAP_ENV_VARIABLE             As String = "TrickVBATimer"
Private Const TIMERPROC_INDEX               As Long = 5

Private Type SAFEARRAYBOUND
    cElements           As Long
    lLbound             As Long
End Type

Private Type PROCESS_HEAP_ENTRY
    lpData              As LongPtr
    cbData              As Long
    cbOverhead          As Byte
    iRegionIndex        As Byte
    wFlags              As Integer
    dwCommittedSize     As Long
    dwUnCommittedSize   As Long
    lpFirstBlock        As LongPtr
    lpLastBlock         As LongPtr
End Type

Private Type SAFEARRAY
    cDims               As Integer
    fFeatures           As Integer
    cbElements          As Long
    cLocks              As Long
    pvData              As LongPtr
    Bounds              As SAFEARRAYBOUND
End Type

Private m_pAsmThunk     As LongPtr
Private m_hCodeHeap     As LongPtr
Private m_pEbMode       As LongPtr
Private m_lIdEvent      As LongPtr
#If VBA7 Then
Private Declare PtrSafe Function SetEnvironmentVariable Lib "kernel32" Alias "SetEnvironmentVariableW" (ByVal lpName As LongPtr, ByVal lpValue As LongPtr) As Long
Private Declare PtrSafe Function GetEnvironmentVariable Lib "kernel32" Alias "GetEnvironmentVariableW" (ByVal lpName As LongPtr, ByVal lpBuffer As LongPtr, ByVal nSize As Long) As Long
Private Declare PtrSafe Function HeapCreate Lib "kernel32" (ByVal flOptions As Long, ByVal dwInitialSize As LongPtr, ByVal dwMaximumSize As LongPtr) As LongPtr
Private Declare PtrSafe Function HeapDestroy Lib "kernel32" (ByVal hHeap As LongPtr) As Long
Private Declare PtrSafe Function HeapAlloc Lib "kernel32" (ByVal hHeap As LongPtr, ByVal dwFlags As Long, ByVal dwBytes As LongPtr) As LongPtr
Private Declare PtrSafe Function HeapFree Lib "kernel32" (ByVal hHeap As LongPtr, ByVal dwFlags As Long, ByVal lpMem As LongPtr) As Long
Private Declare PtrSafe Function HeapWalk Lib "kernel32" (ByVal hHeap As LongPtr, ByRef lpEntry As PROCESS_HEAP_ENTRY) As Long
Private Declare PtrSafe Function HeapLock Lib "kernel32" (ByVal hHeap As LongPtr) As Long
Private Declare PtrSafe Function HeapUnlock Lib "kernel32" (ByVal hHeap As LongPtr) As Long
Private Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleW" (ByVal lpModuleName As LongPtr) As LongPtr
Private Declare PtrSafe Function GetProcAddress Lib "kernel32" (ByVal hModule As LongPtr, ByVal lpProcName As String) As LongPtr
Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryW" (ByVal lpLibFileName As LongPtr) As LongPtr
Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef pDestination As Any, ByRef Source As Any, ByVal Length As LongPtr)
  #If Win64 Then
  Private Declare PtrSafe Sub DupArray Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination() As Any, ByRef pSA As Any, Optional ByVal Length As LongPtr = 8)
  #Else
  Private Declare PtrSafe Sub DupArray Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination() As Any, ByRef pSA As Any, Optional ByVal Length As LongPtr = 4)
  #End If
#Else
Private Declare Function SetEnvironmentVariable Lib "kernel32" Alias "SetEnvironmentVariableW" ( ByVal lpName As Long, ByVal lpValue As Long) As Long
Private Declare Function GetEnvironmentVariable Lib "kernel32" Alias "GetEnvironmentVariableW" ( ByVal lpName As Long, ByVal lpBuffer As Long, ByVal nSize As Long) As Long
Private Declare Function HeapCreate Lib "kernel32" ( ByVal flOptions As Long, ByVal dwInitialSize As Long, ByVal dwMaximumSize As Long) As Long
Private Declare Function HeapDestroy Lib "kernel32" ( ByVal hHeap As Long) As Long
Private Declare Function HeapAlloc Lib "kernel32" ( ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function HeapFree Lib "kernel32" ( ByVal hHeap As Long, ByVal dwFlags As Long, ByVal lpMem As Long) As Long
Private Declare Function HeapWalk Lib "kernel32" ( ByVal hHeap As Long, ByRef lpEntry As PROCESS_HEAP_ENTRY) As Long
Private Declare Function HeapLock Lib "kernel32" ( ByVal hHeap As Long) As Long
Private Declare Function HeapUnlock Lib "kernel32" ( ByVal hHeap As Long) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleW" ( ByVal lpModuleName As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" ( ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryW" ( ByVal lpLibFileName As Long) As Long
Private Declare Function SetTimer Lib "user32" ( ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" ( ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( ByRef pDestination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Sub DupArray Lib "kernel32" Alias "RtlMoveMemory" ( ByRef Destination() As Any, ByRef pSA As Any, Optional ByVal Length As Long = 4)
#End If

Public Event Tick(ByVal hwnd As LongPtr, ByVal idEvent As LongPtr)

Private m_vTag          As Variant
Private m_lInterval     As Long

Public Property Let Interval(ByVal lValue As Long)
  If lValue = m_lInterval Then Exit Property
  If m_pAsmThunk Then
    KillTimer 0, m_lIdEvent
    m_lIdEvent = SetTimer(0, 0, lValue, m_pAsmThunk)
    If m_lIdEvent = 0 Then Err.Raise 5
    #If Win64 Then
    CopyMemory ByVal m_pAsmThunk + &H3A, m_lIdEvent, Len(m_lIdEvent)
    #Else
    CopyMemory ByVal m_pAsmThunk + &H16, m_lIdEvent, Len(m_lIdEvent)
    #End If
  Else
    If Not CreateAsm(lValue) Then Err.Raise 5
  End If
  m_lInterval = lValue
End Property

Public Property Get Interval() As Long
    Interval = m_lInterval
End Property

Public Property Let Tag(ByVal vValue As Variant)
    m_vTag = vValue
End Property

Public Property Set Tag(ByVal vValue As Variant)
    Set m_vTag = vValue
End Property

Public Property Get Tag() As Variant
  If IsObject(m_vTag) Then Set Tag = m_vTag Else Tag = m_vTag
End Property

' // Callback function
'/ / Nêìu baòn sýÒa ðôÒi viò trí cuÒa hàm này baòn nên câòp nhâòt hãÌng sôì TIMERPROC_INDEX
Private Function TimerProc(ByVal hwnd As LongPtr, ByVal uMsg As Long, ByVal idEvent As LongPtr, ByVal dwTime As Long) As Long
  On Error Resume Next
  RaiseEvent Tick(hwnd, idEvent)
  Err.Clear
End Function
  
'// Taòo hôòi thun nêìu không tôÌn taòi
Private Function CreateAsm(ByVal lInterval As Long) As Boolean
  Dim bIsInIDE    As Boolean
  Dim lIdEvent    As LongPtr
  #If Not (-VBA6 Or -VBA7) Then
  Debug.Assert MakeTrue(bIsInIDE)
  #End If
  If m_pAsmThunk Then CreateAsm = True: Exit Function
  If GetCodeHeap() = 0 Then Exit Function
  #If Not (-VBA6 Or -VBA7) Then
  If bIsInIDE Then
  #End If
    If m_pEbMode = 0 Then m_pEbMode = SearchEbMode(): If m_pEbMode = 0 Then Exit Function
  #If Not (-VBA6 Or -VBA7) Then
  End If
  #End If
  #If -VBA7 And -Win64 Then
    m_pAsmThunk = Create64BitThunk()
    If m_pAsmThunk = 0 Then Exit Function
    lIdEvent = SetTimer(0, 0, lInterval, m_pAsmThunk)
    If lIdEvent = 0 Then
      HeapFree m_hCodeHeap, HEAP_NO_SERIALIZE, m_pAsmThunk - 4
      m_pAsmThunk = 0
      Exit Function
    End If
    CopyMemory ByVal m_pAsmThunk + &H3A, lIdEvent, Len(lIdEvent)
  #Else
    m_pAsmThunk = Create32BitThunk()
    If m_pAsmThunk = 0 Then Exit Function
    lIdEvent = SetTimer(0, 0, lInterval, m_pAsmThunk)
    If lIdEvent = 0 Then HeapFree m_hCodeHeap, HEAP_NO_SERIALIZE, m_pAsmThunk - 4: m_pAsmThunk = 0: Exit Function
    #If -VBA6 Or -VBA7 Then
    CopyMemory ByVal m_pAsmThunk + &H16, lIdEvent, Len(lIdEvent)
    #Else
    If bIsInIDE Then CopyMemory ByVal m_pAsmThunk + &H16, lIdEvent, Len(lIdEvent)
    #End If
  '// Debug.Print Hex(m_pAsmThunk)
  #End If
  m_lIdEvent = lIdEvent
  CreateAsm = True
End Function

#If -VBA7 And -Win64 Then
' // Search for EbMode function
Private Function SearchEbMode() As LongPtr
  ' / / 0. Côì gãìng lâìy EbMode týÌ các thunk trýõìc
  SearchEbMode = GetEbModeFromThunks()
  If SearchEbMode Then Exit Function
  Dim hVbe            As LongPtr
  Dim e_lfanew        As Long
  Dim iNumOfSec       As Integer
  Dim iOptSize        As Integer
  Dim pSection        As LongPtr
  Dim lIndex          As Long
  Dim cName           As Currency
  Dim pStartScan      As LongPtr
  Dim pEndScan        As LongPtr
  Dim bTemplate(&H5F) As Byte
  Dim bMask(&H5F)     As Byte
  Dim bData()         As Byte
  Dim tSAMap          As SAFEARRAY
  '// 1. Search for VBE7.dll ".text" section
  hVbe = GetModuleHandle(StrPtr("VBE7"))
  If hVbe = 0 Then Exit Function
  CopyMemory e_lfanew, ByVal hVbe + &H3C, 4
  CopyMemory iNumOfSec, ByVal hVbe + e_lfanew + 6, 2
  CopyMemory iOptSize, ByVal hVbe + e_lfanew + &H14, 2
  pSection = hVbe + e_lfanew + &H18 + iOptSize
  For lIndex = 0 To iNumOfSec - 1
    CopyMemory cName, ByVal pSection, 8
    '// Search for ".text" section
    If cName = 50023612.1134@ Then
      CopyMemory pStartScan, ByVal pSection + &HC, 4
      CopyMemory pEndScan, ByVal pSection + &H8, 4
      pStartScan = pStartScan + hVbe
      pEndScan = pEndScan + pStartScan - 1
      Exit For
    End If
    pSection = pSection + &H28
  Next
  If pStartScan = 0 Or pEndScan = 0 Then Exit Function
  '// 2. Search for Proc/MethCallEngine thunk template
  '// 48 89 4C 24 08 48 89 54 24 10 4C 89 44 24 18 4C
  '// 89 4C 24 20 48 B8 11 11 11 11 11 11 11 11 48 0B
  '// C0 74 32 48 B8 XX XX XX XX XX XX XX XX FF D0 48
  '// 83 F8 02 74 20 48 B8 11 11 11 11 11 11 11 11 48
  '// 8B 4C 24 08 48 8B 54 24 10 4C 8B 44 24 18 4C 8B
  '// 4C 24 20 FF E0 48 33 C0 C2 11 11
  '// XX XX XX XX XX XX XX XX - EbMode
  '// Setup template
  CopyMemory bTemplate(&H0), 609147917080124.0392@, 8
  CopyMemory bTemplate(&H8), 548317242310341.8404@, 8
  CopyMemory bTemplate(&H10), 122996679316526.1961@, 8
  CopyMemory bTemplate(&H18), 81291849773882.1905@, 8
  CopyMemory bTemplate(&H20), 79148524.8704@, 8
  CopyMemory bTemplate(&H28), 524697394135171.072@, 8
  CopyMemory bTemplate(&H30), 127684979858204.0707@, 8
  CopyMemory bTemplate(&H38), 519295061033333.9921@, 8
  CopyMemory bTemplate(&H40), 261787042489960.3595@, 8
  CopyMemory bTemplate(&H48), -840931986015968.9712@, 8
  CopyMemory bTemplate(&H50), -459725066342497.3748@, 8
  CopyMemory bTemplate(&H58), 111.8658@, 8
  '// Setup mask
  For lIndex = 0 To UBound(bMask)
    If lIndex < &H25 Or (lIndex > &H2C And lIndex < &H5B) Then
      bMask(lIndex) = 1
    End If
  Next
  '// Map array to data
  With tSAMap
    .cbElements = 1
    .cDims = 1
    .fFeatures = FADF_AUTO
    .Bounds.cElements = CLng(pEndScan - pStartScan) + 1
    .pvData = pStartScan
  End With
  DupArray bData, VarPtr(tSAMap)
  lIndex = FindSignature(bData(), bTemplate(), bMask())
  DupArray bData, 0@
  If lIndex = -1 Then Exit Function
  CopyMemory SearchEbMode, ByVal pStartScan + lIndex + &H25, Len(SearchEbMode)
  Debug.Print "SearchEbMode: "; SearchEbMode
End Function

' // Create 64 bit thunk
Private Function Create64BitThunk() As LongPtr
  Dim pCode           As LongPtr
  Dim llThunk(19)     As Currency
  Dim pfnKillTimer    As LongPtr
  Dim pfnTimerProc    As LongPtr
  Dim pVtbl           As LongPtr
  Dim hUser32         As LongPtr
  If m_hCodeHeap = 0 Then Exit Function
  hUser32 = GetModuleHandle(StrPtr("user32"))
  If hUser32 = 0 Then
    hUser32 = LoadLibrary(StrPtr("user32"))
    If hUser32 = 0 Then Exit Function
  End If
  pfnKillTimer = GetProcAddress(hUser32, "KillTimer")
  If pfnKillTimer = 0 Then Exit Function
  pCode = HeapAlloc(m_hCodeHeap, HEAP_NO_SERIALIZE Or HEAP_ZERO_MEMORY, &H9E)
  If pCode = 0 Then Exit Function
  pCode = pCode + 4   ' // Disable
  '// 48 83 EC 38 48 89 4C 24 40 48 89 54 24 48 4C 89
  '// 44 24 50 4C 89 4C 24 58 48 B8 00 00 00 00 00 00
  '// 00 00 FF D0 48 85 C0 74 06 3C 01 74 23 EB 66 FF
  '// 0D C7 FF FF FF 48 31 C9 48 BA 00 00 00 00 00 00
  '// 00 00 48 B8 00 00 00 00 00 00 00 00 FF D0 EB 45
  '// 48 B9 00 00 00 00 00 00 00 00 48 8B 54 24 40 4C
  '// 8B 44 24 48 4C 8B 4C 24 50 48 8B 44 24 58 48 89
  '// 44 24 20 48 8D 44 24 30 48 C7 00 00 00 00 00 48
  '// 89 44 24 28 48 B8 00 00 00 00 00 00 00 00 FF D0
  '// 48 8B 44 24 30 48 83 C4 38 C3
  llThunk(0) = 261561642688109.0376@
  llThunk(1) = -855338227140910.8928@
  llThunk(2) = 635128552707379.3092@
  llThunk(3) = 4.7176@
  llThunk(4) = 841287065171859.8656@
  llThunk(5) = -4308860891082.0346@
  llThunk(6) = -394929513387840.1267@
  llThunk(7) = 4.7688@
  llThunk(8) = 309172.6336@
  llThunk(9) = 503835040177926.9632@
  llThunk(10) = 4.7432@
  llThunk(11) = 549443149092460.9536@
  llThunk(12) = 261561864333952.7307@
  llThunk(13) = -855449057939821.1504@
  llThunk(14) = 346897298657326.8036@
  llThunk(15) = 518814677073086.2408@
  llThunk(16) = 20262005062.1577@
  llThunk(17) = -338698839475932.3648@
  llThunk(18) = -428650304872247.8264@
  llThunk(19) = 4.9976@
  '// Get TimerProc address
  CopyMemory pVtbl, ByVal ObjPtr(Me), Len(pVtbl)
  CopyMemory pfnTimerProc, ByVal pVtbl + (TIMERPROC_INDEX + 7) * Len(pfnTimerProc), Len(pfnTimerProc)
  CopyMemory ByVal pCode, llThunk(0), &H9A
  CopyMemory ByVal pCode + &H1A, m_pEbMode, Len(m_pEbMode)
  CopyMemory ByVal pCode + &H44, pfnKillTimer, Len(pfnKillTimer)
  CopyMemory ByVal pCode + &H52, ObjPtr(Me), 8
  CopyMemory ByVal pCode + &H86, pfnTimerProc, Len(pfnTimerProc)
  Create64BitThunk = pCode
End Function

#Else

' // Search for EbMode function
Private Function SearchEbMode() As LongPtr
  '// 0. Try to get EbMode from previous thunks
  SearchEbMode = GetEbModeFromThunks(): If SearchEbMode Then Exit Function
  Dim hVbe            As LongPtr
  Dim pSection        As LongPtr
  Dim pStartScan      As LongPtr
  Dim pEndScan        As LongPtr
  Dim e_lfanew        As Long
  Dim iNumOfSec       As Integer
  Dim iOptSize        As Integer
  Dim lIndex          As Long
  Dim cName           As Currency
  Dim bTemplate(&H27) As Byte
  Dim bMask(&H27)     As Byte
  Dim bData()         As Byte
  Dim tSAMap          As SAFEARRAY
  Dim vb$
  '// 1. Search for VBE7/6.dll ".text" section
  #If VBA7 Then
  vb = "VBE7"
  #ElseIf VBA6 Then
  vb = "VBE6"
  #Else
  vb = "VBA6"
  #End If
  hVbe = GetModuleHandle(StrPtr(vb))
  If hVbe = 0 Then Exit Function
  #If -VBA6 Or -VBA7 Then
  CopyMemory e_lfanew, ByVal hVbe + &H3C, 4
  CopyMemory iNumOfSec, ByVal hVbe + e_lfanew + 6, 2
  CopyMemory iOptSize, ByVal hVbe + e_lfanew + &H14, 2
  pSection = hVbe + e_lfanew + &H18 + iOptSize
  For lIndex = 0 To iNumOfSec - 1
    CopyMemory cName, ByVal pSection, 8
    '// Search for ".text" section
    If cName = 50023612.1134@ Then
      CopyMemory pStartScan, ByVal pSection + &HC, 4
      CopyMemory pEndScan, ByVal pSection + &H8, 4
      pStartScan = pStartScan + hVbe
      pEndScan = pEndScan + pStartScan - 1
      Exit For
    End If
    pSection = pSection + &H28
  Next
  If pStartScan = 0 Or pEndScan = 0 Then Exit Function
  '// 2. Search for Proc/MethCallEngine thunk template
  '// A1 YY YY YY YY 0B C0 74 13 B8 XX XX XX XX FF D0
  '// 83 F8 02 74 07 B8 11 11 11 11 FF E0 33 C0 C2 11
  '// 11
  '// XX XX XX XX - EbMode
  '// Setup template
  CopyMemory bTemplate(&H0), 841273619855599.2225@, 8
  CopyMemory bTemplate(&H8), -338698839475927.6525@, 8
  CopyMemory bTemplate(&H10), 122996651539948.9667@, 8
  CopyMemory bTemplate(&H18), 127979657317731.9697@, 8
  CopyMemory bTemplate(&H20), 0.0017@, 8
  '// Setup mask
  For lIndex = 0 To UBound(bMask)
    Select Case lIndex
    Case 1 To 4, 10 To 13, 33 To 40: bMask(lIndex) = 0
    Case Else: bMask(lIndex) = 1
    End Select
  Next
  '// Map array to data
  With tSAMap
    .cbElements = 1
    .cDims = 1
    .fFeatures = FADF_AUTO
    .Bounds.cElements = CLng(pEndScan - pStartScan) + 1
    .pvData = pStartScan
  End With
  DupArray bData, VarPtr(tSAMap)
  lIndex = FindSignature(bData(), bTemplate(), bMask())
  DupArray bData, 0@
  If lIndex = -1 Then Exit Function
  CopyMemory SearchEbMode, ByVal pStartScan + lIndex + &HA, Len(SearchEbMode)
  #Else
  SearchEbMode = GetProcAddress(hVbe, "EbMode")
  #End If
End Function

' // Create 32 bit thunk

Private Function Create32BitThunk() As LongPtr
  Dim pCode           As LongPtr
  Dim pfnKillTimer    As LongPtr
  Dim pfnTimerProc    As LongPtr
  Dim pVtbl           As LongPtr
  Dim hUser32         As LongPtr
  Dim bIsInIDE        As Boolean
  Dim llThunk(8)      As Currency
  #If Not (-VBA6 Or -VBA7) Then
  Debug.Assert MakeTrue(bIsInIDE)
  #Else
  bIsInIDE = True
  #End If
  If m_hCodeHeap = 0 Then Exit Function
  '// Get TimerProc address
  CopyMemory pVtbl, ByVal ObjPtr(Me), Len(pVtbl)
  CopyMemory pfnTimerProc, ByVal pVtbl + (TIMERPROC_INDEX + 7) * Len(pfnTimerProc), Len(pfnTimerProc)
  If bIsInIDE Then
    hUser32 = GetModuleHandle(StrPtr("user32"))
    If hUser32 = 0 Then
      hUser32 = LoadLibrary(StrPtr("user32"))
      If hUser32 = 0 Then Exit Function
    End If
    pfnKillTimer = GetProcAddress(hUser32, "KillTimer")
    If pfnKillTimer = 0 Then Exit Function
    pCode = HeapAlloc(m_hCodeHeap, HEAP_NO_SERIALIZE Or HEAP_ZERO_MEMORY, &H48)
    If pCode = 0 Then Exit Function
    pCode = pCode + 4   ' // Disable
    '// E8 00 00 00 00 85 C0 74 06 3C 01 74 16 EB 32 FF
    '// 0D 00 00 00 00 68 00 00 00 00 6A 00 E8 3A 10 00
    '// 00 EB 1E 6A 00 54 FF 74 24 18 FF 74 24 18 FF 74
    '// 24 18 FF 74 24 18 68 00 00 00 00 E8 00 00 00 00
    '// 58 C2 10 00
    llThunk(0) = 841287033897458.0968@
    llThunk(1) = -5772536353434.9306@
    llThunk(2) = 11434920928.8717@
    llThunk(3) = 456836774114.0992@
    llThunk(4) = 843054938821800.2176@
    llThunk(5) = 843048357232162.2052@
    llThunk(6) = 2929994243867.242@
    llThunk(7) = 389231.4112@
    llThunk(8) = 109.8328@
    CopyMemory ByVal pCode, llThunk(0), &H44
    CopyMemory ByVal pCode + 1, m_pEbMode - (pCode + 5), Len(m_pEbMode)
    CopyMemory ByVal pCode + &H11, pCode - 4, Len(pCode)
    CopyMemory ByVal pCode + &H1D, pfnKillTimer - (pCode + &H1C + 5), Len(pfnKillTimer)
    CopyMemory ByVal pCode + &H37, ObjPtr(Me), Len(pCode)
    CopyMemory ByVal pCode + &H3C, pfnTimerProc - (pCode + &H3B + 5), Len(pfnTimerProc)
  Else
    pCode = HeapAlloc(m_hCodeHeap, HEAP_NO_SERIALIZE Or HEAP_ZERO_MEMORY, &H29)
    If pCode = 0 Then Exit Function
    pCode = pCode + 4   ' // Disable
    llThunk(0) = -6526210967837.071@
    llThunk(1) = -6526210968229.3644@
    llThunk(2) = 174641.266@
    llThunk(3) = 120762440711195.876@
    CopyMemory ByVal pCode, llThunk(0), &H25
    CopyMemory ByVal pCode + &H14, ObjPtr(Me), Len(pCode)
    CopyMemory ByVal pCode + &H19, pfnTimerProc - (pCode + &H18 + 5), Len(pfnTimerProc)
  End If
  Create32BitThunk = pCode
End Function

#End If

'//TiÌm kiêìm chýÞ kyì bãÌng Mask
Private Function FindSignature(ByRef bData() As Byte, ByRef bSignature() As Byte, ByRef bMask() As Byte) As Long
  Dim lDataIndex  As Long
  Dim lSignIndex  As Long
  lDataIndex = 0: lSignIndex = 0
  Do While lDataIndex <= UBound(bData)
    If bData(lDataIndex) = bSignature(lSignIndex) Or bMask(lSignIndex) = 0 Then
      lSignIndex = lSignIndex + 1
      If lSignIndex > UBound(bSignature) Then
        FindSignature = lDataIndex - UBound(bSignature)
        Exit Function
      End If
    Else
      If lSignIndex Then
        lDataIndex = lDataIndex - lSignIndex + 1
        lSignIndex = 0
      End If
    End If
    lDataIndex = lDataIndex + 1
  Loop
  FindSignature = -1
End Function

' // Nhâòn heap cho asm thunks
'/ / Lõìp lýu nó vào biêìn env toàn cuòc
Private Function GetCodeHeap() As LongPtr
  Dim sHeapHandleString   As String
  Dim lIndex              As Long
  If m_hCodeHeap Then GetCodeHeap = m_hCodeHeap:       Exit Function
  sHeapHandleString = Space$(Len(GetCodeHeap) * 2)
  If GetEnvironmentVariable(StrPtr(HEAP_ENV_VARIABLE), StrPtr(sHeapHandleString), LenB(sHeapHandleString)) Then
    #If VBA7 Then
    m_hCodeHeap = CLngPtr("&H" & sHeapHandleString)
    #Else
    m_hCodeHeap = CLng("&H" & sHeapHandleString)
    #End If
    GetCodeHeap = m_hCodeHeap
    Exit Function
  End If
  m_hCodeHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE Or HEAP_NO_SERIALIZE, 0, 0)
  If m_hCodeHeap = 0 Then Exit Function
  sHeapHandleString = Hex$(m_hCodeHeap)
  For lIndex = Len(sHeapHandleString) + 1 To Len(GetCodeHeap) * 2
    sHeapHandleString = "0" & sHeapHandleString
  Next
  SetEnvironmentVariable StrPtr(HEAP_ENV_VARIABLE), StrPtr(sHeapHandleString)
  GetCodeHeap = m_hCodeHeap
End Function


'/ / Trích xuâìt hàm EbMode týÌ thunks trýõìc ðó
Private Function GetEbModeFromThunks() As LongPtr
  Dim tEntry  As PROCESS_HEAP_ENTRY
  If m_hCodeHeap = 0 Then Exit Function
  HeapLock m_hCodeHeap
  Do While HeapWalk(m_hCodeHeap, tEntry)
    #If -VBA7 And -Win64 Then
    If tEntry.wFlags And PROCESS_HEAP_ENTRY_BUSY And tEntry.cbData >= &H1E Then
      CopyMemory GetEbModeFromThunks, ByVal tEntry.lpData + &H1E, Len(GetEbModeFromThunks)
    #Else
    If tEntry.wFlags And PROCESS_HEAP_ENTRY_BUSY And tEntry.cbData >= &H1E Then
      CopyMemory GetEbModeFromThunks, ByVal tEntry.lpData + &H5, Len(GetEbModeFromThunks)
      GetEbModeFromThunks = GetEbModeFromThunks + (tEntry.lpData + &H4) + 5
    #End If
      Exit Do
    End If
  Loop
  HeapUnlock m_hCodeHeap
End Function

' // KiêÒm tra xem có thunks nào không hoaòt ðôòng không và giaÒi phóng chúng
' // TraÒ vêÌ sôì thunk ðang hoaòt ðôòng
Private Function CleanupThunks() As Long
  Dim tEntry      As PROCESS_HEAP_ENTRY
  Dim lDisable    As Long
  Dim lCount      As Long
  Dim pThunk      As LongPtr
  If m_hCodeHeap = 0 Then Exit Function
  HeapLock m_hCodeHeap
  Do While HeapWalk(m_hCodeHeap, tEntry)
    If pThunk Then HeapFree m_hCodeHeap, HEAP_NO_SERIALIZE, pThunk: pThunk = 0
    If tEntry.wFlags And PROCESS_HEAP_ENTRY_BUSY And tEntry.cbData >= Len(lDisable) Then
      '// Check if disabled
      CopyMemory lDisable, ByVal tEntry.lpData, Len(lDisable)
      If lDisable Then pThunk = tEntry.lpData Else lCount = lCount + 1
    End If
  Loop
  If pThunk Then HeapFree m_hCodeHeap, HEAP_NO_SERIALIZE, pThunk
  HeapUnlock m_hCodeHeap
  CleanupThunks = lCount
End Function

Private Sub Class_Terminate()
  If m_lIdEvent Then
    KillTimer 0, m_lIdEvent
    m_lIdEvent = 0
  End If
  If m_pAsmThunk Then
    HeapFree m_hCodeHeap, HEAP_NO_SERIALIZE, m_pAsmThunk - 4
    m_pAsmThunk = 0
  End If
  If CleanupThunks() = 0 Then
    HeapDestroy m_hCodeHeap
    m_hCodeHeap = 0
    SetEnvironmentVariable StrPtr(HEAP_ENV_VARIABLE), 0
  End If
End Sub

#If Not (-VBA6 Or -VBA7) Then
Private Function MakeTrue(ByRef bValue As Boolean) As Boolean: bValue = True: MakeTrue = True: End Function
#End If
 
Upvote 0
@ongke0711 Tốt nhất là lập trình API sử dụng thư viện comctl32.dll sử dụng SysListView32 nha anh

Mã này viết vui, chứ lợi bất cập hại.
 

File đính kèm

  • KetNoiExcel_Access_Listview.xlsm
    58 KB · Đọc: 9
Upvote 0

Chi tiết API khai báo cao siêu hay cấp thấp ở link sau

giới thiệu cho VBA và VB6 link sau

Copy ở đâu thì cũng nên tôn trọng tác giả một chút
 
Lần chỉnh sửa cuối:
Upvote 0
Cứ thử đi thử lại nhiều lần. Kinh nghiệm sẽ dạy cho biết
Cách đây vài ngày tôi cũng nói vậy, lúc xin form hoành tráng của ongke
Bạn có khuynh hướng giống nhiều người xin code ở đây. Đã không tự viết code được mà còn đòi "tối ưu". Đòi vậy tưởng là hoành tráng, nhưng gặp thằng cắc cớ nó hỏi: "chỗ này làm gì vậy?" thì muối mặt.
Bên chủ đề Alt + x không chạy cũng tình trạng này. Toàn code sao chép chắp vá mà xài đồ cao siêu để ẩn title, không biết khi nào sử dụng sự kiện nào, lỗi thì chỉ khóc chứ không biết sửa.
 
Upvote 0
Tôn trọng tác giả ở đây này mấy 3, The trick chính là nickname của lập trình viên VB6 có tiếng trên vbforum.

Tôi đâu có để là "The Sanbi"

JavaScript:
' //
' // 64/32 bit timer class for VBA
' // by The trick 2019
' //
 
Upvote 0
Web KT
Back
Top Bottom