Autor Beitrag
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2054
Erhaltene Danke: 376

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Do 22.06.17 20:27 
Hallo Forum

Problemstellung:
Gegeben ist eine "einfache" C# Klasse, die auf Windows Messages reagieren soll, sofern eine Instanz dessen besteht.
Dass WndProc() erst ab der Control-Klasse gegeben ist, weiss ich. Ich brauch' aber kein Control, sondern ein Klasse.

Definieren kann man eine solche Methode mit der DefWindowProc() Funktion:

ausblenden C#-Quelltext
1:
2:
[DllImport("User32.dll")]
static extern IntPtr DefWindowProc(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

Probleme macht der erste Parameter:
hWnd -> A handle to the window procedure that received the message.

Was eine Window Prcedure ist, sieht man hier
Was ich nun nicht verstehe, ist wie ich mir daraus ein Handle erzeugen soll?

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4290
Erhaltene Danke: 863


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 22.06.17 20:48 
Hmmm ... Window ist ja im Prinzip die kernelseitige Entsprechung eines Controls oder anders gesagt ein Control ist eine Kapselung für ein Window. Und es ist ja die WindowProc an die du willst also geht es um WindowMessages die an Windows (ich spreche nicht vom OS ;) ) geschickt werden. Du sagt jetzt gerade also das du gerne WindowMessages empfangen möchtest ohne ein Window zu sein. Ist wie Fussballspielen wollen mit Ball aber bitte ohne Spieler ;)

Direkt an der WindowsAPI gibt es das Konzept von sogenannten Message-Only Windows. Aber es sind dann auch richtige Windows die halt nur nicht angezeigt werden. Den Weg kannst du natürlich mal ausprobieren ich denke aber nicht das das irgendwo hinführt (neugierig auf Ergebnisse wäre ich aber). Letztlich ist es das einfachste einfach in deiner Klasse ein nicht sichtbares Control als Nachrichtenempfänger zu erzeugen. Ich habe auch gerade so ein Déjà-vu das ich das in Delphi (so um die Jahrtausendwende) auch so gemacht habe bzw. so machen musste ;)

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2054
Erhaltene Danke: 376

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Do 22.06.17 21:46 
:lol: In Delphi geht das ganz gut. Mit einer einfachen Klasse habe ich es nicht getestet, wohl aber mit TComponent / Component. Auch da war es so, dass WndProc() erst mit TControl / Control mit dabei war.

Funktioniert hat es in Delphi so:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
TfrDrive = class(TComponent)
private
  FHWndProc: HWND;
  procedure WndProc(var Msg: TMessage); virtual;
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
end;

procedure TfrDrive.WndProc(var Msg: TMessage); // (ref Message msg) ... C# 
begin
  Msg.Result := DefWindowProc(FHWndProc, Msg.Msg, Msg.WParam, Msg.LParam);
  if Msg.Msg = // ... schon konnte man Messages abfragen
end;

constructor TfrDrive.Create(AOwner: TComponent);
begin
  inherited;
  FHWndProc := AllocateHWnd(WndProc);  // Delphi-interne Methode
end;

destructor TfrDrive.Destroy;
begin
  DeallocateHWnd(FHWndProc);  // Delphi-interne Methode
  inherited;
end;

Ich hönnte diese internen Methoden nachstellen, das Problem ist, dass der Code nicht mein Eigentum ist.

Ein unsichtbares Dummy-Control bereitzustellen, ist mir nicht eingefallen. Das kann durchaus funktionieren. :zustimm:

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2054
Erhaltene Danke: 376

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Fr 23.06.17 13:53 
So wie ich es mir vorgestellt habe, geht es doch nicht. Die Message reagiert kein bisschen. Was mache ich falsch?

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
public class MainClass
{
    private WndClass _wndClass;
    
    public MainClass()
    {
        _wndClass = new WndClass();
    }
    
    public static void WndProc(ref Message m)
    {
        if (m.Msg == 537)
            if ((byte)m.WParam == 7)
                MessageBox.Show("OK");
    }
}

class WndClass : Control
{
    protected override void WndProc(ref Message m)
    {
        MainClass.WndProc(ref m);
        base.WndProc(ref m);
    }
}

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3832
Erhaltene Danke: 781

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Fr 23.06.17 14:57 
Leite deine Klasse mal von NativeWindow ab.
Als Beispiel habe ich mal eine Datei aus meinem CD-Ripper angehängt (wobei ich diese Datei auch nur übernommen habe ;-)).

Bei einem Control wird es so sein, daß dieses auch ein Parent-Window benötigt, um überhaupt Nachrichten empfangen zu können.
Einloggen, um Attachments anzusehen!

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2054
Erhaltene Danke: 376

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Fr 23.06.17 20:27 
Irgendetwas fehlt dem Beispiel im Dateianhang. Es besteht nur aus der NativeWindow Klasse und einigen EventArgs, sowie structs, fertig.

Eine NativeWindow Klasse habe ich nun auch, nur reagiert sie nicht:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
public class MainClass
{
    private WndClass _wndClass;
    
    public MainClass()
    {
        _wndClass = new WndClass();
    }
}

class WndClass : NativeWindow 
{
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 537)
            if ((byte)m.WParam == 7)
                MessageBox.Show("^.^");
        base.WndProc(ref m);
    }
}

// Aufruf
MainClass test = new MainClass();
// Geräte abziehen ... anstecken ... keine Reaktion

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4290
Erhaltene Danke: 863


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 23.06.17 23:10 
Das Parenting fehlt und an WM_DEVICECHANGE steht
Zitat:
Windows sends all top-level windows a set of default WM_DEVICECHANGE messages when new devices or media ...


Wir brauchen also nicht irgendein Control. Wenn ich dem native Window das Handle der Main Form eine Anwendung unterjubel kommt da auch WM_DEVICECHANGE an.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
public class MainClass
{
    private WndClass _wndClass;
    
    public MainClass(IWin32Window window)
    {
        _wndClass = new WndClass();
        _wndClass.AssignHandle(window.Handle);
    }
}


Im Beispiel der MSDN Doku zu AssignHandle wird gezeigt wie man das etwas schöner koppelt.

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2054
Erhaltene Danke: 376

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Sa 24.06.17 01:39 
Ok, weil ich das Handle der Hauptanwendung nicht übergeben hatte, funktionierte es nicht. Wäre IntPtr da nicht "flexibler" als IWin32Window, als Parameter-Typ?
Die Testanwendung verlief nun positiv, ich danke euch, Th69 und Ralf Jansen!

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3832
Erhaltene Danke: 781

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Sa 24.06.17 08:50 
Hattest du denn auch den Konstruktor-Code (CreateHandle(...) aus meinem Code übernommen? Dadurch brauchst du dann wohl auch kein externes Window-Handle zu übergeben:
ausblenden C#-Quelltext
1:
2:
3:
4:
CreateParams Params = new CreateParams();
Params.ExStyle = WS_EX_TOOLWINDOW;
Params.Style = WS_POPUP;
CreateHandle(Params);

Ob diese beiden Styles generell funktionieren, müßte man jedoch evaluieren (kommt wahrscheinlich darauf an, welche Messages man empfangen will).

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2054
Erhaltene Danke: 376

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Sa 24.06.17 09:26 
Nein, hatte ich nicht. Erstens, wusste ich nicht, an welches Control es gerichtet war (verstecktes Control / Form der Hauptanwendung), zweitens, was mir das erzeugte Handle bringen würde, und letzteres, ob und wo ich dieses Handle freigeben soll/kann, da ich den Finalizer / Destruktor nicht benutzen soll.

Nachtrag

Das funktioniert sehr gut. Somit brauche ich im Konstruktor nicht mehr das Handle zur Hauptanwendung.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
public class MainClass
{
    private WndClass _wndClass;
    
    public MainClass()
    {
        _wndClass = new WndClass();
    }
}

class WndClass : NativeWindow 
{
    public WndControl() 
    {
        CreateParams Params = new CreateParams();
        Params.ExStyle = 0x80;  // WS_EX_TOOLWINDOW
        Params.Style = unchecked((int)0x80000000);  // WS_POPUP ... weil der Wert viel zu groß für ".Style(int)" ist
        CreateHandle(Params);
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 537)
            if ((byte)m.WParam == 7)
                MessageBox.Show("^.^");
        base.WndProc(ref m);
    }
}

Ohne Angaben zum Style, funktioniert es ebenso.

Trotzdem muss mit DestroyHandle() das Handle freigegeben werden. Und dafür muss die Hauptklasse mit IDisposeableerweitert werden, um in der darin befindlichen Dispose() Methode, die Freigabe getätigt zu werden.
Da wäre es doch wesentlich einfacher, im Konstruktor der Hauptklasse ein Handle (IntPtr) mitzugeben.
Kommt also auf die Anforderung und den Geschmack an.

NativeWindow bildet bei der Freigabe des Handle eine Ausnahme :
"The NativeWindow class automatically will destroy the associated window and release its resources in response to a WM_DESTROY message."
Also muss man sich doch nicht darum kümmern.


Das Thema hat sich erledigt !!!

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)