一時停止中のウィンドウ再描画          <TOP>


CreateWaitableTimer 「待機可能」タイマオブジェクトを作成

OpenWaitableTimer 既存の名前付き「待機可能」タイマオブジェクトのハンドルを取得

SetWaitableTimer 指定した「待機可能」タイマをアクティブにする

CancelWaitableTimer 指定した「待機可能」タイマをアクティブでない状態に設定

CloseHandle オープンされているオブジェクトハンドルをクローズ

MsgWaitForMultipleObjects シグナル状態になったとき、またはタイムアウト時間が経過したとき制御を戻す

Sleep カレントスレッドの実行を指定の時間だけ中断

 

例では、どちらも約10秒間一時停止させています。

「Sleep」で一時停止中に他のウィンドウが被った場合は再描画されません。「SetWaitableTimer」で一時停止中は再描画されます。

参照

http://support.microsoft.com/kb/231298/ja
Visual BasicでSetWaitableTimerを使用する方法

 

'================================================================
'= 一時停止中のウィンドウ再描画
'=    (SetWaitableTimer.bas)
'================================================================
#include "Windows.bi"

Type FILETIME
    dwLowDateTime As Long
    dwHighDateTime As Long
End Type

#define WAIT_ABANDONED &H80             'オブジェクトがmutexの場合だけ
#define WAIT_ABANDONED_0 &H80           'オブジェクトがシグナル状態
#define WAIT_FAILED -1                  'エラーが発生したことを示す
#define WAIT_IO_COMPLETION &HC0         'I/O完了コールバック関数の呼び出しによって戻った
#define WAIT_OBJECT_0 &H0               'オブジェクトがシグナル状態になったことを示す
#define WAIT_OBJECT_1 1                 '
#define WAIT_TIMEOUT &H102              'タイムアウト時間が経過したことを示す

#define INFINITE &HFFFF                 '無限に中断
#define ERROR_ALREADY_EXISTS 183        '既に存在している

#define QS_HOTKEY &H80                  'WM_HOTKEY
#define QS_KEY &H1                      'WM_KEYUP・WM_KEYDOWN・WM_SYSKEYUP・WM_SYSKEYDOWN
#define QS_MOUSEBUTTON &H4              'WM_LBUTTONUP・WM_RBUTTONDOWN
#define QS_MOUSEMOVE &H2                'WM_MOUSEMOVE
#define QS_PAINT &H20                   'WM_PAINT
#define QS_POSTMESSAGE &H8              'キューに何らかのメッセージが入った
#define QS_SENDMESSAGE &H40             '他のスレッドから送られたメッセージがある
#define QS_TIMER &H10                   'WM_TIMER
#define QS_MOUSE (&H2 Or &H4)           '(QS_MOUSEMOVE Or QS_MOUSEBUTTON)
#define QS_INPUT (&H2 Or &H4 Or &H1)    '(QS_MOUSE Or QS_KEY)
#define QS_ALLEVENTS (&H2 Or &H4 Or &H1 Or &H8 Or &H10 Or &H20 Or &H80)        '(QS_INPUT Or QS_POSTMESSAGE Or QS_TIMER Or QS_PAINT Or QS_HOTKEY)
#define QS_ALLINPUT (&H40 Or &H20 Or &H10 Or &H8 Or &H4 Or &H2 Or &H80 Or &H1) '(QS_SENDMESSAGE Or QS_PAINT Or QS_TIMER Or QS_POSTMESSAGE Or QS_MOUSEBUTTON Or QS_MOUSEMOVE Or QS_HOTKEY Or QS_KEY)

' 「待機可能」タイマオブジェクトを作成
Declare Function Api_CreateWaitableTimer& Lib "kernel32" Alias "CreateWaitableTimerA" (ByVal lpSemaphoreAttributes&, ByVal bManualReset&, ByVal lpName$)

' 既存の名前付き「待機可能」タイマオブジェクトのハンドルを取得
Declare Function Api_OpenWaitableTimer& Lib "kernel32" Alias "OpenWaitableTimerA" (ByVal dwDesiredAccess&, ByVal bInheritHandle&, ByVal lpName$)

' 指定した「待機可能」タイマをアクティブにする
Declare Function Api_SetWaitableTimer& Lib "kernel32" Alias "SetWaitableTimer" (ByVal hTimer&, lpDueTime As FILETIME, ByVal lPeriod&, ByVal pfnCompletionRoutine&, ByVal lpArgToCompletionRoutine&, ByVal fResume&)

' 指定した「待機可能」タイマをアクティブでない状態に設定
Declare Function Api_CancelWaitableTimer& Lib "kernel32" Alias "CancelWaitableTimer" (ByVal hTimer&)

' オープンされているオブジェクトハンドルをクローズ
Declare Function Api_CloseHandle& Lib "Kernel32" Alias "CloseHandle" (ByVal hObject&)

' 指定したオブジェクトのいずれか1つまたはすべてがシグナル状態になったとき、またはタイムアウト時間が経過したとき制御を戻す
Declare Function Api_MsgWaitForMultipleObjects& Lib "user32" Alias "MsgWaitForMultipleObjects" (ByVal nCount&, pHandles&, ByVal fWaitAll&, ByVal dwMilliseconds&, ByVal dwWakeMask&)

' カレントスレッドの実行を指定の時間だけ中断
Declare Sub Api_Sleep Lib "Kernel32" Alias "Sleep" (ByVal dwMilliseconds&)

Var Shared Button1 As Object
Var Shared Button2 As Object

Button1.Attach GetDlgItem("Button1") : Button1.SetFontSize 14
Button2.Attach GetDlgItem("Button2") : Button2.SetFontSize 14

'================================================================
'= 
'================================================================
Declare Sub sWait(lNumberOfSeconds As Long)
Sub sWait(lNumberOfSeconds As Long)
    Var ft As FILETIME
    Var Busy As Long
    Var Delay As Double
    Var DelayLow As Double
    Var Units As Double
    Var hTimer As Long
    Var Ret As Long

    hTimer = Api_CreateWaitableTimer(0, True, "TestTimer")

    ft.dwLowDateTime = -1
    ft.dwHighDateTime = -1

    '「待機可能」タイマをアクティブ
    Ret = Api_SetWaitableTimer(hTimer, ft, 0, 0, 0, 0)

    'ユニットをナノ秒に変換
    Units = CDbl(&H10000) * CDbl(&H10000)
    Delay = CDbl(lNumberOfSeconds) * 1000 * 10000

    ft.dwHighDateTime = -CLng(Delay / Units) - 1
    DelayLow = -Units * (Delay / Units - Fix(Delay / Units))

    If DelayLow < CDbl(-2147483648) Then
        DelayLow = Units + DelayLow
        ft.dwHighDateTime = ft.dwHighDateTime + 1
    End If

    ft.dwLowDateTime = CLng(DelayLow)

    '「待機可能」タイマをアクティブ
    Ret = Api_SetWaitableTimer(hTimer, ft, 0, 0, 0, False)

    Do
        Busy = Api_MsgWaitForMultipleObjects(1, hTimer, False, INFINITE, QS_ALLINPUT)
        CallEvent
    Loop Until Busy = WAIT_OBJECT_0

    Ret = Api_CloseHandle(hTimer)
End Sub

'================================================================
'= SetWaitableTimerを使用した一時停止
'================================================================
Declare Sub Button1_on edecl ()
Sub Button1_on()
    Var Ret As Long

    Button1.EnableWindow 0
    sWait 10
    Button1.EnableWindow -1
End Sub

'================================================================
'= Sleepを使用した一時停止
'================================================================
Declare Sub Button2_on edecl ()
Sub Button2_on()
    Var Ret As Long

    Button2.EnableWindow 0
    Api_Sleep 10000
    Button2.EnableWindow -1
End Sub

'================================================================
'=
'================================================================
While 1
    WaitEvent
Wend
Stop
End