ab.com コミュニティ
https://www.activebasic.com/forum/

ファイルの終了について
https://www.activebasic.com/forum/viewtopic.php?t=2414
ページ 11

作成者:  jacoby [ 2008年6月21日(土) 22:57 ]
記事の件名:  ファイルの終了について

アプリケーションのヘルプ・メニューからヘルプ(テキストファイル)を
「ShellExecute」APIを使って表示させるようにプログラムを書きました。
それ自体はうまくいったのですが、
ヘルプファイルを開いたまま本体であるアプリケーションを終了させた時
そのヘルプが残ったままという現象に気づきました。
ShellExecuteの戻り値で開いたファイルのインスタンス・ハンドルが
分かるのでそれを使ってどうにかファイルを終了させられないかと
思うのですが、ファイルの終了の方法が分からず。

「アプリケーションを終了時にヘルプファイルが開いたままの場合
それを終了させる」ことの実装について、お知りの方がおられましたら
教えて下さい。

作成者:  jacoby [ 2008年6月23日(月) 04:33 ]
記事の件名:  CloseHandleでは閉じてくれない?

ヘルプ・ファイルの「インスタンス・ハンドル」を入れるためのグローバル変数(hHelpFile)、を用意してヘルプの表示時に
コード:
hHelpFile=ShellExecute(hMainWnd,"open",readMe_FullPathName,NULL,NULL,SW_SHOW)
として、
もしアプリ終了時にヘルプが開いたままならそれを閉じるために
メイン・ウインドウのデストロイ・イベントで
コード:
 CloseHandle(hHelpFile)
としてみたのですが、これではヘルプを閉じてくれないようです。
試しに
コード:
DestroyWindow(hHelpFile)
としてもみたのですがこれもダメ。
ウインドウハンドルじゃなくて「インスタンス・ハンドル」ってのが
そもそもどうなんだろうかなと思っているのですが。。。

作成者:  ゲスト [ 2008年6月23日(月) 09:35 ]
記事の件名: 

ShellExecute/ShellExecuteExで得られるHINSTANCEはエラーを得るため以外には使えないらしいですが

ShellExecuteの変わりに
CreateProcessかShellExecuteEx使ってみては

作成者:  ゲスト [ 2008年6月23日(月) 11:16 ]
記事の件名: 

ヘルプファイルを開いたときに、GetActiveWindow 関数(API)でウインドウハンドルを取得するのはどうでしょうか。

作成者:  jacoby [ 2008年6月23日(月) 22:33 ]
記事の件名:  レスありがとうございます。

引用:
ShellExecute/ShellExecuteExで得られるHINSTANCEはエラーを得るため以外には使えないらしいですが

ShellExecuteの変わりに
CreateProcessかShellExecuteEx使ってみては
レスありがとうございます。
自分の調べた限りですが、CreateProcessは「実行ファイル」を開くのに
使われる命令のようで、その他のファイルはShellExecuteが一般的との
印象です。
ShellExecuteExはShellExecuteの拡張版とも言えるもののようなので
やはり元のShellExecuteで出来る筈じゃないかなとも思っています。

それから、GetActiveWindow 関数ですが、もしもShellExecuteの設定で
ファイルをアクティブなウインドウとして開かなかった場合にはどうなるのかなと、、
まだ実際に自分で試してないので何とも言えないのですが。。。

作成者:  イグトランス [ 2008年6月24日(火) 00:16 ]
記事の件名: 

正攻法は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が今で言うところのプロセスハンドルに近い役割を果たしていたからです。

作成者:  jacoby [ 2008年6月24日(火) 02:00 ]
記事の件名: 

引用:
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のプロジェクトエディターがしっかり開いたままの
ヘルプを閉じて終了する様を眺めつつ、思っています。

ゲストさん、イグトランスさん、レスありがとうございました。
またよろしくお願いします。

作成者:  イグトランス [ 2008年6月24日(火) 09:09 ]
記事の件名: 

そうです。ShellExecuteExではプロセスIDが取得できませんが、プロセスハンドルが分かれば、GetProcessId関数でプロセスIDは容易に判明します。言葉足らずでした、すみません。プロセスハンドルとプロセスIDは2つ必要というわけではなく、関数によってどちらを引数に取るかが異なるので、場合によってどちらを使うか変わってくるというだけです。

CreateProcessでも、自分で関連付けされているアプリケーションのパスを調べてくればいいはずなのですが、結構面倒そうなんですよね。

作成者:  ゲスト2 [ 2008年6月28日(土) 13:38 ]
記事の件名: 

> プロセスハンドルやプロセスIDが分かれば、それを基に対象のウィンドウハンドルを探せます。

イグトランスさん、プロセスIDからウィンドウハンドルを探す方法を具体的に教えていただけるとうれしいのですが。

作成者:  konisi [ 2008年6月28日(土) 15:39 ]
記事の件名: 

EnumWindowsとGetWindowThreadProcessIdを上手く使えばいけたと思います。

作成者:  ゲスト2 [ 2008年7月01日(火) 08:41 ]
記事の件名: 

> EnumWindowsとGetWindowThreadProcessIdを上手く使えばいけたと思います。

konisiさんありがとうございました。何とかなりそうです。

作成者:  田中 宏 [ 2009年1月04日(日) 13:06 ]
記事の件名:  不具合を修正しコードを変更しました。

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日不具合を修正しコードを変更しました。

作成者:  げすと5 [ 2009年1月18日(日) 15:49 ]
記事の件名:  インスタンスハンドルからウインドウハンドルを取得する

日本語が怪しげなのと、VBらしきコードなので・・・あれですが
下記が参考になると思います。

http://support.microsoft.com/kb/242308/ja

ABに書き直しても、それほど手間ではないと思います。

ページ 11 全ての表示時間は UTC+09:00 です
Powered by phpBB® Forum Software © phpBB Limited
https://www.phpbb.com/