ファイルの終了について
ファイルの終了について
アプリケーションのヘルプ・メニューからヘルプ(テキストファイル)を
「ShellExecute」APIを使って表示させるようにプログラムを書きました。
それ自体はうまくいったのですが、
ヘルプファイルを開いたまま本体であるアプリケーションを終了させた時
そのヘルプが残ったままという現象に気づきました。
ShellExecuteの戻り値で開いたファイルのインスタンス・ハンドルが
分かるのでそれを使ってどうにかファイルを終了させられないかと
思うのですが、ファイルの終了の方法が分からず。
「アプリケーションを終了時にヘルプファイルが開いたままの場合
それを終了させる」ことの実装について、お知りの方がおられましたら
教えて下さい。
「ShellExecute」APIを使って表示させるようにプログラムを書きました。
それ自体はうまくいったのですが、
ヘルプファイルを開いたまま本体であるアプリケーションを終了させた時
そのヘルプが残ったままという現象に気づきました。
ShellExecuteの戻り値で開いたファイルのインスタンス・ハンドルが
分かるのでそれを使ってどうにかファイルを終了させられないかと
思うのですが、ファイルの終了の方法が分からず。
「アプリケーションを終了時にヘルプファイルが開いたままの場合
それを終了させる」ことの実装について、お知りの方がおられましたら
教えて下さい。
CloseHandleでは閉じてくれない?
ヘルプ・ファイルの「インスタンス・ハンドル」を入れるためのグローバル変数(hHelpFile)、を用意してヘルプの表示時に
として、
もしアプリ終了時にヘルプが開いたままならそれを閉じるために
メイン・ウインドウのデストロイ・イベントで
としてみたのですが、これではヘルプを閉じてくれないようです。
試しに
としてもみたのですがこれもダメ。
ウインドウハンドルじゃなくて「インスタンス・ハンドル」ってのが
そもそもどうなんだろうかなと思っているのですが。。。
コード: 全て選択
hHelpFile=ShellExecute(hMainWnd,"open",readMe_FullPathName,NULL,NULL,SW_SHOW)
もしアプリ終了時にヘルプが開いたままならそれを閉じるために
メイン・ウインドウのデストロイ・イベントで
コード: 全て選択
CloseHandle(hHelpFile)
試しに
コード: 全て選択
DestroyWindow(hHelpFile)
ウインドウハンドルじゃなくて「インスタンス・ハンドル」ってのが
そもそもどうなんだろうかなと思っているのですが。。。
レスありがとうございます。
レスありがとうございます。ShellExecute/ShellExecuteExで得られるHINSTANCEはエラーを得るため以外には使えないらしいですが
ShellExecuteの変わりに
CreateProcessかShellExecuteEx使ってみては
自分の調べた限りですが、CreateProcessは「実行ファイル」を開くのに
使われる命令のようで、その他のファイルはShellExecuteが一般的との
印象です。
ShellExecuteExはShellExecuteの拡張版とも言えるもののようなので
やはり元のShellExecuteで出来る筈じゃないかなとも思っています。
それから、GetActiveWindow 関数ですが、もしもShellExecuteの設定で
ファイルをアクティブなウインドウとして開かなかった場合にはどうなるのかなと、、
まだ実際に自分で試してないので何とも言えないのですが。。。
最後に編集したユーザー jacoby [ 2008年6月24日(火) 02:29 ], 累計 1 回
正攻法はWinHelp関数やHtmlHelp関数を使うことだと思いますが、自分も使ったことないので正直よく分かりません。
http://www.kumei.ne.jp/c_lang/sdk3/sdk_284.htm
CreateProcessやShellExecuteExが勧められたのは、共に(ShellExecuteと違って)プロセスハンドルを取得できるためでしょう。プロセスハンドルがあれば、TerminateProcess関数で強制終了が可能だからです(一般的に勧められませんが)。TerminateProcessを使わないにしても、プロセスハンドルやプロセスIDが分かれば、それを基に対象のウィンドウハンドルを探せます。そうすれば、そこへWM_CLOSEを送るなど穏便な手段で終了を依頼できます。
ShellExecuteがHINSTANCEを返す理由は、16ビットWindowsではHISNTANCEが今で言うところのプロセスハンドルに近い役割を果たしていたからです。
http://www.kumei.ne.jp/c_lang/sdk3/sdk_284.htm
CreateProcessやShellExecuteExが勧められたのは、共に(ShellExecuteと違って)プロセスハンドルを取得できるためでしょう。プロセスハンドルがあれば、TerminateProcess関数で強制終了が可能だからです(一般的に勧められませんが)。TerminateProcessを使わないにしても、プロセスハンドルやプロセスIDが分かれば、それを基に対象のウィンドウハンドルを探せます。そうすれば、そこへWM_CLOSEを送るなど穏便な手段で終了を依頼できます。
ShellExecuteがHINSTANCEを返す理由は、16ビットWindowsではHISNTANCEが今で言うところのプロセスハンドルに近い役割を果たしていたからです。
レスありがとうございます。CreateProcessやShellExecuteExが勧められたのは、共に(ShellExecuteと違って)プロセスハンドルを取得できるためでしょう。プロセスハンドルがあれば、TerminateProcess関数で強制終了が可能だからです(一般的に勧められませんが)。TerminateProcessを使わないにしても、プロセスハンドルやプロセスIDが分かれば、それを基に対象のウィンドウハンドルを探せます。そうすれば、そこへWM_CLOSEを送るなど穏便な手段で終了を依頼できます。
まだ中々内容の理解が追いつかないのですが、
「プロセスハンドル」及び「プロセスID」というものが(二つとも)必要という
ことでしょうか。
それについてWeb上で他に調べていて、このような記事を見つけました。
http://okwave.jp/qa566523.html
この記事からはShellExecuteExでは「プロセスハンドル」は取得できるものの
「プロセスID」は取得出来なさそうな内容で、
「CreateProcessならプロセスIDを取得出来る」とあります。
ただし確か↓ページの説明では
http://detail.chiebukuro.yahoo.co.jp/qa ... 1310043483
とあり、テキストファイルを「メモ帳」で開くことがあらかじめ前提となっていなくてはCreateProcessで起動できるのは「実行ファイル」だけなので、
ShellExecuteのようにデータファイルを渡してそれに関連付けされている
アプリケーションを起動するということはできません。
ですので、メモ帳の実行ファイル名と開きたいテキストファイルの名前を
渡してやらなければなりません。
ならないような印象も受けます。
うーん、、あれこれ調べてはいるんですけど、何れも大変な処理になりそうな
感じで、何だかヘルプをShellExecute(Ex)やCreateProcess等で開くこと
自体がそもそも不自然なのかもと思えてきます。
そこでイグトランスさんの書かれていた、
ですが、これについては今、読ませてもらっています。これが一般的な方法正攻法はWinHelp関数やHtmlHelp関数を使うことだと思いますが、
なのでしょうか。(ただHTML形式のヘルプを作らなければならないようですね。。)
でも、教えていただいて有難うございます。
それにしてもヘルプをShellExecuteで表示したときに比べて、後始末のほうは
何て複雑なんだろうと、、ABのプロジェクトエディターがしっかり開いたままの
ヘルプを閉じて終了する様を眺めつつ、思っています。
ゲストさん、イグトランスさん、レスありがとうございました。
またよろしくお願いします。
EnumWindowsとGetWindowThreadProcessIdを上手く使えばいけたと思います。
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。
に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
ここ以外の場所では「暇人13世」というHNを主として使用。
に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
不具合を修正しコードを変更しました。
AB4.24で外部機器との通信プログラムでヘルプとしてpdfファイルを表示した時に作成したものです。
Dim pi As PROCESS_INFORMATION 'CreateProcess実行時に取得する構造体
Dim hApplWnd As HWND
Function EnumWindowsProc(hWnd As HWND, lParam As LPARAM) As LRESULT 'CreateProcessで起動したアプリのHWNDを取得する関数
Dim lpdwProcessId As DWord
GetWindowThreadProcessId(hWnd, VarPtr(lpdwProcessId)) 'EnumWindowsで得たhWndのProcessIdを取得し
If pi.dwProcessId = lpdwProcessId Then 'CreateProcessで取得したProcessIdと同じ
hApplWnd = GetWindow(hWnd, GW_OWNER) 'hWndの親hWndを取得する
If hApplWnd = 0 Then hApplWnd = hWnd
End If
EnumWindowsProc = TRUE '全てのhWndをチェック
End Function
'終了イベント
Sub MainWnd_IDM_EXIT_MenuClick()
If pi.hProcess > 0 Then
TypeDef WNDENUMPROC = *Function(hWnd As HWND, lp As LPARAM) As BOOL
Declare Function EnumWindows Lib "user32" (lpEnumFunc As WNDENUMPROC, lParam As LPARAM) As BOOL
Dim lParam As LPARAM
EnumWindows(AddressOf(EnumWindowsProc), lParam)
SendMessage(hApplWnd, WM_CLOSE, 0, 0)
CloseHandle(pi.hProcess)
CloseHandle(pi.hThread)
End If
SendMessage(hMainWnd,WM_CLOSE,0,0)
End Sub
2月21日追記 エラー報告
このコードではWindowが最小化されていると正常に機能しません。
タスクマネージャで終了しなければならない事になります。
手動(マウス)で元に戻すと正常に機能するのですが OpenIcon で元に戻したのでは
改善されません。
2月24日不具合を修正しコードを変更しました。
Dim pi As PROCESS_INFORMATION 'CreateProcess実行時に取得する構造体
Dim hApplWnd As HWND
Function EnumWindowsProc(hWnd As HWND, lParam As LPARAM) As LRESULT 'CreateProcessで起動したアプリのHWNDを取得する関数
Dim lpdwProcessId As DWord
GetWindowThreadProcessId(hWnd, VarPtr(lpdwProcessId)) 'EnumWindowsで得たhWndのProcessIdを取得し
If pi.dwProcessId = lpdwProcessId Then 'CreateProcessで取得したProcessIdと同じ
hApplWnd = GetWindow(hWnd, GW_OWNER) 'hWndの親hWndを取得する
If hApplWnd = 0 Then hApplWnd = hWnd
End If
EnumWindowsProc = TRUE '全てのhWndをチェック
End Function
'終了イベント
Sub MainWnd_IDM_EXIT_MenuClick()
If pi.hProcess > 0 Then
TypeDef WNDENUMPROC = *Function(hWnd As HWND, lp As LPARAM) As BOOL
Declare Function EnumWindows Lib "user32" (lpEnumFunc As WNDENUMPROC, lParam As LPARAM) As BOOL
Dim lParam As LPARAM
EnumWindows(AddressOf(EnumWindowsProc), lParam)
SendMessage(hApplWnd, WM_CLOSE, 0, 0)
CloseHandle(pi.hProcess)
CloseHandle(pi.hThread)
End If
SendMessage(hMainWnd,WM_CLOSE,0,0)
End Sub
2月21日追記 エラー報告
このコードではWindowが最小化されていると正常に機能しません。
タスクマネージャで終了しなければならない事になります。
手動(マウス)で元に戻すと正常に機能するのですが OpenIcon で元に戻したのでは
改善されません。
2月24日不具合を修正しコードを変更しました。
最後に編集したユーザー 田中 宏 [ 2009年2月24日(火) 23:34 ], 累計 2 回
インスタンスハンドルからウインドウハンドルを取得する
日本語が怪しげなのと、VBらしきコードなので・・・あれですが
下記が参考になると思います。
http://support.microsoft.com/kb/242308/ja
ABに書き直しても、それほど手間ではないと思います。
下記が参考になると思います。
http://support.microsoft.com/kb/242308/ja
ABに書き直しても、それほど手間ではないと思います。