2009-06-01 9 views
1

Ich versuche, ein Nachrichtenfenster zu erstellen, um Fenstermeldungen von einer MFC-Bibliotheksklasse innerhalb einer Winforms-Anwendung zu empfangen.Wie erstelle ich ein Nur-Nachrichtenfenster von Windows Forms?

Ich habe versucht Subklassen NativeWindow und im Konstruktor ein Fensterhandle wie folgt anfordernden:

CreateParams cp = new CreateParams(); 
cp.Parent = (IntPtr)HWND_MESSAGE; 
this.CreateHandle(cp); 

aber ich bekomme eine Win32Exception mit der Meldung „Fehler beim Erstellen des Fenster-Handle“ geworfen. Wie erstelle ich ein Nur-Nachrichtenfenster aus Windows Forms? Verwenden Sie NativeWindow den richtigen Ansatz?

+0

Können Sie eine Antwort markieren? –

+1

Keine der angegebenen Antworten funktionierte für mich - am Ende musste ich C++/CLI verwenden und in die Windows API eintauchen. Ich poste den Code, den ich benutzt habe, aber er gehört einem früheren Arbeitgeber. – Simon

Antwort

0

Ich glaube, dass Sie auch eine Fensterklasse angeben müssen.

+0

Worauf sollte ich es einstellen? Ich habe "Message" und den Namen der Klasse ausprobiert, aber keiner hat funktioniert. "Nachricht" gibt mir den gleichen Fehler, und der Klassenname gibt mir "Window-Klassenname ist nicht gültig". – Simon

0

Versuchen Sie das mal:

[DllImport("user32.dll")] 
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 

static IntPtr HWND_MESSAGE = new IntPtr(-3); 

protected override void OnHandleCreated(EventArgs e) 
{ 
    base.OnHandleCreated(e); 
    SetParent(this.Handle, HWND_MESSAGE); 
} 
+0

ACHTUNG: Sie müssen ShowInTaskbar = false setzen. ACHTUNG: Ein Nur-Nachrichten-Fenster ist nutzlos, wenn Sie Nachrichten von einem anderen Prozess senden möchten. Obwohl MSDN angibt, dass ein Nur-Nachrichten-Fenster mit FindWindowEx gefunden werden soll, ist dies nicht der Fall. – Elmue

+0

@Elmue, es ist immer noch nützlich, wenn Sie Broadcast-Nachrichten empfangen möchten –

+0

Sie sollten die MSDN lesen: Ein Nur-Nachrichten-Fenster ermöglicht Ihnen, Nachrichten zu senden und zu empfangen. Es ist nicht sichtbar, hat keine z-Reihenfolge, kann nicht aufgelistet werden und empfängt keine Broadcast-Nachrichten. – Elmue

0

Ich fürchte, dass Sie von einem Form ableiten müssen, und zwingen das Fenster unsichtbar.

Ein anderer Ansatz (im Fall der Klassenbibliothek ist veränderbar) ist ein Nachrichtensystem ohne Fenster laufen (siehe Application.Run und Application.AddMessageFilter, oder wenn Sie es vorziehen pinvokes PeekMessage & Co verwenden).

In diesem Fall können Sie Nachrichten mit PostThreadMessage senden, indem Sie die Thread-ID haben, die Application.Run ausführen, aber tatsächlich können Sie nicht mit dem Anwendungsnachrichten-Pumpenthread synchronisieren, da er nicht auf Nachrichtenbestätigung wartet.

1

Ich weiß, das ist 7,5 Jahre alt, aber nur für den Fall, dass jemand das findet, dachte ich, ich würde antworten. Ich habe Microsofts TimerNativeWindow code verwendet und die Timerfunktion entfernt. Ich endete mit diesem Ansatz:

public class MyNativeWindow : NativeWindow 
    { 
     private readonly string _caption; 
     private const int WmClose = 0x0010; 

     [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] 
     private static readonly HandleRef HwndMessage = new HandleRef(null, new IntPtr(-3)); 

     [DllImport("user32.dll", CharSet = CharSet.Auto)] 
     [ResourceExposure(ResourceScope.None)] 
     private static extern IntPtr PostMessage(HandleRef hwnd, int msg, int wparam, int lparam); 

     [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] 
     [ResourceExposure(ResourceScope.Process)] 
     private static extern int GetWindowThreadProcessId(HandleRef hWnd, out int lpdwProcessId); 

     [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] 
     [ResourceExposure(ResourceScope.Process)] 
     private static extern int GetCurrentThreadId(); 

     public MyNativeWindow(string caption) 
     { 
      _caption = caption; 
     } 

     public bool CreateWindow() 
     { 
      if (Handle == IntPtr.Zero) 
      { 
       CreateHandle(new CreateParams 
       { 
        Style = 0, 
        ExStyle = 0, 
        ClassStyle = 0, 
        Caption = _caption, 
        Parent = (IntPtr)HwndMessage 
       }); 
      } 
      return Handle != IntPtr.Zero; 
     } 


     public void DestroyWindow() 
     { 
      DestroyWindow(true, IntPtr.Zero); 
     } 

     private bool GetInvokeRequired(IntPtr hWnd) 
     { 
      if (hWnd == IntPtr.Zero) return false; 
      int pid; 
      var hwndThread = GetWindowThreadProcessId(new HandleRef(this, hWnd), out pid); 
      var currentThread = GetCurrentThreadId(); 
      return (hwndThread != currentThread); 
     } 

     private void DestroyWindow(bool destroyHwnd, IntPtr hWnd) 
     { 
      if (hWnd == IntPtr.Zero) 
      { 
       hWnd = Handle; 
      } 

      if (GetInvokeRequired(hWnd)) 
      { 
       PostMessage(new HandleRef(this, hWnd), WmClose, 0, 0); 
       return; 
      } 

      lock (this) 
      { 
       if (destroyHwnd) 
       { 
        base.DestroyHandle(); 
       } 
      } 
     } 

     public override void DestroyHandle() 
     { 
      DestroyWindow(false, IntPtr.Zero); 
      base.DestroyHandle(); 
     } 
    }