モニタ電源の入り切り制御の方法は?

解決


take  2008-10-02 18:58:14  No: 32079

モニタの電源を切る設定をして、モニタの電源が切れた状態のパソコンを、
イベント内で復帰させ、表示が出るようにしたいのですがうまくいきません。

検索するとSendMessageやmouse_eventで解決できるとの情報から
下記のような命令をタイマー内で実行しましたが
モニタは復旧しませんでした。

なおスクリーンセーバの解除は「SetCursorPos」で出来ております。

環境はXP ServicePack3のノートパソコンです。

    // モニタのON/OFFをしてみる
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER,  2);
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER,  -1);

    // マウスを動かしたように見せかける
    mouse_event(MOUSEEVENTF_MOVE,100,100,0, GetMessageExtraInfo() );

よろしくお願いします。


monaa  2008-10-03 03:40:19  No: 32080

Vista,Desktop環境では問題なく動作することを確認しました。

procedure TForm1.Button1Click(Sender: TObject);
begin
  //OFF=2, ON=-1, (省エネ=1)
  SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, 2);
  sleep(3000);
  SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, -1);
end;


take  2008-10-03 17:25:27  No: 32081

レスありがとうございます。
しかし試したところ、やはり画面は復帰しません。

>procedure TForm1.Button1Click(Sender: TObject);
ボタンイベントで試されたということは
キーを押した事で画面が復帰したのではないでしょうか?

こちらで試したソースです。

モニタの電源を切るを1分後に設定
Intervalを80000に設定したタイマーとボタンをフォームに設置

procedure TForm1.Button1Click(Sender: TObject);
begin
  Timer1.Enabled := True;
end;

procedure TForm1.ScreenServerOff;
begin
  SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, 2);
  sleep(3000);
  SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, -1);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  ScreenServerOff();
end;


monaa  2008-10-03 19:23:57  No: 32082

私の環境ではということですが、
実際には二種類チェックしました。
上記ソースで、ボタンを押して何もしない。
Windowsの自動的にモニタの電源を切る(1分)で
1分30秒後にモニタの電源を入れる指令をタイマーで走らせ何もしない。
いずれも、モニタの電源はOFFからONに切り替わりました。
おそらく、関数的には目的の動作を果たしていると思われます。
もちろんモニタOFF中にマウスを動かしたり等はしていません。
モニタの電源OFFと言っても、No signalの事で物理的にモニタの電源が切れるわけではありません。(当然ですが)


take  2008-10-03 20:30:33  No: 32083

ボタンクリックイベントの件、こちらの勘違いだったようで申し訳ないです。
上記サンプルを何度か試したところ
「時々表示が復帰する」
という現象でした。さらに復帰しても1秒後にはモニタOFFに
なってしまいます。

検索すると同じ悩みを持ち、解決に至った人がいましたので
http://d.hatena.ne.jp/NyaRuRu/20080925/p1

同じようにWindowsMessageの停止ができないか処理を考えてみる事にします。
解決までもう少々時間ください。


take  2008-10-03 22:02:57  No: 32084

Windowsメッセージを奪っても今度は再度1分後に自動で電源をOFFするのが
困難なようです。

kernel32.dll内のSetThreadExecutionStateを呼ぶのが最も理想の動作で
あったため、作成してみました。

kernel32.dllが無いと起動すらしなくなるのが嫌なので
動的DLLで呼び出していますが
実際はたった1命令で済ませる事もできそうです。

自己解決してしまいましたが、様々な助言を頂いた事、感謝いたします。

  // SetThreadExecutionState APIの引数
const
  ES_CONTINUOUS       = $80000000;
  ES_SYSTEM_REQUIRED  = $00000001;
  ES_DISPLAY_REQUIRED = $00000002;

type TSetThreadExecutionState = function(esFlags: DWORD): DWORD; stdcall;

type
  TScreenSaverCtrl = class(TPersistent)
  private
    { Private 宣言 }
    FDllHandle    : THandle;                               // 動的ロードしたDLLのハンドル
    FExecutionState : TSetThreadExecutionState;
  public
    { Public 宣言 }
    constructor Create;
    destructor Destroy;override;
    // 画面の表示が必要な場合の処理
    function Require() : Boolean;
  end;

implementation

{ TScreenSaverCtrl }

constructor TScreenSaverCtrl.Create;
begin
  FDllHandle := LoadLibrary('kernel32.dll');                       // DLLを動的ロード
  if FDllHandle = 0 then begin                                     // 失敗した場合
    // 必要であればエラー処理
    raise Exception.Create('kernel32.DLL が見つかりません');      // エラーとして通知
    exit;
  end;
  @FExecutionState := GetProcAddress(FDllHandle,'SetThreadExecutionState');
  if @FExecutionState = nil then begin
    // 必要であればエラー処理
    //raise Exception.Create('SetThreadExecutionState' + ' が見つかりません');
    exit;
  end;

end;

destructor TScreenSaverCtrl.Destroy;
begin
  if FDllHandle <> 0 then begin
    FreeLibrary(FDllHandle);
  end;
  inherited;

end;

function TScreenSaverCtrl.Require: Boolean;
begin
  result := False;
  if @FExecutionState = nil then exit;
  FExecutionState(ES_DISPLAY_REQUIRED);
  result := True;
end;


take  2008-10-03 23:17:06  No: 32085

解決チェックし忘れました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加