2008-09-05 28 views
22

私はこの質問をする前にgoogleとsoを検索しました。基本的に私はそれにコンパイルされたフォームを持つDLLを持っています。フォームは、情報を画面に表示するために使用されます。最終的には非同期になり、dllで多くのカスタマイズを公開します。今のところ私はちょうどそれが適切に表示したい。私が抱えている問題は、PowerShellセッションでロードすることによってDLLを使用することです。だから私はフォームを表示し、それがトップに来て、フォーカスを持って取得しようとすると、それは他のすべてのアプリケーションを表示する上で問題はありませんが、私の人生はPowershellウィンドウ。私が現在使っているコードを表示してみましょう。私は一度それを把握すればそれの大部分は必要ないと確信しています、これはちょうど私がGoogleで見つけたすべてのものを表しています。C#フォームのフォーカスを強制する

CLass Blah 
{ 
     [DllImport("user32.dll", EntryPoint = "SystemParametersInfo")] 
     public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni); 

     [DllImport("user32.dll", EntryPoint = "SetForegroundWindow")] 
     public static extern bool SetForegroundWindow(IntPtr hWnd); 

     [DllImport("User32.dll", EntryPoint = "ShowWindowAsync")] 
     private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow); 
     private const int WS_SHOWNORMAL = 1; 

    public void ShowMessage(string msg) 
    { 
      MessageForm msgFrm = new MessageForm(); 
      msgFrm.lblMessage.Text = "FOO"; 
      msgFrm.ShowDialog(); 
      msgFrm.BringToFront(); 
      msgFrm.TopMost = true; 
      msgFrm.Activate(); 

      SystemParametersInfo((uint)0x2001, 0, 0, 0x0002 | 0x0001); 
      ShowWindowAsync(msgFrm.Handle, WS_SHOWNORMAL); 
      SetForegroundWindow(msgFrm.Handle); 
      SystemParametersInfo((uint)0x2001, 200000, 200000, 0x0002 | 0x0001); 
    } 
} 

私は、私はちょうど私がしようとした事を見せたかった、というの大半が必要か間違っても、平らにされていないいずれかのことを確信して言うように。また、私が言及したように、私は別のスレッドを必要とすると思われるある時点でこれを非同期に表示する予定です。フォームを自分自身のスレッドに分割するとPowershellセッションにフォーカスを当てやすくなりますか?


@Joel、情報ありがとうございます。ここで私はあなたの提案に基づいて試したものです:

msgFrm.ShowDialog(); 
msgFrm.BringToFront(); 
msgFrm.Focus(); 
Application.DoEvents(); 

フォームはまだアップ下PowerShellセッションをしています。私はスレッドを作成する作業を進めます。私は前にスレッドを生成しましたが、親スレッドが子スレッドと話す必要があった場所は決してありませんでした。

これまでのすべてのアイデアのためのThnks。


いいえ、スレッディングは問題を処理しました。 @おかあさん、私はそれらの両方を試しました。どちらも(どちらも一緒に)働かなかった。私はスレッディングを使用することに関して何が悪いのか不思議です。私はApplication.Runを使用していないので、まだ問題があります。親スレッドと子スレッドの両方にアクセスできるメディエータクラスを使用しています。そのオブジェクトでは、ReaderWriterLockを使用して、子スレッドが作成するフォームに表示したいメッセージを表す1つのプロパティをロックしています。親はプロパティをロックし、表示する内容を書き込みます。子スレッドはプロパティをロックし、フォーム上のラベルをどのように変更する必要があるのか​​を読み込みます。私は本当に幸せではないポーリング間隔(デフォルトは500ms)でこれを行う必要がありますが、私はイベントの方法を見つけることができませんでした子供のスレッドは、ポーリングをしている。

+0

あなただけのフォーム内のコントロールのいずれかに焦点を()を呼び出すことができますか? –

+0

ありがとうございました。 @Chadちょうど私がすでに得ていたのと同じ結果で巻き上げられたフォームにコントロールをフォーカスしようとしています。 @Dean、私はあなた自身のスレッドにフォームを分割する必要があなたの方法を使用すると思います。私はある時点でそれをやり遂げることを計画していたので、今から始めてみようと思います。 – EBGreen

答えて

16

また、前景をアクティブにしてウィンドウを前面に持ってきても困っていました。最終的に私のために働いたコードはここにあります。あなたの問題を解決するかどうかは分かりません。

基本的に、ShowWindow()とSetForegroundWindow()を呼び出します。

using System.Diagnostics; 
using System.Runtime.InteropServices; 

// Sets the window to be foreground 
[DllImport("User32")] 
private static extern int SetForegroundWindow(IntPtr hwnd); 

// Activate or minimize a window 
[DllImportAttribute("User32.DLL")] 
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 
private const int SW_SHOW = 5; 
private const int SW_MINIMIZE = 6; 
private const int SW_RESTORE = 9; 

private void ActivateApplication(string briefAppName) 
{ 
    Process[] procList = Process.GetProcessesByName(briefAppName); 

    if (procList.Length > 0) 
    { 
     ShowWindow(procList[0].MainWindowHandle, SW_RESTORE); 
     SetForegroundWindow(procList[0].MainWindowHandle); 
    } 
} 
+0

どのパラメータをShowWindow()に渡す必要がありますか?方法???? – Hassanation

+0

これらのすべてのSW_定数の元の定義はどこにありますか? – gonzobrains

+1

@gonzobrains http://pinvoke.net –

0

このためにwin32関数をインポートする必要はありません。 .Focus()で十分でない場合、フォームには.BringToFront()メソッドも必要です。それが失敗した場合は、.TopMostプロパティをtrueに設定できます。 にしたくない場合は、を永遠に残しておき、フォームがそのメッセージを処理してfalseに戻すようにApplication.DoEventsを呼び出します。

3

にShowDialog()はちょうどショー()とは異なるウィンドウの動作を持っていませんか?

あなたがしようとした場合はどう:

msgFrm.Show(); 
msgFrm.BringToFront(); 
msgFrm.Focus(); 
3

TopMostの=はtrue。 .Activate()?

どちらか良いですか?あなたはApplication.Runとそれを呼び出すことはありませんし、それがスレッドを飲み込むだろう場合、それが正しく動作文句を言わないよう

独自のスレッドにそれを分割するには、ビット悪です。最悪の場合のシナリオでは、別のプロセスに分離し、ディスクまたはWCF経由で通信できると思います。ここで

16

は、私は数年前から1つのフォームまたは別に使用してきたいくつかのコードです。別のアプリのポップアップでウィンドウを作成するにはいくつかの問題があります。あなたはウィンドウハンドルを持っていたら、次の操作を行います。

 if (IsIconic(hWnd)) 
     ShowWindowAsync(hWnd, SW_RESTORE); 

     ShowWindowAsync(hWnd, SW_SHOW); 

     SetForegroundWindow(hWnd); 

     // Code from Karl E. Peterson, www.mvps.org/vb/sample.htm 
     // Converted to Delphi by Ray Lischner 
     // Published in The Delphi Magazine 55, page 16 
     // Converted to C# by Kevin Gale 
     IntPtr foregroundWindow = GetForegroundWindow(); 
     IntPtr Dummy = IntPtr.Zero; 

     uint foregroundThreadId = GetWindowThreadProcessId(foregroundWindow, Dummy); 
     uint thisThreadId  = GetWindowThreadProcessId(hWnd, Dummy); 

     if (AttachThreadInput(thisThreadId, foregroundThreadId, true)) 
     { 
     BringWindowToTop(hWnd); // IE 5.5 related hack 
     SetForegroundWindow(hWnd); 
     AttachThreadInput(thisThreadId, foregroundThreadId, false); 
     } 

     if (GetForegroundWindow() != hWnd) 
     { 
     // Code by Daniel P. Stasinski 
     // Converted to C# by Kevin Gale 
     IntPtr Timeout = IntPtr.Zero; 
     SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, Timeout, 0); 
     SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Dummy, SPIF_SENDCHANGE); 
     BringWindowToTop(hWnd); // IE 5.5 related hack 
     SetForegroundWindow(hWnd); 
     SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Timeout, SPIF_SENDCHANGE); 
     } 

は、私はそれが 関係ありませんが、ここで上記のコードの定数と輸入がされている他の事をしているのでので、ユニット全体を投稿しません。

//Win32 API calls necesary to raise an unowned processs main window 

[DllImport("user32.dll")] 

private static extern bool SetForegroundWindow(IntPtr hWnd); 
[DllImport("user32.dll")] 
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); 
[DllImport("user32.dll")] 
private static extern bool IsIconic(IntPtr hWnd); 
[DllImport("user32.dll", SetLastError = true)] 
private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni); 
[DllImport("user32.dll", SetLastError = true)] 
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId); 
[DllImport("user32.dll")] 
private static extern IntPtr GetForegroundWindow(); 
[DllImport("user32.dll")] 
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); 
[DllImport("user32.dll")] 
static extern bool BringWindowToTop(IntPtr hWnd); 

[DllImport("user32.dll")] 
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, Int32 nMaxCount); 
[DllImport("user32.dll")] 
private static extern int GetWindowThreadProcessId(IntPtr hWnd, ref Int32 lpdwProcessId); 
[DllImport("User32.dll")] 
public static extern IntPtr GetParent(IntPtr hWnd); 

private const int SW_HIDE = 0; 
private const int SW_SHOWNORMAL = 1; 
private const int SW_NORMAL = 1; 
private const int SW_SHOWMINIMIZED = 2; 
private const int SW_SHOWMAXIMIZED = 3; 
private const int SW_MAXIMIZE = 3; 
private const int SW_SHOWNOACTIVATE = 4; 
private const int SW_SHOW = 5; 
private const int SW_MINIMIZE = 6; 
private const int SW_SHOWMINNOACTIVE = 7; 
private const int SW_SHOWNA = 8; 
private const int SW_RESTORE = 9; 
private const int SW_SHOWDEFAULT = 10; 
private const int SW_MAX = 10; 

private const uint SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000; 
private const uint SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001; 
private const int SPIF_SENDCHANGE = 0x2; 
+1

これは私のために働いたここの唯一の答え、共有のためのGevinに感謝! –

+2

Btw、レイモンド・チェンによると、これはUIのフリーズを引き起こす可能性があります。 私はあなたに警告しました:入力キューを接続する危険性 http://blogs.msdn.com/b/oldnewthing/archive/2008/ 08/01/8795860.aspx この問題をケビンに会ったことがありますか? –

+0

問題が報告されずに24時間365日稼働するアプリケーションの多くの顧客サイトで、このコードを長年にわたって使用してきました。それは陳が正しくないことを意味するものではありませんが、それが問題であれば、それは非常に頻繁に起こるわけではありません。 –

0

ダイアログを呼び出し元のフォームの子にしたくないのですか?

これを行うには、呼び出し元のウィンドウにパスが必要で、 はShowDialog(IWin32Window所有者)メソッドを使用します。

2

次のソリューションは、あなたの要件を満たす必要があります。

  1. 総会はPowerShellのにロードすることができ、メインクラスがこのインスタンスでShowMessageメソッドが呼び出されると、新しいウィンドウが示されており、
  2. 活性化される
  3. をインスタンス化ShowMessageを複数回呼び出すと、この同じウィンドウがタイトルテキストを更新して有効になります
  4. ウィンドウの使用を停止するには、Disposeメソッドを呼び出します。

ステップ1

(powershell.exe) 
mkdir C:\TEMP\PshWindow 
cd C:\TEMP\PshWindow 

(あなたが自然に独自のディレクトリを使用することができます)の一時的な作業ディレクトリを作成してみましょう。ステップ2:それでは、私たちはPowerShellでと対話されるクラスを定義してみましょう:

// file 'InfoProvider.cs' in C:\TEMP\PshWindow 
using System; 
using System.Threading; 
using System.Windows.Forms; 

namespace PshWindow 
{ 
    public sealed class InfoProvider : IDisposable 
    { 
     public void Dispose() 
     { 
      GC.SuppressFinalize(this); 
      lock (this._sync) 
      { 
       if (!this._disposed) 
       { 
        this._disposed = true; 
        if (null != this._worker) 
        { 
         if (null != this._form) 
         { 
          this._form.Invoke(new Action(() => this._form.Close())); 
         } 
         this._worker.Join(); 
         this._form = null; 
         this._worker = null; 
        } 
       } 
      } 
     } 

     public void ShowMessage(string msg) 
     { 
      lock (this._sync) 
      { 
       // make sure worker is up and running 
       if (this._disposed) { throw new ObjectDisposedException("InfoProvider"); } 
       if (null == this._worker) 
       { 
        this._worker = new Thread(() => (this._form = new MyForm(this._sync)).ShowDialog()) { IsBackground = true }; 
        this._worker.Start(); 
        while (this._form == null || !this._form.Created) 
        { 
         Monitor.Wait(this._sync); 
        } 
       } 

       // update the text 
       this._form.Invoke(new Action(delegate 
       { 
        this._form.Text = msg; 
        this._form.Activate(); 
       })); 
      } 
     } 

     private bool _disposed; 
     private Form _form; 
     private Thread _worker; 
     private readonly object _sync = new object(); 
    } 
} 

と同様に表示されますフォーム:

// file 'MyForm.cs' in C:\TEMP\PshWindow 
using System; 
using System.Drawing; 
using System.Threading; 
using System.Windows.Forms; 

namespace PshWindow 
{ 
    internal sealed class MyForm : Form 
    { 
     public MyForm(object sync) 
     { 
      this._sync = sync; 
      this.BackColor = Color.LightGreen; 
      this.Width = 200; 
      this.Height = 80; 
      this.FormBorderStyle = FormBorderStyle.SizableToolWindow; 
     } 

     protected override void OnShown(EventArgs e) 
     { 
      base.OnShown(e); 
      this.TopMost = true; 

      lock (this._sync) 
      { 
       Monitor.PulseAll(this._sync); 
      } 
     } 

     private readonly object _sync; 
    } 
} 

ステップ3:...そして、それを楽しんでいるためにPowerShellでアセンブリをロードします:

(powershell.exe) 
csc /out:PshWindow.dll /target:library InfoProvider.cs MyForm.cs 

ステップ4 ...のは、アセンブリをコンパイルしてみましょう

(powershell.exe) 
[System.Reflection.Assembly]::LoadFile('C:\TEMP\PshWindow\PshWindow.dll') 
$a = New-Object PshWindow.InfoProvider 
$a.ShowMessage('Hello, world') 

グリーン「Hello、world」というタイトルのウィンドウがポップアップしてアクティブになるはずです。あなたはPowerShellウィンドウを再活性化し、入力した場合:

$a.ShowMessage('Stack overflow') 

ウィンドウのタイトルは、「スタックオーバーフロー」に変更する必要がありますし、ウィンドウが再びアクティブにする必要があります。

は、私たちのウィンドウで作業を停止したオブジェクトを配置するには、次のWindows XP SP3、x86およびWindows VistaのSP1、x64の両方で期待どおり

$a.Dispose() 

このソリューションは、動作します。このソリューションの仕組みについて疑問がある場合は、このエントリを詳細な説明で更新できます。今のところ私はコードが自明であることを望んでいます。

1

大変感謝しています。 私はそれを少し短くしたと思う、ここで私は別スレッドに入れて、うまく動いているようだ。

private static void StatusChecking() 
     { 
      IntPtr iActiveForm = IntPtr.Zero, iCurrentACtiveApp = IntPtr.Zero; 
      Int32 iMyProcID = Process.GetCurrentProcess().Id, iCurrentProcID = 0; 
      IntPtr iTmp = (IntPtr)1; 
      while (bIsRunning) 
      { 
       try 
       { 
        Thread.Sleep(45); 
        if (Form.ActiveForm != null) 
        { 
         iActiveForm = Form.ActiveForm.Handle; 
        } 
        iTmp = GetForegroundWindow(); 
        if (iTmp == IntPtr.Zero) continue; 
        GetWindowThreadProcessId(iTmp, ref iCurrentProcID); 
        if (iCurrentProcID == 0) 
        { 
         iCurrentProcID = 1; 
         continue; 
        } 
        if (iCurrentProcID != iMyProcID) 
        { 
         SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, IntPtr.Zero, 0); 
         SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, IntPtr.Zero, SPIF_SENDCHANGE); 
         BringWindowToTop(iActiveForm); 
         SetForegroundWindow(iActiveForm); 
        } 
        else iActiveForm = iTmp; 
       } 
       catch (Exception ex) 
       { 
        Definitions.UnhandledExceptionHandler(ex, 103106); 
       } 
      } 
     } 

私は定義をrepastingわざわざ `tを...

関連する問題