アクティブウィンドウのロックタイムアウトを設定するSystemParametersInfoの使い方について

解決


まえだまえだ  2010-08-08 01:53:05  No: 38952

(OS=XP)
・ウィンドウを最前面に移動するとき、SetForegroundWindowだけでは、タスクバーが点滅するだけで終わることがあるので、他ページをみて、下記のようなコードを試しましたが、たまにエラーがでます。ウィンドウは最前面になっているのですが、気になります。どこが間違っているのでしょうか。

エラー
SystemParametersInfo GET OK. LockTimeOut = 17423844
SystemParametersInfo SET(0) Fail. アクセスが拒否されました。
SystemParametersInfo SET(BACK) Fail. アクセスが拒否されました。

コードここから
LockTimeOut: DWORD;

      //begin ----------------
      if KeyVK = $20 then
      begin
        Logging('Key = Space');
        FormMain.Visible := True;
        ForegroundProcessId := GetWindowThreadProcessId(GetForegroundWindow, nil);
        CurrentProcessId := GetCurrentThreadId;
        if ForegroundProcessId = CurrentProcessId then
        begin
          Logging('ForegroundProcessId = CurrentProcessId');
          if SetForegroundWindow(Application.Handle) then
          begin
            Logging('SetForegroundWindow OK')
          end
          else
          begin
            Logging('SetForegroundWindow Fail')
          end;
        end
        else //if ForegroundProcessId <> CurrentProcessId then
        begin
          Logging('ForegroundProcessId <> CurrentProcessId');
          SetActiveWindow(Application.Handle);
          if AttachThreadInput(CurrentProcessId, ForegroundProcessId, True) then
          begin
            LockTimeOut := 0;
            Logging('AttachThreadInput OK');
            if not SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0,  @LockTimeOut, SPIF_SENDCHANGE) then
            begin
              Logging('SystemParametersInfo GET Fail. ' + SysErrorMessage(GetLastError));
            end
            else
            begin
              Logging('SystemParametersInfo GET OK. LockTimeOut = ' + IntToStr(LockTimeOut));
            end;
            if not SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Pointer(0), SPIF_SENDCHANGE) then
            begin
              Logging('SystemParametersInfo SET(0) Fail. ' + SysErrorMessage(GetLastError));
            end
            else
            begin
              Logging('SystemParametersInfo SET(0) OK. ');
            end;
            SetActiveWindow(Application.Handle);
            SetForegroundWindow(Application.Handle);
            if SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Pointer(LockTimeOut), SPIF_SENDCHANGE) then
            begin
              Logging('SystemParametersInfo SET(BACK) OK. ');
            end
            else
            begin
              Logging('SystemParametersInfo SET(BACK) Fail. ' + SysErrorMessage(GetLastError));
            end;
            AttachThreadInput(CurrentProcessId, ForegroundProcessId, False);
          end
          else
          begin
            Logging('AttachThreadInput Fail');
          end;
        end;
      end;
      //end ----------------


Mr.XRAY  2010-08-13 16:10:37  No: 38953

こんにちは.
よくは分からないのですが,

SystemParametersInfoのSPIF_SENDCHANGEフラグは,トップレベルのウィンのすべてに
WM_SETTIMGCHANGEメッセージを送ります.これは必要ない気がします.
これがエラーの原因かも知れません.

後,気になるのは,Application.Handleですが,そういうこともありますか.
Windows XPということですので,SystemParametersInfoの設定は必要ない気もします.
参考にしたコードが,どのバージョンのOSで動作確認されているかですね.


Mr.XRAY  2010-08-13 16:18:03  No: 38954

>参考にしたコードが,どのバージョンのOSで動作確認されているかですね.

でも,タスクバーの点滅はWindows XPからの機能ですね.
う〜む.
Windows XPではSPI_SETFOREGROUNDLOCKTIMEOUTの設定は無効だったような.


Mr.XRAY  2010-08-13 23:44:46  No: 38955

>Windows XPではSPI_SETFOREGROUNDLOCKTIMEOUTの設定は無効だったような.

大変失礼しました.動作確認しました.
MSDNオンライン英語版のクラシックスタイルの時に書いてあった気がしたのですが.
勘違いのようです.Windows XP以降のOSでも設定可能ですね.


Mr.XRAY  2010-08-14 01:23:39  No: 38956

こんにちは,Mr.XRAYです.
SDKやら調べ,テストしてみました.

以下Windows XP以降の場合です.

SystemParametersInfoのSPI_SETFOREGROUNDLOCKTIMEOUT(SPI_GET...も)アクションは,
デバック(IDEで実行)中は正常動作しない
ただし,[プログラムからデタッチ]すれば正常動作する.これはDelphi2007以降の機能.
フォアグラウンド移行の禁止時間のデフォルト値は非常に大きな値である.つまり,
事実上,SetForegroundWindowに失敗した場合,対応処理をしなければそのウィドウを
自動的にフォアグランドにはできない.

Windows XP以降でタスクバー点滅の機能が導入された.
少なくともWindows XP以降では,今回のコーディングにフォアグラウンド移行の
禁止時間の設定は必要ない.

以上,こんなところです.


まえだまえだ  2010-08-17 09:55:07  No: 38957

いろいろ調べていただいてありがとうございます。
ですが、いまだに、エラーがなぜでるのかわかりません。
下記コードのどこが間違えなのかご指摘いただけるとありがたいです。

ちなみに、このコードで実現したいのは、
ホットキー(今回はスペースキー)を押すことで、
隠れてたウィンドウが最前面にきて、
ユーザーがEDITに何か入力してエンターキーを押すと、
何か処理して隠れる、というようなものです。

main.pas
http://codepad.org/NEpqCl6V

UnitRawInput.pas
http://codepad.org/HTvtk18U


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

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






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