フォーラム


ゲスト  

ようこそ ゲスト さん。このフォーラムに投稿するには 登録が必要です。

ページ: [1]
トピック: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
5匹のねこ
メンバー
投稿数: 6
Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/02 17:33 Tue

初めて投稿します。アドバイスをよろしくお願いします。

Windows XP 時代に自作した、次のようなアプリを使っています。
Vistaになった時に、Windowsの終了をブロックする方法が変わりましたので、変更に対応させたものを使っていますが、Windows8.1 では期待した通りに動きません。

*** アプリの概要 ***
Windowsの起動時に起動して、メインウィンドウは非表示になります。
その後は何もせずに常駐して、Windowsの終了を検知すると、指定したファイルを指定した場所にコピーします。
アプリが終了してから、Windowsが終了します。

*** 不具合 *** Windows 8.1のみの現象です。
コピーに時間がかかると、Windowsに戻ってしまい、コピーが終了しても、Windowsがシャットダウンしません。
コピーが短時間で終わると、アプリが終了してから、Windowsがシャットダウンします。

*** 動作環境 ***
ホストOS:Mac OSX OS X 10.10.5 (14F1509)で動いているParallels Desktop 10 for Mac(10.3.0-29227)
ゲストOS:
   Windows Vista(32bit) バージョン6.0(ビルド6002:Service Pack 2)
   Windows 7(64bit) バージョン6.1(ビルド7601:Service Pack 1)
   Windows 8.1(64bit) バージョン6.3(ビルド9600)
***開発環境 ***
   Windows 7(64bit)+Embarcadero® RAD Studio XE7 バージョン 21.0.17707.5020(Delphi)

*** 関係すると思われるソース ***
PROCEDURE TMAINForm.WndProc
( VAR Msg : TMessage );
BEGIN
IF Msg.Msg = WM_ENDSESSION THEN BEGIN
TRY
ShutdownBlockReasonCreate
( Handle,
PWideChar('バックアップしています。しばらくお待ち下さい。'));
CopyFiles;
FINALLY
ShutdownBlockReasonDestroy( Handle );
Close;
END(* of TRY *);
END(* of IF *);
INHERITED;
END(* WndProc *);

PROCEDURE TMainForm.WMQueryEndSession
( VAR Msg : TWMQueryEndSession );
BEGIN
Msg.Result := LongInt( ORD( FALSE ) );
INHERITED;
END(* WMQueryEndSession *);

PC-DOSのTurbo Pascalから付き合いですので、Delphiに至るまでの経歴は長いのですが、本業に関係するちょっとしたアプリを数年に一度作るくらいのアマチュアです。

DEKO
管理者
投稿数: 2691
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/03 07:22 Wed

恐らくですが、メッセージハンドラの中でファイルコピーをしているのがいけないのではないかと。
メッセージにはさっさと応答して、スレッドなりタイマーを使ってコピー処理を遅延実行させればうまくいくような気がします。

5匹のねこ
メンバー
投稿数: 6
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/03 21:07 Wed

早速のアドバイスに感謝いたします。
残念ながら、知識不足で実際にどのようなコードを書けば良いのかわかりませんので、例を示していただけますでしょうか。

スレッドを使うとは?
  他のprocedure内でコピーを実行すればよいのでしょうか。

また、タイマーを使ってとは、Sleep( )を使うということでしょうか。

PC-DOSのTurbo Pascalから付き合いですので、Delphiに至るまでの経歴は長いのですが、本業に関係するちょっとしたアプリを数年に一度作るくらいのアマチュアです。

DEKO
管理者
投稿数: 2691
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/04 01:39 Thu

ざっくりとですが、

procedure TForm1.AAA(var Msg: TMessage);
begin
if (条件) then
begin
ShutdownBlockReasonCreate();
Timer1.Enabled := True; // タイマーを有効にしてすぐ抜ける
end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
(コピー処理)
end;

 
こんな感じです。メッセージハンドラの中で重い処理をせずにすぐ抜ける、と。すぐ抜けるための手段は何でも構いません。

5匹のねこ
メンバー
投稿数: 6
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/04 19:37 Thu

重ねてのアドバイスに感謝いたします。

次の2通りを試しましたが、どちらもうまく行きませんでした。

*** その1 **********************************************************************
タイマーを使った、アドバイスを頂いた方法です。
Windowsの終了を検知できず、コピーしないで終了してしまいます。

 procedure TMAINForm.TimerTimer(Sender: TObject);
 begin
  Timer.Enabled := FALSE;
  CopyFiles;
  Close;
 end;

 PROCEDURE TMAINForm.WndProc
       ( VAR  Msg   : TMessage );
 BEGIN
  IF Msg.Msg = WM_ENDSESSION THEN BEGIN
    ShutdownBlockReasonCreate
     ( Handle,
      PWideChar('バックアップをしています。しばらくお待ち下さい。'));
   Timer.Enabled := TRUE;
  END(* of IF *);
  INHERITED;
 END(* WndProc *);

 PROCEDURE TMainForm.WMQueryEndSession
       ( VAR  Msg   : TWMQueryEndSession );
 BEGIN
  Msg.Result := LongInt( ORD( FALSE ) );
  INHERITED;
 END(* WMQueryEndSession *);

*** その2 **********************************************************************
本来は、設定されたフラグを元に、FormCloseQuery内でコピーを実行していましたので、それを改変してみました。
Windows8.1ではコピーの途中で、Windowsに戻ってしまいます。状況は改善されていません。さらに、メッセージが正しく表示されず、「次のアプリケーションがシャットダウンを妨げています。」と、デフォルト?のメッセージが表示されます。

 procedure TMAINForm.FormCloseQuery
       (    Sender  : TObject;
        var  CanClose : Boolean   );
 begin
  IF CopyRequested THEN BEGIN
    CopyFiles;
  END;
  CanClose := TRUE;
 end(* FormCloseQuery *);

 PROCEDURE TMAINForm.WndProc
       ( VAR  Msg   : TMessage );
 BEGIN
  IF Msg.Msg = WM_ENDSESSION THEN BEGIN
    ShutdownBlockReasonCreate
     ( Handle,
      PWideChar('バックアップをしています。しばらくお待ち下さい。'));
    CopyRequested := TRUE;
    Close;
  END(* of IF *);
  INHERITED;
 END(* WndProc *);

 PROCEDURE TMainForm.WMQueryEndSession
       ( VAR  Msg   : TWMQueryEndSession );
 BEGIN
  Msg.Result := LongInt( ORD( FALSE ) );
  INHERITED;
 END(* WMQueryEndSession *);

PC-DOSのTurbo Pascalから付き合いですので、Delphiに至るまでの経歴は長いのですが、本業に関係するちょっとしたアプリを数年に一度作るくらいのアマチュアです。

DEKO
管理者
投稿数: 2691
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/05 10:20 Fri

解決策っぽいコードを見つけました。
http://stackoverflow.com/questions/18346571/how-to-pause-windows-shut-down

5匹のねこ
メンバー
投稿数: 6
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/05 20:30 Fri

毎回、素早いご回答に感謝いたします。

ご紹介いただきましてサイトを参考に、次のコードで試しましたが、うまく行きませんでした。
☆☆☆最も気になっているのは、…
 Vistaと7ではうまくいくのに、8.1のみダメという点です。何か7から8.1で変更があったのかと思い検索いたしましたが、うまくヒットしません。
☆☆☆次に気になっているのは、…
 Microsoftの文書(Application Shutdown Changes in Windows Vista (Windows))を、次のように理解しました。(私の英語力に問題がありますが…)
「WM_QUERYENDSESSIONのメッセージに対して、FALSEを返せ。そうすると、Windowsからアプリに対してWM_ENDSESSION送る。WM_ENDSESSIONに対して、アプリが応答せよ。」
そこで、最初に質問したようなコードを書きました。しかし、今回のコードはMicrosoftの文書とは違うように感じました。しかし、結果は同じです。
☆☆☆ちょっと気になるのは、…
 ShutdownBlockReasonCreateとShutdownBlockReasonDestroyを別のPROCEDUREに書くと、メッセージが無視されてデフォルトのメッセージが表示されることです。

 PROCEDURE TMainForm.WMQueryEndSession
       ( VAR  Msg   : TWMQueryEndSession );
  CONST ENDSESSION_CRITICAL = $40000000;
 BEGIN
  (* TMessage.Result フィールドに割り当てられるポインタは、
    Integer/Longint ではなく LRESULT に型キャストを使用する必要があります。*)
  Msg.Result := LRESULT( TRUE );
  IF (( Msg.Unused AND ENDSESSION_CRITICAL ) = 0) THEN BEGIN
   ShutdownBlockReasonCreate
    ( Handle,
     PWideChar('バックアップをしています。しばらくお待ち下さい。'));
   COPYFiles;
   ShutdownBlockReasonDestroy( Handle );
   CopyRequested := FALSE;
   Close;
  END;
  INHERITED;
 END(* WMQueryEndSession *);

PC-DOSのTurbo Pascalから付き合いですので、Delphiに至るまでの経歴は長いのですが、本業に関係するちょっとしたアプリを数年に一度作るくらいのアマチュアです。

5匹のねこ
メンバー
投稿数: 6
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/08 19:38 Mon

Windows10を入手して、試してみましたが、うまくバックアップしてから、Windowsが終了いたしました。しかし、8.1よりも動作が早くコピーの時間が短かったような気がします。もしかすると、Vistaや7でうまく行っているのは、コピーの時間が短いからかもしれません。
コピーの時間を調べてみます。

PC-DOSのTurbo Pascalから付き合いですので、Delphiに至るまでの経歴は長いのですが、本業に関係するちょっとしたアプリを数年に一度作るくらいのアマチュアです。

5匹のねこ
メンバー
投稿数: 6
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2016/02/17 20:52 Wed

その後、ネットの情報を探しましたが、解決策は見つかりません。
強引な方法ですが、コピーが終了した時点で、アプリからWindowsを終了するようにしました。とりあえず、Windowsのシャットダウン直前に、コピーをすることはできました。
でも、エレガントじゃありません。

PC-DOSのTurbo Pascalから付き合いですので、Delphiに至るまでの経歴は長いのですが、本業に関係するちょっとしたアプリを数年に一度作るくらいのアマチュアです。

Mr.XRAY
メンバー
投稿数: 192
Re: Windows8.1でShutdownBlockReasonCreateを用いたシャットダウンブロックがうまくいかないことがある
on: 2019/01/14 00:21 Mon

最後の書き込みからだいぶ時間が経過していますが,
最近,シャットダウンに関係する記事を書きましたのでリンクを貼っておきます.

[ 10_システムのログオフと再起動とシャットダウンの検出と阻止 ]
http://mrxray.on.coocan.jp/Delphi/Others/PowerControl.htm#10

シャットダウンの操作が行われた時の挙動は,Windows XP と Widows 7 と Windows 8.1 / 10 とで違いがあります.
そのことにも触れています.

ページ: [1]
WP Forum Server by ForumPress | LucidCrew
バージョン: 1.7.5 ; ページロード: 0.05 sec.