tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルスクリーンセーバーの解除
記事No14228
投稿日: 2009/11/06(Fri) 17:31
投稿者ジョニー
いつも参考にさせて頂いてました
開発環境は VB6+SP6 WindowsXPSP2相当です ターゲットPCも同様です

ずっと以前に納めたソフト(NT4)をXPに移行することになり、そのままのコードで流用していたのですが
スクリーンセーバーの解除ができない現象に悩まされています

セーバーがかかっていたときにはこちらのサンプル
http://hanatyan.sakura.ne.jp/vbhlp/SaverOff.htm

とほぼ同様の手順で、マウスカーソルを移動させているのですが
セーバー解除できないときが発生します

   Dim CurPos As MoPoint
   RetVal& = GetCursorPos(CurPos)
   Call SetCursorPos(0, 0): DoEvents
   Call SetCursorPos(CurPos.x, CurPos.y): DoEvents

以前の環境では問題なくできていたはずですので、今回XPでできない理由がわかりません
ちなみに、ブレークを張って見張ると必ず解除されます

Doeventsの個数を増やして実験もしましたが、改善されません
サンプルコードはXPも対応されているとのことですのでSPかなにかで条件変わっているのでしょうか?

アドバイス頂けると幸いです

[ツリー表示へ]
タイトルRe: スクリーンセーバーの解除
記事No14229
投稿日: 2009/11/06(Fri) 18:30
投稿者花ちゃん
下記のようにマウスカーソルを移動する処で、一度フォーカスを移して見て下さい。

Me.SetFocus   'これだけでも OK かも知れない。
Call SetCursorPos(0, 0): DoEvents

念の為、3D系のスクリーンセーバーを起動して、Vista 環境でも試してみましたが、
一応問題なく解除されました。

[ツリー表示へ]
タイトルRe: スクリーンセーバーの解除
記事No14230
投稿日: 2009/11/06(Fri) 19:32
投稿者オショウ
> とほぼ同様の手順で、マウスカーソルを移動させているのですが
> セーバー解除できないときが発生します

  その方法でできない場合もあるみたいですが・・・
  テストされた折のスクリーンセーバーは何だったのでしょうか?

  できない原因は、WM_SYSCOMMAND/SC_SCREANSAVEメッセージをブロード
  キャストしてくれないものの場合・・・(多分)

● WndProcをフックして行うケース

' Module.bas

Option Explicit

Declare Function CallWindowProc Lib "user32" Alias _
   "CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
   ByVal hMainWnd As Long, ByVal Msg As Long, _
   ByVal wParam As Long, ByVal lParam As Long) As Long

Declare Function SetWindowLong Lib "user32" Alias _
   "SetWindowLongA" (ByVal hMainWnd As Long, _
   ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    
Public Const GWL_WNDPROC As Long = -4
Public Const WM_SYSCOMMAND As Long = &H112
Public Const SC_SCREENSAVE As Long = &HF140
    
Private lpPrevWndProc As Long
Private hWndBack As Long

Public Sub Hook(ByVal hMainWnd As Long)

    hWndBack = hMainWnd
    lpPrevWndProc = SetWindowLong(hMainWnd, GWL_WNDPROC, AddressOf WndProc)
    
End Sub

Public Sub Unhook()

    Dim temp As Long
    
    temp = SetWindowLong(hWndBack, GWL_WNDPROC, lpPrevWndProc)
    
End Sub

Public Function WndProc(ByVal hw As Long, ByVal uMsg As _
       Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Select Case uMsg
    Case WM_SYSCOMMAND
        Beep
        If wParam = SC_SCREENSAVE Then
            WndProc = 1
            Exit Function
        End If
    End Select
    
    WndProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam)
    
End Function

' Form1.frm

Private Sub Form_Load()

    Call Hook(Me.hWnd)
  
End Sub

Private Sub Form_Unload(Cancel As Integer)

    Unhook
    
End Sub

Private Sub Command1_Click()

    Me.Hide
    Unload Me
    
End Sub

● タイマーで、SetThreadExecutionState API を呼ぶケース

' Module.bas

Declare Function SetThreadExecutionState Lib "kernel32.dll" (ByVal esFlags As Long) As Long

Public Const ES_SYSTEM_REQUIRED As Long = &H1
Public Const ES_DISPLAY_REQUIRED As Long = &H2
Public Const ES_CONTINUOUS As Long = &H80000000

' Form1.frm

Private Sub Form_Load()

    Timer1.Enabled = False
    Timer1.Interval = 5000
    Timer1.Enabled = True
  
End Sub

Private Sub Command1_Click()

    Timer1.Enabled = False

    Me.Hide
    Unload Me
    
End Sub

Private Sub Timer1_Timer()

    SetThreadExecutionState (ES_SYSTEM_REQUIRED Or ES_DISP_REQUIRED)

End Sub

※ WinXP なら、多分、両方OKだと思いますが・・・
  VISTA以降なら、管理者権限が必要でした。

※ VB.NETの場合は、WndProcフックタイプでOKでした。
  管理者権限は不必要でした。
  多分、SetThreadExecutionState API を呼ぶ方もOKかと。

以上。参考まで

[ツリー表示へ]
タイトルRe^2: スクリーンセーバーの解除
記事No14232
投稿日: 2009/11/06(Fri) 23:42
投稿者ジョニー
花ちゃん様 オショウ様 早速のアドバイスありがとうございます
現在VBの環境無いため、明日確認させて頂きます

>  Me.SetFocus   'これだけでも OK かも知れない。
な・・・なるほど 妙に納得しました 環境にて確認し結果報告させて頂きます

>  テストされた折のスクリーンセーバーは何だったのでしょうか?
実際に使用されるエンドユーザーは不明ですが、当方は伝言板で確認しています
また、選択範囲はWindows標準搭載のものからになります

SetThreadExecutionState API
このAPIの存在知りませんでした

花ちゃんさんのもので対応できなかった場合を想定し、試してみます


まずはお礼まで

[ツリー表示へ]
タイトルRe^3: スクリーンセーバーの解除
記事No14234
投稿日: 2009/11/07(Sat) 15:35
投稿者ジョニー
板が見にくくなってすみません
花ちゃん様のSetFocusを使う方法
自分の開発環境では改善されました

それを実際のアプリコードに引用して見たところ、なぜかお客様のPCでは解除できないまま
記述コードがフォーム上に無いため、存在する別のフォームにSetFocusしてあるんですけど・・・

Doeventsの追加や他の選択可能なコントロールにSetFocus それの複数追加しても改善されないまま
なぜでしょうかね

オショウさんの対応を検討してみることにします

[ツリー表示へ]
タイトルRe^4: スクリーンセーバーの解除
記事No14235
投稿日: 2009/11/07(Sat) 18:35
投稿者花ちゃん
> 記述コードがフォーム上に無いため、存在する別のフォームにSetFocusしてあるんで

多分その辺が問題かと思います。
終了後、一度、Form 上にコードを戻してから、そのForm上に解除のコードを書けば
いいかと思います。

[ツリー表示へ]
タイトル【解決】Re^5: スクリーンセーバーの解除
記事No14236
投稿日: 2009/11/08(Sun) 16:13
投稿者ジョニー
花ちゃん様 アドバイスありがとうございます
まさにご指摘の通りで、存在するフォーム上に新規関数作成し処理させたところ、無事セーバーが解除されるようになりました

オショウ様の方法は試してみて、実験ではうまくいくこともわかりましたが
フック関数を使うことに抵抗があって(他のルーチンや総合的な動作への支障)、組み込むか悩んでおりました

花ちゃん様のコードであればVBだけの仕様ですみますので、他への影響も少ないと想像できたため、こちらで対応させて頂こうと思っております

このたびはいろいろアドバイス頂きありがとうございました 大変助かりました

願わくば、セーバー解除のサンプルに
SetFocusの追加、フォーム上のコードで記述することの注記を追記して頂けましたら幸いです
今更こんな事で悩む人はほぼいないこととは存じますが・・・(汗)

[ツリー表示へ]