HTMLWindow2オブジェクト(IHTMLWindow2インターフェース)のsetIntervalメソッドを利用することで、APIを使用せずにタイマーを利用することができます。
このタイマー機能を利用することでModalDialogが表示された状態でもループ処理が行えるようになります。
※ moug にて、shiraさんから教えて頂いた方法でInternet Explorer 8環境でも動作確認できました。この場を借りてお礼申し上げます。
[ThisWorkbook]
Option Explicit
Private d As Object
Private TimerId As Long
Public Sub Sample()
Call StartTimer
MsgBox "タイマー処理を開始しました。" & vbCrLf & _
"タイマーID:" & TimerId, vbInformation + vbSystemModal
Call EndTimer
MsgBox "タイマー処理を終了しました。", vbInformation + vbSystemModal
End Sub
Public Sub StartTimer()
If TimerId <> 0& Then Exit Sub
Set d = CreateObject("htmlfile")
Set d.parentWindow.onhelp = Me
TimerId = d.parentWindow.setInterval("onhelp.TimerProc", 10&, "VBScript")
Debug.Print "--- タイマー開始 --- (" & Hex(TimerId) & ")" '確認用
End Sub
Public Sub EndTimer()
If TimerId = 0& Then Exit Sub
Call d.parentWindow.clearInterval(TimerId)
TimerId = 0&
Set d = Nothing
Debug.Print "--- タイマー終了 ---" '確認用
End Sub
Public Sub TimerProc()
Static n As Long
n = n + 1
ActiveSheet.Range("A1").Value = n
End Sub
また、moug でshiraさんが載せられた他のサンプルコードも掲載しておきます(ログが流れてしまうので…)。
サンプルコード1 [ThisWorkbook]
Private m_TimerId As Variant
Private m_doc As Object
Const ATTRNAME = "VBATimerHandler"
Private Sub StartTimer()
Const Script = "document.documentElement.getAttribute('" & _
ATTRNAME & "').TimerProc()"
EndTimer
Set m_doc = CreateObject("htmlfile")
m_doc.DocumentElement.setAttribute ATTRNAME, Me
m_TimerId = m_doc.parentWindow.setInterval(Script, 1000)
End Sub
Private Sub EndTimer()
If m_doc Is Nothing Then Exit Sub
If Not IsEmpty(m_TimerId) Then
m_doc.parentWindow.clearInterval m_TimerId
m_TimerId = Empty
End If
m_doc.DocumentElement.removeAttribute ATTRNAME
Set m_doc = Nothing
End Sub
Public Sub TimerProc()
Debug.Print Now()
End Sub
サンプルコード2 [ThisWorkbook]
Private m_TimerId As Variant
Private m_doc As Object
Private m_sc As Object
Private Sub StartTimer()
EndTimer
Set m_doc = CreateObject("htmlfile")
Set m_sc = CreateObject("ScriptControl")
With m_sc
.Language = "JScript"
.AddObject "o", Me
.AddCode "function f(){o.TimerProc()}"
End With
m_TimerId = m_doc.parentWindow.setInterval(m_sc.Eval("f"), 1000)
End Sub
Private Sub EndTimer()
If m_doc Is Nothing Then Exit Sub
If Not IsEmpty(m_TimerId) Then
m_doc.parentWindow.clearInterval m_TimerId
m_TimerId = Empty
End If
Set m_sc = Nothing
Set m_doc = Nothing
End Sub
Public Sub TimerProc()
Debug.Print Now()
End Sub