2008-09-05 26 views
22

Vì vậy, tôi đã tìm kiếm google và SO trước khi hỏi câu hỏi này. Về cơ bản tôi có một DLL có một hình thức biên dịch vào nó. Biểu mẫu sẽ được sử dụng để hiển thị thông tin cho màn hình. Cuối cùng nó sẽ không đồng bộ và hiển thị nhiều tùy biến trong dll. Bây giờ tôi chỉ muốn nó hiển thị đúng. Vấn đề mà tôi đang gặp phải là tôi sử dụng dll bằng cách tải nó trong một phiên Powershell. Vì vậy, khi tôi cố gắng để hiển thị các hình thức và làm cho nó đến đầu và tập trung, Nó không có vấn đề với hiển thị trên tất cả các ứng dụng khác, nhưng tôi không thể cho cuộc sống của tôi làm cho nó hiển thị trên cửa sổ Powershell . Đây là mã mà tôi hiện đang sử dụng để thử và hiển thị mã đó. Tôi chắc chắn rằng phần lớn của nó sẽ không được yêu cầu một khi tôi tìm ra nó, điều này chỉ đại diện cho tất cả những điều mà tôi tìm thấy thông qua google.C# Force Form Focus

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); 
    } 
} 

Như tôi nói chắc chắn rằng hầu hết điều đó là không cần thiết hoặc thậm chí không đúng, tôi chỉ muốn hiển thị những điều tôi đã thử. Ngoài ra, như tôi đã đề cập, tôi có kế hoạch để có điều này được hiển thị không đồng bộ tại một số điểm mà tôi nghi ngờ sẽ gió lên đòi hỏi một sợi riêng biệt. Sẽ tách các hình thức ra thành chủ đề riêng của nó làm cho nó dễ dàng hơn để làm cho nó để có được tập trung trong phiên Powershell?


@Joel, cảm ơn thông tin. Đây là những gì tôi đã cố gắng dựa trên đề xuất của bạn:

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

Hình thức vẫn đi lên dưới phiên Powershell. Tôi sẽ tiếp tục làm việc với luồng. Tôi đã sinh ra các chủ đề trước đây nhưng không bao giờ nơi mà các chủ đề cha mẹ cần thiết để nói chuyện với các chủ đề con, vì vậy chúng tôi sẽ xem nó như thế nào đi.

Thnks cho tất cả ý tưởng cho đến nay mọi người.


Ok, luồng này đã giải quyết được sự cố. @Quarrelsome, tôi đã thử cả hai. Cả hai (không phải cả hai cùng nhau) đều hoạt động. Tôi tò mò về điều gì là xấu về việc sử dụng luồng? Tôi không sử dụng Application.Run và tôi chưa có vấn đề gì. Tôi đang sử dụng một lớp hòa giải mà cả chuỗi gốc và chuỗi con có quyền truy cập. Trong đối tượng đó, tôi đang sử dụng ReaderWriterLock để khóa một thuộc tính đại diện cho thông báo mà tôi muốn hiển thị trên biểu mẫu mà chuỗi con tạo ra. Các phụ huynh khóa tài sản sau đó viết những gì sẽ được hiển thị. Các chủ đề con khóa tài sản và đọc những gì nó nên thay đổi nhãn trên biểu mẫu để. Đứa trẻ phải làm điều này trong một khoảng thời gian bỏ phiếu (tôi mặc định nó là 500ms) mà tôi không thực sự hạnh phúc, nhưng tôi không thể tìm thấy một sự kiện hướng dẫn để cho các chủ đề con biết rằng proerty đã thay đổi, vì vậy tôi ' m bị mắc kẹt với việc bỏ phiếu.

+0

có thể bạn chỉ cần gọi Focus() trên một trong các điều khiển trong các hình thức? –

+0

Cảm ơn bạn đã trả lời. @Chỉ, chỉ cần cố gắng tập trung() một điều khiển trên biểu mẫu vết thương với cùng kết quả mà tôi đã nhận được. @Dean, tôi nghĩ rằng để sử dụng phương pháp của bạn, tôi sẽ cần phải tách biểu mẫu ra thành chuỗi riêng của nó. Tôi đã lên kế hoạch để làm điều đó nyway tại một số điểm vì vậy tôi đoán tôi sẽ bắt đầu vào đó ngay bây giờ. – EBGreen

Trả lời

16

Tôi cũng gặp sự cố khi kích hoạt và đưa cửa sổ lên nền trước. Đây là mã mà cuối cùng đã làm việc cho tôi. Tôi không chắc chắn nếu nó sẽ giải quyết vấn đề của bạn.

Về cơ bản, hãy gọi ShowWindow() rồi 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

thông số nào tôi nên chuyển đến ShowWindow(); phương pháp???? – Hassanation

+0

Bạn tìm định nghĩa gốc cho tất cả các hằng số SW_ ở đâu? – gonzobrains

+1

@gonzobrains http://pinvoke.net –

0

Bạn không cần nhập bất kỳ hàm win32 nào cho điều này. Nếu .Focus() không đủ, biểu mẫu cũng phải có phương thức .BringToFront() mà bạn có thể sử dụng. Nếu không thành công, bạn có thể đặt thuộc tính .TopMost thành true. Bạn không muốn để lại nó đúng mãi mãi, vì vậy hãy gọi Application.DoEvents để biểu mẫu có thể xử lý thông báo đó và đặt lại thành sai.

3

Không ShowDialog() có hành vi cửa sổ khác với chỉ Hiển thị()?

gì nếu bạn đã cố gắng:

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

topmost = true; .Kích hoạt()?

Một trong số đó có lợi ích gì không?

Tách nó ra thành chủ đề riêng của nó là một chút ác vì nó sẽ không hoạt động đúng nếu bạn không gọi nó bằng Application.Run và điều đó sẽ nuốt luồng. Trong trường hợp xấu nhất, tôi đoán bạn có thể tách nó ra thành một quy trình khác và giao tiếp thông qua đĩa hoặc WCF.

16

Dưới đây là một số mã mà tôi đã sử dụng trên một biểu mẫu này hoặc biểu mẫu khác trong một vài năm. Có một vài gotchas để làm cho một cửa sổ trong một ứng dụng khác bật lên. Một khi bạn có tay cầm cửa sổ làm việc này:

 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); 
     } 

tôi sẽ không gửi toàn bộ đơn vị từ năm kể từ khi nó làm những việc khác mà không liên quan nhưng đây là những hằng số và nhập khẩu cho các mã trên.

//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

Đây là câu trả lời duy nhất ở đây phù hợp với tôi, cảm ơn Gevin đã chia sẻ! –

+2

Btw, có vẻ như một hành động nguy hiểm theo Raymond Chen điều này có thể kích hoạt giao diện người dùng: Tôi cảnh báo bạn: Những mối nguy hiểm khi gắn hàng đợi đầu vào http://blogs.msdn.com/b/oldnewthing/archive/2008/ 08/01/8795860.aspx Bạn đã bao giờ gặp vấn đề này Kevin chưa? –

+0

Được sử dụng mã này trong nhiều năm tại nhiều trang web của khách hàng trong một ứng dụng chạy 24x7 mà không có sự cố nào được báo cáo. Điều đó không có nghĩa là Chen không đúng nhưng nếu nó là một vấn đề thì nó không xảy ra thường xuyên. –

0

Bạn không muốn hộp thoại là con của biểu mẫu gọi điện?

Để thực hiện điều đó, bạn sẽ cần mật khẩu trong cửa sổ gọi và sử dụng phương thức ShowDialog (IWin32Window).

2

Các giải pháp sau đây phải đáp ứng yêu cầu của bạn:

  1. hội có thể được nạp vào PowerShell và lớp học chính instantiated
  2. Khi phương pháp ShowMessage về trường hợp này được gọi là, một cửa sổ mới sẽ hiển thị và kích hoạt
  3. Nếu bạn gọi ShowMessage nhiều lần, cửa sổ tương tự này sẽ cập nhật văn bản tiêu đề của nó và được kích hoạt
  4. Để ngừng sử dụng cửa sổ, hãy gọi phương thức Vứt bỏ

Bước 1: Hãy tạo một thư mục làm việc tạm thời (tự nhiên bạn có thể sử dụng dir của riêng bạn)

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

Bước 2: Bây giờ chúng ta hãy xác định lớp mà chúng ta sẽ được tương tác với trong 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(); 
    } 
} 

cũng như các mẫu sẽ được hiển thị:

// 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; 
    } 
} 

Bước 3: Hãy biên dịch lắp ráp ...

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

Bước 4: ... và tải lắp ráp trong PowerShell để vui chơi với nó:

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

Một màu xanh lá cây cửa sổ có tiêu đề 'Xin chào, thế giới' bây giờ sẽ bật lên và hoạt động.Nếu bạn kích hoạt lại cửa sổ PowerShell và nhập:

$a.ShowMessage('Stack overflow') 

Tiêu đề cửa sổ sẽ thay đổi thành 'Ngăn xếp ngăn xếp' và cửa sổ sẽ hoạt động trở lại.

Để ngừng làm việc với cửa sổ của chúng tôi, vứt bỏ các đối tượng:

$a.Dispose() 

giải pháp này hoạt động như mong đợi trong cả Windows XP SP3, x86 và Windows Vista SP1, x64. Nếu có câu hỏi về cách hoạt động của giải pháp này, tôi có thể cập nhật bài viết này với thảo luận chi tiết. Bây giờ tôi hy vọng mã nếu tự giải thích.

1

Rất cảm ơn mọi người. Tôi nghĩ rằng tôi đã làm cho nó một chút ngắn hơn, đây là những gì tôi đặt trên một sợi riêng biệt và có vẻ là làm việc ok.

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); 
       } 
      } 
     } 

tôi don `t bận tâm repasting các định nghĩa ...