- 題名: ShowInTaskbar = False でのメインウィンドウハンドルの取得方法について
- 日時: 2009/02/04 14:22:49
- ID: 23906
- この記事の返信元:
- (なし)
- この記事への返信:
- [23907] サンプルソースの訂正2009/02/04 14:26:39
- [23908] Re[1]: ShowInTaskbar = False でのメインウィンドウハンドルの取得方法について2009/02/04 14:41:27
- ツリーを表示
サンプルソースに一部誤りが有りましたので訂正いたします。
static void Main()
{
Application.SetCompatibleTextRenderingDefault(false);
StringBuilder className = new StringBuilder(256);
using (Form1 dummy = new Form1())
{
GetClassName(new HandleRef(null, dummy.Handle), className, className.Capacity);
}
IntPtr hWnd = FindWindow(className.ToString(), null);
if (hWnd == IntPtr.Zero)
{
Application.Run(new Form1());
}
else
{
SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
■No23908に返信(Hongliangさんの記事) > EventWaitHandle を使って名前付きイベントで多重起動を通知すればいいかと思います。 > 先に起動した方は EventWaitHandle をワーカスレッドでタイムアウト無しの WaitOne。待機が完了したら Invoke を使って終了処理。 > 後に起動した方は EventWaitHandle を Set。 > 多重起動判定も EventWaitHandle 作成時にできますね(コンストラクタの引数 createNew が false を返したら 2 つ目のインスタンスが起動)。 Hongliangさん、お返事ありがとうございます。 EventWaitHandle や 名前付きイベント と言う物を始めて知りまして、現在調べている 最中なのですが、厚かましいお願いを承知の上で、もし良ければお手隙の際で結構です ので具体的なサンプルコードを提示しては頂けないでしょうか? 宜しくお願い致します。
■No23908に返信(Hongliangさんの記事)
> EventWaitHandle を使って名前付きイベントで多重起動を通知すればいいかと思います。
実業務が一段落しましたので EventWaitHandle について調べて見ました。
Hongliangさんに教えて頂いた内容を元にソースを記述してみたのですが、雰囲気的に
下記のような記述で合っているでしょうか?
public partial class Form1 : Form
{
private EventWaitHandle ewh;
public Form1()
{
InitializeComponent();
bool createdNew;
ewh = new EventWaitHandle(false, EventResetMode.AutoReset,
"hogehoge", out createdNew);
if (!createdNew)
{
bool ret = ewh.Set();
}
else
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
ewh.WaitOne();
MessageBox.Show("他で起動されたから終了");
e.Result = 0;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
ewh.Close();
this.Close();
}
}
ただし1点分からない事がありましたので、引き続き教えて頂けると幸いです。
EventWaitHandleのコンストラクタの説明(ヘルプ)に「(非)シグナル状態」と「スレッド
のブロック」について以下の様に記載が有ります。
> イベントの初期状態が非シグナル状態の場合、イベントを待機するスレッドはブロックされます。
> イベントの初期状態がシグナル状態で、ManualReset フラグが mode に指定されている場合、
> イベントを待機するスレッドはブロックされません。
> イベントの初期状態がシグナル状態で、mode が AutoReset である場合、イベントを待機している
> 最初のスレッドはすぐに解放されますが、その後イベントがリセットされ、後続のスレッドはブロックされます。
この部分がどうにもイメージし難いのですが、どなたかもう少し噛み砕いた形で教えて
頂けないでしょうか?
以上 宜しくお願い致します。
■No23981に返信(Hongliangさんの記事)
Hongliangさん、非常に分かりやすい説明を書いて下さって本当にありがとうございました。
仕様をきちんと把握できたお陰で、実務にも応用できそうです。
最後に実装したコードを"回答"として挙げ、本スレッドを"解決済み"とさせて頂きます。
static class Program
{
public static EventWaitHandle evnt = null;
[STAThread]
static void Main()
{
bool createdNew;
evnt = new EventWaitHandle(false, EventResetMode.ManualReset, "hogehoge", out createdNew);
if (createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
evnt.Set();
};
}
}
public partial class Form1 : Form
{
private Thread WaitThread = null;
public Form1()
{
InitializeComponent();
WaitThread = new Thread(new ThreadStart(WaitOne));
WaitThread.IsBackground = true;
WaitThread.Priority = ThreadPriority.Lowest;
WaitThread.Start();
}
public void WaitOne()
{
Program.evnt.WaitOne();
this.Invoke((MethodInvoker)delegate
{
this.Close();
});
}
}
分類:[.NET]
先日は"角の丸いフォーム"の件でお世話になりました、まことと申します。 今回も、引き続き開発中の拡大鏡プログラムに起因する質問をさせて下さい。 現在"プログラムの実行"をトリガーに、トグルスイッチの様な感じで起動⇔終了を 切り替えたいと考えております。 理論的には起動時に二重起動のチェックを行い、起動済みのプロセスからメインの ウィンドウハンドルを取得し、WM_CLOSEでも送ってやれば…と思っていたのですが 表題に書いてあります様に、ShowInTaskbar を False とした場合の Process.MainWindowHandle が常に 0 となってしまい、上手く行きません。 自分なりに調べてみた結果、Process を足掛かりにフォームのハンドルを取得する 事が出来ないと判断したのですが、まずこの判断は正しいのでしょうか? 更に FindWindow と GetClassName を使用して、同一クラス名を持つウィンドウの ハンドルを取得しようと試みているのですが、自身のクラス名を探し出すと当り前 ですが自分自身を検出してしまい、起動すらしなくなります(苦笑) そこで Application.Run の前にダミーのフォームをインスタンス化し、それから クラス名を取得した後にダミーフォームを破棄してから FindWindow を呼び出して いるのですが、スマートな方法では無い様な気がしてなりません。 尚 Form.Text は都合により空文字 or としていますので、ウィンドウタイトルで 検索する事出来ない物と考えております。 上記以外の方法で実行中の同一プログラムのウィンドウハンドルを取得する方法が 有りましたら教えて頂けないでしょうか。 以上 宜しくお願い致します。 static void Main() { Application.SetCompatibleTextRenderingDefault(false); using (Form1 dummy = new Form1()) { StringBuilder className = new StringBuilder(256); GetClassName(new HandleRef(null, dummy.Handle), className, className.Capacity); } IntPtr hWnd = FindWindow(className.ToString(), null); if (hWnd == IntPtr.Zero) { Application.Run(new Form1()); } else { SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); } }