Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function SetTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As LongPtr, ByVal lpTimerFunc As LongPtr) As Long
Private Declare PtrSafe Function KillTimer Lib "USER32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
#Else
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
#End If
'///////////////////////////////////////////////////////
#If Win64 Then
Private gTimerID As LongPtr
#Else
Private gTimerID As Long
#End If
'///////////////////////////////////////////////////////
Private RemoveRowsBlankAgrs(), RemoveRowsBlankIndex As Integer
Function S_RemoveRowsBlank(ByVal WithCell As Excel.Range, _
Optional ByVal ColumnsCheckNull As String = "0") As String
On Error Resume Next
KillTimer 0&, gTimerID: gTimerID = 0
'-----------------------------------------------
S_RemoveRowsBlank = VBA.Replace(VBA.Mid(Application.Caller.Formula, 2), "S_RemoveRowsBlank", "S_RemoveRowsBlank", , , 1)
'-----------------------------------------------
Dim UB As Integer, i As Integer, f As Integer, K As Integer, Fit, Arg
Set WithCell = WithCell.Parent.Range(WithCell.Address)
'-----------------------------------------------
UB = UBound(RemoveRowsBlankAgrs, 2): K = UB
If K > 0 Then GoSub CheckIn
If f = 0 Then K = K + 1:
ReDim Preserve RemoveRowsBlankAgrs(1 To 2, 1 To K)
Set RemoveRowsBlankAgrs(1, K) = WithCell
RemoveRowsBlankAgrs(2, K) = ColumnsCheckNull
gTimerID = SetTimer(0&, 0&, 0, AddressOf S_RemoveRowsBlank_callback)
Exit Function
CheckIn:
i = VBA.IIf(RemoveRowsBlankIndex > 0 And RemoveRowsBlankIndex <= K, RemoveRowsBlankIndex, 1)
For f = i To K
If RemoveRowsBlankAgrs(2, f).Worksheet Is WithCell.Worksheet Then
If RemoveRowsBlankAgrs(2, f).Address = WithCell.Address Then Return
End If
Next
f = 0
Return
End Function
'///////////////////////////////////////////////////////
Private Sub S_RemoveRowsBlank_callback()
On Error Resume Next
Static EarliestTime As Date, Procedure As String
Procedure = "'" & ThisWorkbook.Name & "'!S_RemoveRowsBlank_callback"
Call KillTimer(0&, gTimerID): gTimerID = 0
Call Application.OnTime(EarliestTime, Procedure, , False)
'----------------------------------
Dim UB As Integer
UB = UBound(RemoveRowsBlankAgrs, 2)
If UB > 0 Then
RemoveRowsBlankIndex = RemoveRowsBlankIndex + 1
Call RemoveRowsBlank(RemoveRowsBlankAgrs(1, RemoveRowsBlankIndex), RemoveRowsBlankAgrs(2, RemoveRowsBlankIndex))
If RemoveRowsBlankIndex >= UB Then
Erase RemoveRowsBlankAgrs: RemoveRowsBlankIndex = 0
Else
EarliestTime = VBA.Now()
Call Application.OnTime(EarliestTime, Procedure)
End If
End If
End Sub
Private Sub RemoveRowsBlank(Optional ByVal Target As Range, Optional ByVal ColumnsCheckNull As String = "1")
Dim Arr, cdt As String
Dim r&, c%, cc%, LC&, LR&, rng As Range
On Error Resume Next
With Target.Parent
LR = .Cells.Find("*", After:=.Cells(1), LookIn:=xlFormulas, LookAt:=xlWhole, SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row - Target.Row + 1
LC = .Cells.Find("*", After:=.Cells(1), LookIn:=xlFormulas, LookAt:=xlWhole, SearchDirection:=xlPrevious, SearchOrder:=xlByColumns).Column - Target.Column + 1
Set rng = Target.Resize(LR, LC)
If LR <= 2 Or LC <= 0 Then Exit Sub
On Error Resume Next
Dim CN As Object, Rs As Object
Set CN = VBA.Interaction.CreateObject("ADODB.Connection")
CN.Open SyncConnectionXL(Target.Parent.Parent.FullName, , False)
If ColumnsCheckNull <= "0" Then
For c = 1 To LC
cdt = cdt & IIf(cdt = "", "", " OR ") & "(F" & CStr(c) & " IS NOT NULL)"
Next
Else
Dim SP() As String, rr%
SP = Split(ColumnsCheckNull, ",")
For c = 0 To UBound(SP)
If VBA.IsNumeric(SP(c)) Then
cdt = cdt & IIf(cdt = "", "", " OR ") & "(F" & CStr(SP(c)) & " IS NOT NULL)"
Else
For cc = Columns(SP(c)).Column To Columns(SP(c)).Column + Columns(SP(c)).Columns.Count - 1
If cc - Target.Row + 1 > 0 Then
cdt = cdt & IIf(cdt = "", "", " OR ") & "(F" & CStr(cc - Target.Row + 1) & " IS NOT NULL)"
End If
Next
End If
Next
End If
Err.Clear
Set Rs = CN.Execute("SELECT * FROM [" & .Name & "$" & rng.Address(0, 0) & "] WHERE (" & cdt & ")")
If Err.Number = 0 Then
If Not Rs.EOF Then
r = Target.CopyFromRecordset(Rs)
End If
End If
Rs.Close
If LR - r > 0 And r > 0 Then
Target(r + 1, 1).Resize(LR - r, LC).ClearContents
End If
Set CN = Nothing: Set Rs = Nothing
End With
Ends:
On Error GoTo 0
End Sub
Public Function SyncConnectionXL(ByVal DataSource As String, _
Optional ByVal Mode As String = "Read", _
Optional ByVal Header As Boolean = True, _
Optional ByVal FormatFileText As String = "Delimited") As String
Dim cnt As String, XL As String, HDR As String
HDR = VBA.IIf(Header, "YES", "NO")
If Application.Version >= 12 Then
XL = "12.0": cnt = ("provider=Microsoft.ACE.OLEDB.12.0;Data source='" & DataSource & "';mode=" & Mode & ";")
Else
XL = "8.0": cnt = ("Provider=Microsoft.Jet.OLEDB.4.0;Data Source='" & DataSource & "';mode=" & Mode & ";")
End If
DataSource = VBA.LCase(DataSource)
Select Case Right(DataSource, 4)
Case "xlsx":
cnt = cnt & "Extended Properties=""Excel " & XL & " Xml;HDR=" & HDR & ";imex=1"";"
Case ".csv", ".txt":
cnt = cnt & "Extended Properties=""Text;HDR=" & HDR & ";FMT=" & FormatFileText & ";"";"
Case "xlsb":
cnt = cnt & "Extended Properties=""Excel " & XL & ";HDR=" & HDR & ";"";"
Case "xlsm", "xlam":
cnt = cnt & "Extended Properties=""Excel " & XL & " Macro;HDR=" & HDR & ";"";"
Case ".xla", ".xls"
cnt = cnt & "Extended Properties=""Excel 8.0;HDR=" & HDR & ";"";"
End Select
SyncConnectionXL = cnt
End Function