program scv; { 2012-08-18:Ver 0.2.8.4 ・スリープ、休止状態の抑止が効かなくなっていた不具合を修正。  前回のリリース時に紛れ込んだ不具合。 2012-08-16:Ver 0.2.7.4 ・先に起動中のscvの設定を後から実行することで変更できるようにした。 ・二重起動時のメッセージ出力を削除。 ・スリープを許可していてもスクリーンセーバーを抑止しているとスリープに入らないよ  うなので「スリープ、休止状態の許可」を削除。 2012-04-25:Ver 0.2.6.3 ・メニューの「スリープ、電源オフを許可」を「スリープ、休止状態を許可」に変更。 ・バージョン情報の表示内容にコマンドラインオプションの説明を追加。 2012-04-24:Ver 0.2.5.3 ・「スリープ、電源オフを許可」メニューを追加。 ・コマンドラインの引数で「スクリーンセーバーを許可」「スリープ、電源オフを許可」  を指定できるようにした。 2012-04-22:Ver 0.2.4.3 ・「スクリーンセーバーを許可」メニューを追加。 2012-02-29:Ver 0.2.3.3 ・メッセージボックスがプライマリモニター以外に表示されてしまうことがある不具合を  修正。 2012-02-27:Ver 0.2.2.3 ・http://kerokero.org/wp/archives/154  によるとVista以降ではSetThreadExecutionState(ES_DISPLAY_REQUIRED)だけではスク  リーンセーバーの抑止にはならないらしいのでmouse_event APIも併用してみた。  が、Vistaや7の環境がないので効果があるのかどうか解らない。 2011-01-21:Ver 0.2.1.3 ・DLLプリロード攻撃対策。  LoadLibraryは利用していないので必要ないとは思うのだけれども念のため。 2009-09-19:Ver 0.2.0.2 ・Unicode版APIの使用をとりやめ。  よくよく考えたらUnicode版である必要がないのでそれなら9x系でも動くようにということで。 ・「バージョン情報」復活。  かなりな手抜きであるけれど。 ・通知領域にアイコンが登録されなかった場合へ対処。 ・タスクバーが再起動した場合に通知領域へのアイコンの再登録に対処。 マイナーバージョンあげ。 「バージョン情報」機能も復活したしアイコンの再登録もできるようになったことだし。 2009-04-05:Ver 0.1.0.1 ・VCLを使わずに書き直し。  12KBになった。 ・タスクトレイのアイコンを左クリックしてもポップアップメニューを出すように変更。 ・「バージョン情報」メニューを廃止。 機能としては若干低下したもののファイルサイズがえらく小さくなったのでマイナー上げ。 2009-02-08:Ver 0.0.3.0 ・完璧を目指し0.9秒ごとにモニターをアクティブにするように変更。  ダイアログでは設定の最短は1分であるがAPIを使えば最短で1秒にすることができ、  Vistaでは設定によりスクリーンセーバーが立ち上がろうとしたらキャンセルできない  場合があるらしいので最短の1秒より短い0.9秒とした。 ・ポップアップメニューに「バージョン情報」追加。 2009-02-06:Ver 0.0.2.0 ・スクリーンセーバー、モニター電源オフのメッセージを捕まえて処理するようにもした。 2008-11-19:Ver 0.0.1.0 ・モニターオフの抑止だけでなくシステムスタンバイの抑止もするように変更。 ・二重起動のエラーメッセージを出すようにした。 2008-04-22:作成 } //{$DEFINE DEBUG} //{$DEFINE ALLOWPOWER} {$IFNDEF DEBUG} {$O+} //{$Q-} //{$R-} {$ENDIF} uses // my_safedll, {$IFDEF DEBUG} myDebug, {$ENDIF} ShellAPI, Messages, Windows, SysUtils; {$R *.res} const IDM_EXIT = 200; IDM_HELP = 201; IDM_ALLOWMONITOR = 202; {$IFDEF ALLOWPOWER} IDM_ALLOWPOWEROFF = 204; {$ENDIF} const USER_ICONMESSAGE = WM_USER + 100; //電源OFFの抑止 function SetThreadExecutionState(esFlags: DWORD): DWORD; stdcall external 'kernel32.dll'; const ES_SYSTEM_REQUIRED = $00000001; ES_DISPLAY_REQUIRED = $00000002; ES_CONTINUOUS = $80000000; var F_hWindowHandle : HWND; F_hMenu : HMENU; F_iTaskbarCreated : UINT; //タスクバーの再起動 F_bIconRegist : Boolean; //通知領域にアイコンが登録されたか F_rIconData : TNotifyIconData; //登録アイコンデータ function gfnsGetExeVersion: String; forward; //------------------------------------------------------------------------------ //メニューをポップアップ procedure OnContextMenu(var Msg: TWMMouse); var lpt_Pos: TPoint; begin GetCursorPos(lpt_Pos); TrackPopupMenu(F_hMenu, 0, lpt_Pos.X, lpt_Pos.Y, 0, Msg.Msg, nil); end; function gfnbIsMenuChecked(hMenu : HMENU; iItemID : UINT) : Boolean; begin Result := (GetMenuState(hMenu, iItemID, MF_BYCOMMAND) and MF_CHECKED) = MF_CHECKED; end; procedure gpcSetMenuCheck(hMenu: HMENU; iItemID: UINT; bCheck: Boolean); begin if (bCheck) then begin CheckMenuItem(hMenu, iItemID, MF_BYCOMMAND or MF_CHECKED); end else begin CheckMenuItem(hMenu, iItemID, MF_BYCOMMAND or MF_UNCHECKED); end; DrawMenuBar(hMenu); end; procedure gpcSetMenuCheckInvert(hMenu: HMENU; iItemID: UINT); begin gpcSetMenuCheck(hMenu, iItemID, not(gfnbIsMenuChecked(hMenu, iItemID))); end; procedure SetAllowMonitorMenu; begin //モニター、スクリーンセーバー gpcSetMenuCheckInvert(F_hMenu, IDM_ALLOWMONITOR); end; {$IFDEF ALLOWPOWER} procedure SetAllowPowerOffMenu; begin gpcSetMenuCheckInvert(F_hMenu, IDM_ALLOWPOWEROFF); end; {$ENDIF} procedure CheckParam(sParam : WideString); function _DoParam(sOpt : String) : Boolean; var ls_UpOpt : String; begin Result := False; ls_UpOpt := UpperCase(sOpt); if (ls_UpOpt = '-X') then begin Result := True; DestroyWindow(F_hWindowHandle); Exit; end; if (ls_UpOpt = '-S') then begin SetAllowMonitorMenu; end; {$IFDEF ALLOWPOWER} if (ls_UpOpt = '-P') then begin SetAllowPowerOffMenu; end; {$ENDIF} if (ls_UpOpt = '-C') then begin gpcSetMenuCheck(F_hMenu, IDM_ALLOWMONITOR, False); {$IFDEF ALLOWPOWER} gpcSetMenuCheck(F_hMenu, IDM_ALLOWPOWEROFF, False); {$ENDIF} end; end; const lcs_QUOT = WideChar('"'); lcs_SPACE = WideChar(' '); lcs_TAB = WideChar(#$9); lcs_CR = WideChar(#$D); lcs_LF = WideChar(#$A); var i: Integer; li_Len : Integer; ls_Param : WideString; ls_Char : WideChar; lb_Quot : Boolean; lb_Skip : Boolean; begin li_Len := Length(sParam); lb_Quot := False; lb_Skip := False; ls_Param := ''; for i := 1 to li_Len do begin ls_Char := sParam[i]; case ls_Char of lcs_QUOT :begin //最初にみつかった引用符は区切り //オプションではない if not(lb_Quot) then begin //最初にみつかった引用符は区切り lb_Quot := True; if (ls_Param <> '') then begin //パラメータがあった if (_DoParam(ls_Param)) then begin Exit; end; ls_Param := ''; end; end else if (lb_Skip) then begin //引用符内引用符 lb_Skip := False; ls_Param := ls_Param + ls_Char; end else if (i < li_Len) and (sParam[i +1] = lcs_QUOT) then begin //この引用符のすぐ後にも引用符があるので引用符内引用符であるので引数の取り出しにはならない //ex) "引用符を含めるには""とする" lb_Skip := True; end else if (lb_Quot) then begin //引用符の閉じ⇒引数取り出し lb_Quot := False; if (_DoParam(ls_Param)) then begin Exit; end; ls_Param := ''; end; end; lcs_SPACE, //半角スペース lcs_TAB, //タブ lcs_CR, //改行 lcs_LF //改行 :begin //引数の区切り if (lb_Quot) then begin //引用符つき引数であるので引数の区切りではない⇒引数の文字列に加える ls_Param := ls_Param + ls_Char; end else begin //引用符つき引数ではないので引数の区切り⇒引数の取り出し if (ls_Param <> '') then begin if (_DoParam(ls_Param)) then begin Exit; end; ls_Param := ''; end; end; end; else begin ls_Param := ls_Param + ls_Char; end; end; end; if (ls_Param <> '') then begin _DoParam(ls_Param); end; end; function MainWndProc(hWindow: HWND; Msg: UINT; iWParam: WPARAM; iLParam: LPARAM): LRESULT; stdcall; var lr_Msg : TMessage; li_Flag : DWORD; begin Result := 0; FillChar(lr_Msg, SizeOf(lr_Msg), 0); with lr_Msg do begin Msg := hWindow; WParam := iWParam; LParam := iLParam; Result := 0; end; case Msg of USER_ICONMESSAGE :begin //タスクトレイのアイコンをクリック if (iLParam = WM_RBUTTONUP) or (iLParam = WM_LBUTTONUP) then begin SetForegroundWindow(lr_Msg.Msg); //メニューをポップアップ OnContextMenu(TWMMouse(lr_Msg)); //XPosやYPosには座標は入っていない end; end; WM_COMMAND :begin //ポップアップメニューを選択 if (lr_Msg.WParamHi = 0) then begin case (lr_Msg.WParamLo) of IDM_ALLOWMONITOR :begin //モニター、スクリーンセーバー SetAllowMonitorMenu; end; {$IFDEF ALLOWPOWER} IDM_ALLOWPOWEROFF :begin //スリープ、電源オフ SetAllowPowerOffMenu; end; {$ENDIF} IDM_HELP :begin //バージョン情報 MessageBox(F_hWindowHandle, PChar(gfnsGetExeVersion), 'バージョン情報', MB_SETFOREGROUND or MB_APPLMODAL); end; IDM_EXIT :begin //「終了(&X)」 PostQuitMessage(0); end; end; end; end; WM_TIMER :begin //タイマー //モニター電源オフ&スクリーンセーバー抑止 if not(gfnbIsMenuChecked(F_hMenu, IDM_ALLOWMONITOR)) {$IFDEF ALLOWPOWER} or not(gfnbIsMenuChecked(F_hMenu, IDM_ALLOWPOWEROFF)) {$ENDIF} then begin li_Flag := 0; if not(gfnbIsMenuChecked(F_hMenu, IDM_ALLOWMONITOR)) then begin li_Flag := li_Flag or ES_DISPLAY_REQUIRED; end; {$IFDEF ALLOWPOWER} if not(gfnbIsMenuChecked(F_hMenu, IDM_ALLOWPOWEROFF)) then begin li_Flag := li_Flag or ES_SYSTEM_REQUIRED; end; {$ELSE} // li_Flag := li_Flag or ES_SYSTEM_REQUIRED; {$ENDIF} if (li_Flag <> 0) then begin SetThreadExecutionState(li_Flag); end; if ((li_Flag and ES_DISPLAY_REQUIRED) <> 0) then begin //Vistaか7以上ではこれがないとスクリーンセーバーのキャンセルができないようだ mouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0); end; end; //通知領域にアイコンが登録されていなければ登録する if not(F_bIconRegist) then begin F_bIconRegist := Shell_NotifyIcon(NIM_ADD, @F_rIconData); end; end; (* WM_SYSCOMMAND :begin //スクリーンセーバー、モニター電源オフのメッセージが飛んできてもキャンセルする //フォームがアクティブでないとこのメッセージは飛んでこない //つまりこのプログラムにあってはこのメッセージはこないので無駄な努力 if (iWParam = SC_MONITORPOWER) or (iWParam = SC_SCREENSAVE) then begin SetThreadExecutionState(ES_DISPLAY_REQUIRED); mouse_event(MOUSEEVENTF_MOVE, 0, 0, 0, 0); TWMSysCommand(lr_Msg).Result := 1; //0だと抑止にならない end; end; *) WM_SETTEXT :begin CheckParam(String(PChar(iLParam))); Result := DefWindowProc(hWindow, Msg, iWParam, iLParam); end; WM_DESTROY :begin PostQuitMessage(0); end; else begin if (Msg = F_iTaskbarCreated) then begin //http://katsura-kotonoha.sakura.ne.jp/prog/win/tip0001a.shtml Shell_NotifyIcon(NIM_DELETE, @F_rIconData); F_bIconRegist := Shell_NotifyIcon(NIM_ADD, @F_rIconData); end else begin Result := DefWindowProc(hWindow, Msg, iWParam, iLParam); end; end; end; end; const lcsCLASSNAME = 'TApp_TOOLScrBlock'; lcsWINDOWTEXT = 'scv'; lciTIMERCODE = 8345; function gfnsGetExeVersion: String; begin Result := 'スクリーンセーバー起動抑止プログラム' + #13 + lcsWINDOWTEXT + ' Ver:0.2.8.4' + #13#13'コマンドラインオプション' + #13'-s スクリーンセーバーの起動を許可' {$IFDEF ALLOWPOWER} + #13'-p スリープ、休止状態を許可' + #13'-c -sと-pの設定をクリアしスクリーンセーバーの起動とスリープ、休止状態を抑止' {$ENDIF} + #13'-c -sの設定をクリアしスクリーンセーバーの起動を抑止' + #13'-x プログラム終了' ; end; //main var i : Integer; lr_WndClass : TWndClass; lr_Msg : TMsg; lh_ScvWindow : HWND; ls_Param : String; // lb_Exit : Boolean; begin // lb_Exit := False; ls_Param := lcsWINDOWTEXT; for i := 1 to ParamCount do begin ls_Param := ls_Param + ' ' + ParamStr(i); { if (ParamStr(i) = '/x') or (ParamStr(i) = '/X') then begin lb_Exit := True; end; } end; //二重起動防止 if (CreateMutex(nil, False, 'doaGD[da12_') <> 0) //関数が成功して and (GetLastError = ERROR_ALREADY_EXISTS) //既に同名のミューテックスオブジェクトがあれば then begin //二重起動である { if not(lb_Exit) then begin MessageBox(F_hWindowHandle, '起動済みです', lcsWINDOWTEXT, MB_SETFOREGROUND or MB_APPLMODAL); end; } if (ParamCount > 0) then begin lh_ScvWindow := FindWindow(lcsCLASSNAME, nil); if (lh_ScvWindow <> 0) then begin SendMessage(lh_ScvWindow, WM_SETTEXT, WPARAM(0), LPARAM(PChar(ls_Param))); end; end; Halt(1); end; FillChar(lr_WndClass, SizeOf(lr_WndClass), 0); lr_WndClass.lpszClassName := lcsCLASSNAME; lr_WndClass.lpfnWndProc := @MainWndProc; lr_WndClass.style := CS_VREDRAW or CS_HREDRAW; lr_WndClass.hInstance := SysInit.HInstance; lr_WndClass.hIcon := LoadIcon(SysInit.HInstance, 'MAINICON'); lr_WndClass.lpszMenuName := nil; if (RegisterClass(lr_WndClass) = 0) then begin Halt(1); end; F_hWindowHandle := CreateWindow( lcsCLASSNAME, lcsWINDOWTEXT, WS_POPUP , 0, 0, 0, 0, 0, 0, SysInit.hInstance, nil ); if (F_hWindowHandle = 0) then begin Halt(1); end; //ポップアップメニュー作成 F_hMenu := CreatePopupMenu; AppendMenu(F_hMenu, MF_STRING, IDM_ALLOWMONITOR, 'スクリーンセーバーの起動を許可(&S)'); {$IFDEF ALLOWPOWER} AppendMenu(F_hMenu, MF_STRING, IDM_ALLOWPOWEROFF, 'スリープ、休止状態を許可(&P)'); AppendMenu(F_hMenu, MF_SEPARATOR, 0, nil); {$ENDIF} AppendMenu(F_hMenu, MF_STRING, IDM_HELP, 'バージョン情報(&A)'); AppendMenu(F_hMenu, MF_SEPARATOR, 0, nil); AppendMenu(F_hMenu, MF_STRING, IDM_EXIT, '終了(&X)'); UpDateWindow(F_hWindowHandle); F_iTaskbarCreated := RegisterWindowMessage('TaskbarCreated'); //タスクトレイにアイコンを追加 FillChar(F_rIconData, SizeOf(F_rIconData), 0); with F_rIconData do begin cbSize := SizeOf(F_rIconData); uID := 13; Wnd := F_hWindowHandle; uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP; uCallbackMessage := USER_ICONMESSAGE; hIcon := lr_WndClass.hIcon; szTip := 'スクリーンセーバー抑止'; //ヒント end; F_bIconRegist := Shell_NotifyIcon(NIM_ADD, @F_rIconData); if (ParamCount > 0) then begin SendMessage(F_hWindowHandle, WM_SETTEXT, WPARAM(0), LPARAM(PChar(ls_Param))); end; //システムスタンバイの抑止 SetThreadExecutionState(ES_SYSTEM_REQUIRED or ES_CONTINUOUS); //タイマーセット SetTimer(F_hWindowHandle, lciTIMERCODE, 900, nil); //メッセージループ while (GetMessage(lr_Msg, 0, 0, 0)) do begin TranslateMessage(lr_Msg); DispatchMessage(lr_Msg); end; //タイマー解除 KillTimer(F_hWindowHandle, lciTIMERCODE); //システムスタンバイの抑止の解除 SetThreadExecutionState(ES_CONTINUOUS); //タスクトレイのアイコンを削除 Shell_NotifyIcon(NIM_DELETE, @F_rIconData); DestroyMenu(F_hMenu); DestroyWindow(F_hWindowHandle); Halt(lr_Msg.wParam); end.