起動元からの重複起動の歯止め?


カタッキー  2002-09-17 21:52:12  No: 104973

コマンドボタンを押すと別なプログラムを開く
メニュープログラムがあるのですが
コマンドボタン?キーボードの上にノートなどの載せてしまい。
延々とプログラムを起動してしまいます。。
そのためプログラム起動毎にOracleの接続を行うので
一人のユーザーで全てのセッションを使用してしまい
システム全体が止まってしまったのですが。プログラム数が多すぎて
今から重複起動のソースを組み込む事はしたくないのですが?
メニューのプログラムから判定する事?歯止めすることできますか?


多分  2002-09-17 23:55:54  No: 104974

よく使い方がわからないけど、
App.PrevInstance
でうまく良くかも。
先輩が作ったので、、、、、、、
動いている事は動いてます。


カタッキー  2002-09-18 00:24:02  No: 104975

App.PrevInstanceを全てのプログラムに入れる事が出来ないので
ここで質問させていただいたのです。
起動元から使えるんですか?


たかみちえ  URL  2002-09-18 00:41:38  No: 104976

PrevInstanceは、自分のソフトが二回目以降の起動のとき(自分のソフトが二重起動しようとしているとき)にTrueになります。
事足りる場合はそれでいいんですけど、
この場合、ほかのソフトの重複起動抑止ということになるから、
それではだめなんじゃないですか?

  えーと、そういう場合は、ボタンのMouseDownに、起動イベントを移動すればいいと思います。
けど、そのままではMouseDownが、押されっぱなしのときにも発生してしまうので、
一回目のMouseDownのときに何らかのフラグを立てて、二回目以降のMouseDownを遮断。
MouseUpのときにそのフラグを消せばいいです。

  ただ、マウスを押しっぱなしにした状態で、キーボードのキーを押して、
そのままマウスをボタンの外に移動して、離したりすると、
たまにMouseUpが発生せず、フラグが立ったままになることがあります。

  なので、Timerなどを使って、おかしいと思われるフラグは消すとか、
何か、いざというときのための処置が必要です。


カタッキー  2002-09-18 00:41:47  No: 104977

メニューのプログラムからは既にいくつでも
プログラムの起動ができる仕様でメニューはいつでも落とす事ができるので
メニュー内でメモリ管理もしくは終了確認の判定?するといった事ができません
お願いします。


カタッキー  2002-09-18 00:46:20  No: 104978

たかみちえさんありがとうございます
教えていただいた処理を使用すると?
Enterでのコマンドボタンを廃止?って事になるんでしょうか?
Clickイベント?確認してみないとわかりませんが?
キーボードでのボタン押下を破棄しないで可能でしょうか?すいません


さわ  2002-09-18 00:56:44  No: 104979

横レス失礼します。
考えられる方法はいくつかあると思います。。
1.メニュー画面でコマンドボタン押した時点でAPIでプロセス上の
  Windowタイトルを全て取得しこれから起動するプログラムのWindowタイトルと
  バッティングしてるか判定して起動破棄?
  (起動プログラム毎にCaptionを持つ為お勧めできませんし同一タイトルがいたらアウトです。)

2.コマンドボタンを押して別プログラムを起動した後に
  押されたコマンドボタンを選択不可(Enabled = False)にして
  APIでアクティブウィンドウのハンドルが押下時点(メニュープログラム)
  のハンドル以外(起動したプログラム)に変更されるまで
  同期のLoop内でDoeventsでイベント逃がしながら判定しつづける。
 (フォーカス遷移が認められるまでって事です)ハンドル変更が確認できたら
  ボタンを選択可能状態に戻す。(未確認ですができると思います)

3.OracleのDBAよりユーザー?その端末の人が何個セッションを使用しているか?取得して
  一つの端末で使用できるセッション数に制限を付けちゃう。
  五個以上Oracleセッションを使用していいたらプログラムの起動をキャンセルするみたいに。
  (全てのプログラム起動に組み込むとパフォーマンスが落ちますが・・・)
  ※アクセスやその他プログラム?システム以外のセッションを覗く判定も必要になってしまいます。
  ※Oracleサーバー側のいくつかの制限が必要になってしまいます。


カタッキー  2002-09-18 01:26:52  No: 104980

さわさん三つもの方法ありがとうございます。
降番2の方法を使用するのが良いのでしょうか?
試してみたいと思うのですが?初心者の為か解らない点があります。
アクティブウィンドウ、フォーカス遷移の判定をどうやったらいいんですか?
教えていただければうれしいです。お願いします。


たかみちえ  URL  2002-09-18 10:11:10  No: 104981

>Enterでのコマンドボタンを廃止?って事になるんでしょうか?
>Clickイベント?確認してみないとわかりませんが?
  まあ、とりあえずやってみてください(^^ゞ
Clickと、MouseDownは、同一のタイミングで起こります。
左クリックだけにしたいなら、引数として押されたボタンが渡されているので、
それが左クリックを示していない場合ははじくようにします。

  Enterキーも入れたい場合は、KeyDownイベントで、Enterキーが押されたら、
MouseDownイベントを起こすようにすればいいだけです。

  ところで、もうひとつ方法を思いつきました。面倒ですけど。
実行ファイルをCreateProcessというAPIを使って起動すると、
その引数として指定するProcessInfo構造体にプロセス情報が返ります。
それを、できるだけ早めに指定したタイマーで、
毎回その構造体が有効なものかを確かめます。
そして、構造体の内容が有効な間は、ボタンを押してもエラーを出すか、無反応にしておきます。
(このあたりはさわさんの言う、DoEventsにおきかえられるかもしれません、
  もしできたら、あんまり変わりないことになりますけどね^^;)


さわ  2002-09-18 21:24:22  No: 104982

あたしの上げた方法ですが試して見たところいくつか問題があったので
1.Enabledでボタン制御した時点で次のフォ-カスに遷移してしまうので
  その部分の考慮が必要です
2.Enabledを廃止した場合Formにフォーカスを移動するとかの処理が必要です。。
↑を無視した場合↓の様になります
↓の関数は単純にForm上にコマンドボタンしかないメニューのイメージです。
コマンドボタンがいくつもプログラム起動とか戻る?終了?とかのイメージです
Public Declare Function GetActiveWindow _
                    Lib "user32" () As Long                     'アクティブウィンドウのハンドル取得

Public Sub nfTest()
    
    Dim lhWnd           As Long     'Windowhwnd
    Dim bExit           As Boolean  '同期LoopOutフラグ
    Dim oCont           As Object   'オブジェクトの参照用
    On Error Resume Next            'エラースルー
    'スレッド待機フラグを下ろす
    bExit = False
    '画面コントロール全てを検索
    For nCnt = 0 To Screen.ActiveForm.Count - 1
        'コマンドボタンのみ検出、Enabledメソッドを持つもの
        If TypeOf Screen.ActiveForm.Controls(nCnt) Is CommandButton Then
            'イベント通知の認識破棄
            Screen.ActiveForm.Controls(nCnt).Enabled = False
        End If
    Next
    'フラグが立つまで同期待機
    Do Until bExit
        'アクティブウィンドウのハンドル取得
        lhWnd = GetActiveWindow
        '当プロジャクトのアクティブフォームのハンドルとスレッド上のアクティブウィンドウハンドルが違う?
        If Screen.ActiveForm.hWnd <> lhWnd Then
            'スレッド待機フラグを立てる
            bExit = True
        End If
        'イベントキューを逃がす
        DoEvents
    Loop
    'イベント通知認識破棄のコマンドボタン全ての再起
    For nCnt = 0 To Screen.ActiveForm.Count
        If TypeOf Screen.ActiveForm.Controls(nCnt) Is CommandButton Then
            Screen.ActiveForm.Controls(nCnt).Enabled = True
        End If
    Next
    'エラークリア
    Err.Clear
End Sub
プログラム起動後に↑の処理で待機させ
実行プログラムにフォーカス遷移しない場合(延々とEnterKeyによるClickイベントを拾ってる状態)待機しながらClickイベントを逃がしています。
Form上にコマンドボタン以外が存在する場合は追加する事になりますが
イメージとしては上記の様な感じでしょうか?
Form上にコマンドボタンをいくつか置いてCallして見れば解ると思います。


さわ  2002-09-18 21:29:52  No: 104983

たいした問題ではないのですが?
↑のプロシージャでoContのオブジェクトが遊んでいます・・・
毎回コントロール配列の参照をするのではなく
Set oCont = Screen.ActiveForm.Controls(nCnt)
にした方が早いのかも?しれません。
あとScreen.ActiveFormもやめた方がいいかもしれません・・・
自分のFormを参照で渡しても同じ事です。
標準モジュールにいても呼べるって程度の問題です。
好まれるかどうかは私には判断しかねますけど。。


さわ  2002-09-18 21:40:46  No: 104984

度々すいません。。
↑の2番のFormにフォーカス当てるのは駄目ですね・・・
  別プログラム起動でNormalFocus?で起動したら自分に当てていまいますから
  なので上のプロシージャなら起動プログラムにフォーカス移動するので大丈夫だと思います。


カタッキー  2002-09-18 22:24:19  No: 104985

お客さんの要望でキーボードで呼べる方がと言う事なので
たかみちえさんの言われた方法で試してみたのですけど
Enterキーを拾う事が出来ませんでした?VB6では駄目なんでしょうか?
後その前におっしゃってたフラグを戻す?タイミングが難しく
戻らない時が発生して呼びたいのに呼べなくなってしまいました
勉強不足ですいません。わざわざ説明までしていただいたのに。

さわさんプロシージャまで用意してもらいありがとうございます
さっそく試してみます。
メニューの画面ですが単純にフォームにボタンが並んでるだけです
最初のメニューでボタンを押すと次のフォームにサブメニューでプログラム毎のボタン
といったかんじです。


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

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






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