Nochmal BalloonTip Message Duration - Neuer Ansatz

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 31 Antworten in diesem Thema. Der letzte Beitrag () ist von Dideldum.

    Nochmal BalloonTip Message Duration - Neuer Ansatz

    Hi Ihr,

    jetzt habe ich ewig nach einer Lösung gesucht und bin bei MS und WinUser.h fündig geworden.
    learn.microsoft.com/en-us/wind…/winauto/message-duration

    Habe in meiner NativeMethods also eingebaut:

    VB.NET-Quellcode

    1. <DllImport("user32.dll", SetLastError:=True)>
    2. Public Function SystemParametersInfo(
    3. ByVal uiAction As UInteger,
    4. ByVal uiParam As UInteger,
    5. ByRef pvParam As Integer,
    6. ByVal fWinIni As UInteger) As Boolean
    7. End Function


    und

    VB.NET-Quellcode

    1. ' Message Duration
    2. Public Const SPI_GETMESSAGEDURATION As UInteger = &H2016
    3. Public Const SPI_SETMESSAGEDURATION As UInteger = &H2017
    4. Public Const SPIF_UPDATEINIFILE As UInteger = &H1
    5. Public Const SPIF_SENDCHANGE As UInteger = &H2


    Im Proggi habe ich:

    VB.NET-Quellcode

    1. Private Function Lese_BalloonTip_MessageDuration() As Integer
    2. Dim duration As Integer = 0
    3. If SystemParametersInfo(SPI_GETMESSAGEDURATION, 0, duration, 0) Then
    4. MsgBox("Lesen: " & duration.ToString)
    5. Return duration
    6. End If
    7. Return 5
    8. End Function
    9. Private Function Schreibe_BalloonTip_MessageDuration(duration As Integer) As Boolean
    10. If SystemParametersInfo(SPI_SETMESSAGEDURATION, 0, duration, SPIF_UPDATEINIFILE Or SPIF_SENDCHANGE) Then
    11. MsgBox("Schreiben: " & duration.ToString)
    12. Return True
    13. End If
    14. Return False
    15. End Function


    Die Funktion "Lese_BalloonTip_MessageDuration()" liest nun auch brav den in der Systemsteuerung unter "Anzeigeeinstellungen für Erleichterte Bedienung" in der Combobox "Benachrichtigungen anzeigen für" eingetragenen Wert aus.
    Das ist ein Integer, der die Anzeigezeit in Sekungen speichert.
    Also mögliche Inhalte: 5, 7, 15, 30, 60, 300

    Diese Combo habe ich in dem Einstellungen-Fensters meines Proggis nachgebaut und selektiere mit obiger Funktion den korrekten Eintrag.

    Wähle ich aber nun in meiner Combobox einen anderen Wert aus und speichere dessen Wert als Integer (in entsprechenden Sekunden) mit der Funktion "Schreibe_BalloonTip_MessageDuration", übernimmt das System diesen Wert dennoch nicht.
    Obwohl die Test-Msgbox die "Schreiben: %Wert%" anzeigt.

    Nun bin ich total am Ende mit meinem Latein.
    War happy, dass ich eine MS-unterstützte Lösung gefunden habe - und nun will die nüscht so als ick wohl will. ;(

    Weiss vielleicht einer von Euch, woran das liegen könnte?
    Ich denke, mit meinem Script ist alles OK - oder etwa doch nicht?

    Wünsche ein schönes Rest-Weekend @All :)
    Habs sofort gefunden. Das Problem ist ByRef wenn du schreibst. Nachdem schreiben lohnt es sich auch nochmal zu lesen, ich sah sofort eine viel viel zu hohe Zahl beim auslesen nach dem schreiben. Das dir in der MessageBox der richtige Wert gezeigt wurde heist nichts, denn die Variable hat ja den richtigen Wert, wie gesagt, du hast danach nicht nochmal ausgelesen. Und diese viel zu hohe Zahl ist eine Speicheraddresse, wegen des ByRef wird diese geschrieben, nicht der Wert der Variable.

    Das musst du 2 mal die Funktion definieren, einmal zum auslesen mit ByRef und wenn du schreiben willst mit ByVal.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Imports System.Runtime.InteropServices
    3. Public Class Form1
    4. <DllImport("user32.dll", SetLastError:=True, EntryPoint:="SystemParametersInfo")>
    5. Private Shared Function SystemParametersInfoRead(uiAction As UInteger, uiParam As UInteger, ByRef pvParam As UInteger, fWinIni As UInteger) As Boolean
    6. End Function
    7. <DllImport("user32.dll", SetLastError:=True, EntryPoint:="SystemParametersInfo")>
    8. Private Shared Function SystemParametersInfoWrite(uiAction As UInteger, uiParam As UInteger, pvParam As UInteger, fWinIni As UInteger) As Boolean
    9. End Function
    10. Public Const SPI_GETMESSAGEDURATION As UInteger = &H2016
    11. Public Const SPI_SETMESSAGEDURATION As UInteger = &H2017
    12. Public Const SPIF_UPDATEINIFILE As UInteger = &H1
    13. Public Const SPIF_SENDCHANGE As UInteger = &H2
    14. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    15. ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList
    16. ComboBox1.Items.AddRange({5, 7, 15, 30, 60, 300})
    17. ComboBox1.SelectedIndex = 0
    18. End Sub
    19. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    20. Dim duration As UInteger = 0
    21. If SystemParametersInfoRead(SPI_GETMESSAGEDURATION, 0, duration, 0) Then
    22. MessageBox.Show("Gelesen: " & duration.ToString)
    23. duration = CType(ComboBox1.SelectedItem, UInteger)
    24. If SystemParametersInfoWrite(SPI_SETMESSAGEDURATION, 0, duration, SPIF_UPDATEINIFILE Or SPIF_SENDCHANGE) Then
    25. MessageBox.Show("Geschrieben: " & duration.ToString)
    26. If SystemParametersInfoRead(SPI_GETMESSAGEDURATION, 0, duration, 0) Then
    27. MessageBox.Show("Gelesen: " & duration.ToString)
    28. Else
    29. Throw New Win32Exception(Marshal.GetLastWin32Error())
    30. End If
    31. Else
    32. Throw New Win32Exception(Marshal.GetLastWin32Error())
    33. End If
    34. Else
    35. Throw New Win32Exception(Marshal.GetLastWin32Error())
    36. End If
    37. End Sub
    38. End Class

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „DTF“ ()

    Servus @DTF

    Wow!!! Danke Dir recht sakrisch :) :thumbsup:
    Mir ist das mit der viel zu hohen Zahl zwar auch aufgefallen, aber soweit reichen meine Kenntnisse noch nicht, diese korrekt zu interpretieren.

    Nachdem ich in Deinem Lesen-Aufruf den UInt in Integer umgebaut hatte:

    VB.NET-Quellcode

    1. <DllImport("user32.dll", SetLastError:=True, EntryPoint:="SystemParametersInfo")>
    2. Public Function SystemParametersInfoRead(uiAction As UInteger, uiParam As UInteger, ByRef pvParam As Integer, fWinIni As UInteger) As Boolean
    3. End Function

    hat auch das Auslesen wieder funktioniert. Bei UInt bekam ich immer 0 zurück.

    Aber jetzt mag mein Proggi endlich spuren.

    Na ja, bis auf ein paar andere kleine Problemchen.

    Immerhin klappt so das Auslesen und Schreiben der Balloon-Message-Duration endlich.
    Da mein Proggi viel Balloon-Tips verwendet, lese ich bei vor dem Aufruf einer Balloon-Message den ursprünglichen Duration-Wert aus, setze die Duration auf die vom User gewünschte Anzeigezeit (z.T. Infos mit den max. Zeichen) und im Ballon_Close wird die Duration dann wieder auf den ursprünglichen Wert gesetzt.

    Beste Grüsse

    P.S. Falls mal jemand diese Funktion braucht:

    Achtung: Zulässige Werte für das Schreiben der MessageDuration sind nur 5, 7, 15, 30, 60 und 300

    VB.NET-Quellcode

    1. <DllImport("user32.dll", SetLastError:=True, EntryPoint:="SystemParametersInfo")>
    2. Public Function SystemParametersInfoRead(uiAction As UInteger, uiParam As UInteger, ByRef pvParam As UInteger, fWinIni As UInteger) As Boolean
    3. End Function
    4. <DllImport("user32.dll", SetLastError:=True, EntryPoint:="SystemParametersInfo")>
    5. Public Function SystemParametersInfoWrite(uiAction As UInteger, uiParam As UInteger, pvParam As UInteger, fWinIni As UInteger) As Boolean
    6. End Function
    7. ' Message Duration
    8. Public Const SPI_GETMESSAGEDURATION As UInteger = &H2016
    9. Public Const SPI_SETMESSAGEDURATION As UInteger = &H2017
    10. Public Const SPIF_UPDATEINIFILE As UInteger = &H1
    11. Public Const SPIF_SENDCHANGE As UInteger = &H2
    12. Private Function Lese_BalloonTip_MessageDuration() As Integer
    13. Dim duration As UInteger = 0
    14. If SystemParametersInfoRead(SPI_GETMESSAGEDURATION, 0, duration, 0) Then
    15. Return CType(duration, Integer)
    16. End If
    17. Return 5
    18. End Function
    19. Private Function Schreibe_BalloonTip_MessageDuration(duration As Integer) As Boolean
    20. return SystemParametersInfoWrite(SPI_SETMESSAGEDURATION, 0, CType(duration, UInteger), SPIF_UPDATEINIFILE Or SPIF_SENDCHANGE)
    21. End Function


    Oder anstelle der zwei Funktionen eine Property:

    VB.NET-Quellcode

    1. Public Property System_Message_Duration() As Integer
    2. Get
    3. Dim duration As UInteger = 0
    4. If SystemParametersInfoRead(SPI_GETMESSAGEDURATION, 0, duration, 0) Then
    5. Return CType(duration, Integer)
    6. End If
    7. Return 5
    8. End Get
    9. Set(value As Integer)
    10. SystemParametersInfoWrite(SPI_SETMESSAGEDURATION, 0, CType(value, UInteger), SPIF_UPDATEINIFILE Or SPIF_SENDCHANGE)
    11. End Set
    12. End Property


    So klapps mit dem Nachbarn ^^

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Dideldum“ ()

    Wenn das bei dir mit Uint nicht ging, hast du irgendwo einen Fehler drin gehabt.

    learn.microsoft.com/de-de/wind…ser-systemparametersinfoa

    C-Quellcode

    1. BOOL SystemParametersInfoA(
    2. [in] UINT uiAction,
    3. [in] UINT uiParam,
    4. [in, out] PVOID pvParam,
    5. [in] UINT fWinIni
    6. );


    PVOID Datatype:
    learn.microsoft.com/de-de/wind…inprog/windows-data-types
    PVOID
    Ein Zeiger auf einen beliebigen Typ.
    Dieser Typ wird in WinNT.h wie folgt deklariert:
    typedef void *PVOID;


    Ein Zeiger, also ein Pointer kann nicht negativ sein, Pointer zeigen auf Speicheradressen bzw. sind welche. Negative Speicheradressen gibt es ja nicht.
    EDIT: JA negative Adressen gibt es nicht, wir geben ja selbst keine an, der Wert wird mit der Breite des Typs dort geschrieben.


    Dideldum schrieb:

    Mir ist das mit der viel zu hohen Zahl zwar auch aufgefallen, aber soweit reichen meine Kenntnisse noch nicht, diese korrekt zu interpretieren.


    Das wäre eine Meldung im ersten Post Wert gewesen, mir hätte das wegen dem ByRef zwar auch so sofort auffallen müssen, aber wie das leben manchmal so läuft...



    PS:
    @Dideldum
    Vergiss das wieder was ich mit den int/uint erwähnt hab, nicht alles, es ist ja ein Zeiger auf einen beliebigen Typ, das heist NET managed das schon und schreibt die Bytes passend. Den Typ der angegeben ist, dessen Breite wird verwendet. Von daher war die Erwähnung von negativen Speicheradressen unpassend. Heute bin ich mal wieder ein wenig Banane.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „DTF“ ()

    Nochmal danke @DTF :)
    ich habe keinen anderen Fehler gefunden.
    Aber ja, da hast ganz recht, dass UInt das eigentlich korrekte Format dafür ist.
    Nachdem meine Integers aus den Combo.selectedIndex generiert werden, kann mit Integer aber auch nichts schief gehen, denke ich. ;)
    Da hat der User eh keinen anderen Einfluss darauf, als dass er in der Combo einen der sechs Werte auswählen kann.

    Aber ich versuche es nochmal mit UInt ^^
    Jetzt wart du schneller, hatte noch editiert. Bin Banane heute, wie ich korrigierte, der Wert wird in die Adresse der Variable geschrieben. Wir geben ja selbst keine Adresse an. Von daher egal ob int/uint.

    PS
    @Dideldum
    Also Byte würde auch gehen, aber da reicht die Range nicht(300 passt nicht in 1 Byte), Short,Ushort,Long,Ulong etc... geht auch.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DTF“ ()

    @DTF
    Hihi,
    Du warst aber keiner meiner Profs in den Vorlesungen anno 1985?
    "Immer schön das kleinstmögliche Datenformat wählen - Speicherplatz ist teuer. Sonst gibt's Punkt abgezogen!" :P
    Na ja, damals war das ja auch so - mit Rechnern, die gerade mal einen 286er mit 8MHz-Takt, 128KB RAM und eine 20MB HDD hatten, wenn ich mich recht erinnere.
    Manch einer sagt zwar ich sei ein verrückter Raketenwissenschaftler :D , aber ich hab nicht mal'n Doktor Titel ;(

    Aber auch heute muss ich manchmal noch Bytes zählen. Kommt schon mal vor das ich meinen Lieblings-IC(ATmega328) bis ans Limit nutze.

    PS:
    Deine Funktion kann kürzer:

    VB.NET-Quellcode

    1. Private Function Schreibe_BalloonTip_MessageDuration(duration As Integer) As Boolean
    2. Return SystemParametersInfoWrite(SPI_SETMESSAGEDURATION, 0, CType(duration, UInteger), SPIF_UPDATEINIFILE Or SPIF_SENDCHANGE)
    3. End Function

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DTF“ ()

    Danke Dir @Raketenwissenschaftler, äh @DTF :D
    Habs oben korrigiert - wobei ich doch bei Integer bleibe - da spart sich Otto-Normal-Coder die erforderliche Umwandlung Int->UInt
    Ich vermute mal leise, dass wohl viele bei Ganzzahlen immer das Integer-Format nutzen. ;)
    Und der Funktion tut es ja auch nur weh, wenn mal jemand irrigerweise eine negative Ganzzahl reinschmeisst.

    EDIT: Ne, bin ja brav... :P
    Jetzt ist obiges Script mit UInt
    Stimmt das so, wie ich es umgebaut habe?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Dideldum“ ()

    Du kannst auch negative Zahlen schreiben, das ist kein Problem. Nur eine negative Adresse, das würde dir die Ohren fliegen, das hatte ich vorhin verdreht. Die Adresse geben wir ja nicht selbst an, bzw. legen die nicht selbst fest, beim lesen wird halt in Bitbreite des angegebenen Datentyps in den Speicher geschrieben.

    Beispiel :
    Dim x as integer = 0 // ist jetzt einfach so mal an adresse 0xABCDEF des prozesses.
    Durch das Byref wird die Adresse der Variable verwendet, dorthin schreibt windows dann den Wert in Bitbreite des Parameter-Datentyps, so hast du den Wert dann Küchenfertig in der Variable.

    Dideldum schrieb:

    Stimmt das so, wie ich es umgebaut habe?

    Schreibe_BalloonTip_MessageDuration(duration As Integer) As Boolean
    Datentyp des parameters zu Uint, dann das CType(duration, UInteger) korrigieren, also das CType weg. Wobei egal, willst ja die Parameter als Integer haben aus komfort Gründen. Die andere Funktion gibt ja auch Integer raus. Aber kannste machen wie dir beliebt.

    Fehler hab ich keinen gesehen, sollte funzen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „DTF“ ()

    Hmm, klingt für mich etwas komisch erst die Duration auszulesen, einen neuen Wert für die Duration zu schreiben um dann einen BalloonTip anzuzeigen um danach den alten Wert zurück zuschreiben. Beschreib mal genauer was Du vor hast denn wenn ich mich recht erinnere sollte die ToolTip-Klasse doch entsprechende Properties haben um die Duration/Delay zu setzen. Im Prinzip wird per API SendMessage an das hWnd des ToolTip-Fensters mit Flag TTS_BALLOON die Message TTM_SETDELAYTIME mit TTDT_AUTOPOP und entsprechenden Wert in lParam die Anzeigedauer festgelegt (max UShort.MaxValue in Millisekunden). -> learn.microsoft.com/de-de/wind…controls/ttm-setdelaytime
    Mfg -Franky-
    Hi @-Franky-,

    ich möchte in meinem Programm generell keine Systemeinstellungen ändern, wie eben auch nicht die Systemeinstellungen für die MessageDuration.
    Daher kann der User in meinem Programm z.B. auch Dateiendungen zu Anwendungen zuordnen, ohne die im System bestehenden Zuweisungen zu ändern. Also z.B. *.txt mit einem frei im ICE definierbaren Editor öffnen oder *.jpg mit einem auswählbaren Bild-Programm, ohne, dass die System-Dateizuordnungen davon berührt werden.

    Und so lese ich also nach der Installation von ICE beim ersten Start des Programms die System-MessageDuration in eine My.Settings Variable ein - sozusagen als Initial-Einstellung für die User-MessgeDuration, welche nur im ICE wirkt.
    Dann kann der User diese Variable jederzeit in den Programm-Einstellungen frei ändern.

    Da meine Ballool.text-Messages teilweise recht gross sind, braucht der User oft länger zum Lesen der Balloons, als die im System eingestellte BalloonDuration mtspielt.

    Daher kann der User also in den Einstellungen meines Programs u.a. auch die User-MessageDuration verändern, welche nur für die programmeigenen Balloons gilt .
    Bei 15sek ist es teilweise schon problematisch, die Texte zu lesen und zu verstehen.
    Bei den 5sek., welche Win per Default als System-MessageDuration vorgibt praktich unmöglich.

    Mein Proggi liest dann vor dem Anzeigen eines Balloons die System-MessageDuration aus und sichert diese temporär in einer Variablen.
    Dann liest mein Proggi die o.g. User-MessageDuration (die My.Settings-Variable) aus, und überschreibt damit temporär die System-MessageDuration des Systems.
    Nun wird der Balloon mit dieser Duration geöffnet.
    Nach Ablauf der User-MessageDuration schreibe ich In dem Ereignis Balloon_Close den zuvor temporät gesicherten System-MessageDuration-Wert wieder in die System-MessageDuration.
    Damit ist alles, wie es war und mein Balloon wurde User-MessageDuration lang angezeigt.
    So stelle ich sicher, dass die Usser-MessageDuration auch wirklich nur in meinem Programm zum Tragen kommt und ansonsten immer die vom User in der Systemsteuerung eingestellte System-MessageDuration wirkt.

    In der ToolTip-Klasse habe ich nichts gefunden, womit ich die Balloon-MessageDuration hätte einstellen können.
    Daher sah ich mich zu diesem Umweg genötigt.

    @DTF
    Dank Dir machen die Funktionen jetzt, was ich schon seit Wochen probiere. :)
    Da das System eh nur diese sechs Werte annimmt und der Benutzer nur die Combo.selectedIndex wählen kann, sind auch nur diese sechs Werte schreibbar.
    Da sollte also nichts anbrennen. ;)

    P.S. Man könnte dese beiden Funktionen natürlich auch in eine hübsche Property packen.
    Das würde noch schöner aussehen. ^^
    EDIT: Habe es oben ergänzt. ;)

    @-Franky-
    ich habe folgende Antwort vom ChatGPT:
    ---------------

    Du

    Das Prohblem ist, dass .net die Angabe einer Anzeigedauer in:
    icn_TaskleistenSymbol.ShowBalloonTip(My.Settings.Fragen_Balloontip_Anzeigedauer)
    nicht mehr unterstützt, sondern stets die in der Systemsteuerung eingestellte Anzeigedauer verwendet.

    ChatGPT

    Wenn .NET die Angabe einer individuellen Anzeigedauer für NotifyIcon Balloontips nicht unterstützt und stattdessen die in der Systemsteuerung festgelegte Anzeigedauer verwendet, haben Sie tatsächlich begrenzte Möglichkeiten, dies programmatisch zu umgehen, da diese Verhaltensweise tief in der Implementierung von Windows selbst verankert ist.

    Eine direkte Anwendung von TTM_SETDELAYTIME und TTM_GETDELAYTIME auf ein NotifyIcon-Objekt ist, wie bereits erwähnt, nicht möglich, da diese Nachrichten für die Verwendung mit ToolTip-Steuerelementen im Kontext der Windows API gedacht sind und NotifyIcon-Balloontips nicht auf die gleiche Weise kontrolliert werden.

    ----------

    Also verstehe ich es so, als ob meine Lösung die einzige ist.
    Bilder
    • MessageDuration.jpg

      143,73 kB, 1.016×616, 46 mal angesehen
    • Pfade.jpg

      150,55 kB, 1.016×616, 53 mal angesehen

    Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „Dideldum“ ()

    Dideldum schrieb:

    Also verstehe ich es so, als ob meine Lösung die einzige ist.


    Na wo ist deine Fantasie? Du kannst durchaus selbst ein Popup basteln. Das ist garnicht so ungewöhnlich. Da hast du dann die volle Kontrolle ohne temporär was beim System ändern zu müssen. Ich finde es immer wieder komisch wenn ein Programmierer sagt, das ist die einzige Lösung, nur weil diese nur diese eine sehen. Es gibt fast immer andere Wege, um zum Ziel zu kommen, man muss sich nur was einfallen lassen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    @Dideldum Wenn Du in Deinem Code UInteger durch Integer ersetzt, funktioniert das alles genau so.

    Dideldum schrieb:

    Zulässige Werte für das Schreiben der MessageDuration sind nur 5, 7, 15, 30, 60 und 300
    Das kann ich nicht bestätigen.
    Werte von 21 und 42 werden bei mir anstandslos akzeptiert und realisiert.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich verstehe ChatGPT so das die in .NET enthaltene ToolTip-Klasse ein verändern der Duration nicht mehr unterstützt. Wenn dem so ist, was man ja Nachprüfen könnte, dann wäre das noch ein negativ Beispiel aus dem .NET Universum wo ich dann denke: Warum MS?

    What ever. Du kannst Dir auch per API CreateWindowsEx selbst ein ToolTip-Fenster erstellen. learn.microsoft.com/en-us/wind…controls/tooltip-controls Hier sollte, hab das seit Ewigkeiten nicht mehr genutzt, das einstellen der Duration/Delay wie im anderen Post erwähnt, funktionieren. Bei UShort.MaxValue wären das 65,535 Sekunden die maximal einstellbar wären.
    Mfg -Franky-

    RodFromGermany schrieb:

    Das kann ich nicht bestätigen.


    Kann sein das es funktioniert, aber Windows zeigt dann in der Systemsteurung was falsches an. Die ComboBox dort, hat nur die oben erwähnten Werte als Items. Deshalb würde ich auch nur die Werte nutzen, die MS dafür vorgesehen hat. Hatte 200 via Code gesetzt, Windows zeigte aber 5 minuten an, was mehr als eine Minute differenz ist. Auch bei 100 wird mir 5 Minuten angezeigt, wird also nichtmal der naheste Wert gezeigt.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DTF“ ()

    DTF schrieb:

    wird also nichtmal der naheste Wert gezeigt.
    Ich habe mich nicht an die ComboBox gehalten, sondern geschossene Werte verwendet und beim Aufpoppen eine StopWatch gestartet und sekündlich ausgelesen.
    Diese Funktionalität ist wohl "besser" als ihre Beschreibung.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ui, Ihr seid ja Super! Danke Euch für Eure Hilfe und Tips :)

    @-Franky-
    Nu, dass die:

    VB.NET-Quellcode

    1. icn_TaskleistenSymbol.ShowBalloonTip(My.Settings.Fragen_Balloontip_Anzeigedauer)

    keine Parameter mehr verarbeitet, sondern ausschliesslich die Windows-Einstellungen, musste ich dem doofen ChatGPT mühseelig erklären.
    Das war vor Wochen ja mein erster Versuch und nach langer Recherche im Web habe ich dies als Antwort gefunden, warum meine Params so gnadenlos ignoriert werden.
    Das doofe ChatGPT hat aber auch immer wieder diese Lösung vorgeschlagen - der hat zugegeben, dass er meine Aussagen nicht mal in seine Datenbank zur Selbstkorrektur und für spätere Fragen von Dritten übernimmt.
    Daraufhin habe ich mich also auf die Suche nach einem Direktzugriff auf die Registry-Einträge gemacht.
    Auch die in der Registry stehenden BalloonDurations, welche früher manipulierbar waren, sind heute nur noch wegen Abwärtskompatibilität als Dummys in der Registry und werden nicht mehr bedient/ausgewertet.
    Also wieder ein Griff in den keramischen Haushaltsgegenstand.
    Dann habe ich elend lang weitergesucht und bin schliesslich endlich auf die WinUser.h gestossen, welche sich vielversprechend gelesen haben.
    Und dank @DTF läuft die Sache nun endlich wie gewünscht.

    @DTF
    Ja sicher - das wäre eine Lösung, ein eigenes Popup zu bauen.
    Habe ja auch eigene Info-, Eingaben- und Wartenfenster.
    Habe in meiner Verzweiflung auch schon daran gedacht. Nur hätte ich dafür recherchieren müssen, woher ich die Farbe dieses Balloons und dessen identisches Hochschieben herbekomme.
    Da erschien mir einfacher, doch gleich das Original zu verwenden - sofern möglich.
    Genauso wie bei den SHFileOperations. Ich hatte mir aufwendig eine Kopierroutine gebaut und war mehr schlecht als recht am Infofenster für diese zu bauen, als ich hier irgendwo von der möglichen Nutzung der SHFileOperation mit seiner hübschen Diagramm-Anzeige stiess. Also meine selbstgeschnitzte Routine in die Tonne getreten und die OS-Routine verwendet.
    M.E. ist immer am besten, wenn möglich die OS-Routinen zu verwenden, damit die User einen Wiedererkennungswert haben.

    @RodFromGermany
    Jo, hatte Anfangs auch mit Integers gearbeitet, und es funzte prima.
    Aber @DTF hat schon recht - wenn nur positive Werte gewünscht sind, ist UInt das bessere Format. Dann weiss derjenige, der den Code vielleicht mal nutzt, was erwartet wird.
    Und es sind ja auch ein paar Bytes weniger im Datenspeicher - das würde meinen alten Prof freuen :D

    @RodFromGermany und @DTF
    Hihi, diesem Trugschluss bin ich auch aufgesessen, dass jeder Int-Wert akzeptiert wird und habe eine NumericUpDown in meine Programm-Settings reingebastelt. Eingabe, Speicherung, Auslesen - funktioniert prima mit allen Zahlen. Nur der Test am lebenden Objekt hat dann bewiesen, dass in der Systemsteuerung dann keine 1:1 Ausgabe der eigenen Werten erfolgt. Wie auch - ist ja nicht möglich bzw. nur mit grösserem Aufwand, welchen MS sich aber verkniffen hat. Um meine Funktion universal zu bauen und ggf. auch später verwenden zu können habe ich also auch nur diese sechs Werte verwendet. Also wurde aus der NuD eine Combo. Das Einzige, was in den vorgegebenen Werten m.E. fehlt, wäre "2 Minuten" als 7. Eintrag.
    EDIT: Das einzige Problem, welche ich bei der externen Bearbeitung der System-Settings sehe, ist, wenn jemand mein Proggi exakt dann abschiesst, solange die Balloon-Message angezeigt wird oder in dem Moment seinen Rechner an die Wand fährt. Dann bleiben meine Werte in der Systemsteuerung. Und in diesem Fall sollten dann auch korrekte Werte in der Systemsteuerung angezeigt werden, die dem gespeicherten Wert entsprechen.
    Ich setze daher auch nach jedem Programmstart meines Programms den Wert in der Systemsteuerung auf den ursprünglich ausgelesenen Wert, falls es wirklich mal passieren sollte, dass jemand diesen Fehler macht.
    So stimmt der Systemsteuerungs-Einrag spätestens nach dem nächsten ICE-Start wieder mit der Original-System_BalloonDuration überein.

    Danke Euch allen - Wünsche Euch einen supertollen Sonntach :)

    P.S. werde hernach einen neuen Thread anlegen...
    Bin zu dumm, um die gespeicherte Topline einer RTF so aufzurufen, dass das Dokument nach dem Öffnen exakt wieder an die Stelle scrollt, an welcher es beim speichern war.
    Alles, was ich hier und bei ChatGPT dazu gefunden habe, klappt irgendwie nicht.
    Sei es, dass nicht an die korrekte Stelle gescrollt wird oder dass trotz "RTFBox.visible = false - Dokument in RTFBox laden - Code zum Scrollen - RTFBox.visible = true" sichtbar gescrollt wird.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Dideldum“ ()

    @Dideldum Hmm, die NotifyIcon Klasse ist nicht das gleiche wie die ToolTip Klasse. Ok, im weitesten Sinne dann aber doch da beide auf der TOOLTIPS_CLASS basieren. Deswegen bin ich ein wenig verwirrt welche Klasse Du genau meinst.
    Mfg -Franky-

    Dideldum schrieb:

    wenn nur positive Werte gewünscht sind, ist UInt das bessere Format. Dann weiss derjenige, der den Code vielleicht mal nutzt, was erwartet wird.


    Dann wäre es IMO richtig eine Enumeration zu verwenden. Diesen Typ dann auch in der Api-Funktionsdeklaration zu nutzen. Hab den Code von mir um wenige Zeilen erweitert, so ist dann sichergestellt, das User deines Codes keine ungewollten Werte nutzen
    können.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.ComponentModel
    3. Imports System.Runtime.InteropServices
    4. Public Class Form1
    5. <DllImport("user32.dll", SetLastError:=True, EntryPoint:="SystemParametersInfo")>
    6. Private Shared Function SystemParametersInfoRead(uiAction As UInteger, uiParam As UInteger, ByRef pvParam As BalloonDuration, fWinIni As UInteger) As Boolean
    7. End Function
    8. <DllImport("user32.dll", SetLastError:=True, EntryPoint:="SystemParametersInfo")>
    9. Private Shared Function SystemParametersInfoWrite(uiAction As UInteger, uiParam As UInteger, pvParam As BalloonDuration, fWinIni As UInteger) As Boolean
    10. End Function
    11. Public Const SPI_GETMESSAGEDURATION As UInteger = &H2016
    12. Public Const SPI_SETMESSAGEDURATION As UInteger = &H2017
    13. Public Const SPIF_UPDATEINIFILE As UInteger = &H1
    14. Public Const SPIF_SENDCHANGE As UInteger = &H2
    15. Private Enum BalloonDuration As UInteger
    16. FiveSeconds = 5
    17. SevenSeconds = 7
    18. FifteenSeconds = 15
    19. ThirtySeconds = 30
    20. OneMinute = 60
    21. FiveMinutes = 300
    22. End Enum
    23. Private Class ComboBoxBalloonDurationItem
    24. Public Sub New()
    25. End Sub
    26. Public Sub New(duration As BalloonDuration)
    27. Me.Duration = duration
    28. End Sub
    29. Private _duration As BalloonDuration = BalloonDuration.FiveSeconds
    30. Public Property Duration As BalloonDuration
    31. Get
    32. Return _duration
    33. End Get
    34. Set(value As BalloonDuration)
    35. _duration = value
    36. End Set
    37. End Property
    38. Public ReadOnly Property DurationValue As UInteger
    39. Get
    40. Return CUInt(_duration)
    41. End Get
    42. End Property
    43. End Class
    44. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    45. Dim items As New List(Of ComboBoxBalloonDurationItem)
    46. For Each item As BalloonDuration In [Enum].GetValues(GetType(BalloonDuration))
    47. items.Add(New ComboBoxBalloonDurationItem(item))
    48. Next
    49. ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList
    50. ComboBox1.DisplayMember = "DurationValue"
    51. ComboBox1.DataSource = items
    52. ComboBox1.SelectedIndex = 0
    53. End Sub
    54. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    55. Dim item As ComboBoxBalloonDurationItem = New ComboBoxBalloonDurationItem()
    56. If SystemParametersInfoRead(SPI_GETMESSAGEDURATION, 0, item.Duration, 0) Then
    57. If BalloonDuration.IsDefined(GetType(BalloonDuration), item.DurationValue) Then
    58. MessageBox.Show("Gelesen: " & item.DurationValue.ToString())
    59. Else
    60. MessageBox.Show("Illegalen Wert gelesen: " & item.ToString())
    61. End If
    62. item = DirectCast(ComboBox1.SelectedItem, ComboBoxBalloonDurationItem)
    63. If SystemParametersInfoWrite(SPI_SETMESSAGEDURATION, 0, item.Duration, SPIF_UPDATEINIFILE Or SPIF_SENDCHANGE) Then
    64. MessageBox.Show("Geschrieben: " & item.DurationValue.ToString())
    65. If SystemParametersInfoRead(SPI_GETMESSAGEDURATION, 0, item.Duration, 0) Then
    66. If BalloonDuration.IsDefined(GetType(BalloonDuration), item.DurationValue) Then
    67. MessageBox.Show("Gelesen: " & item.DurationValue.ToString())
    68. Else
    69. MessageBox.Show("Illegalen Wert gelesen: " & item.ToString())
    70. End If
    71. Else
    72. Throw New Win32Exception(Marshal.GetLastWin32Error())
    73. End If
    74. Else
    75. Throw New Win32Exception(Marshal.GetLastWin32Error())
    76. End If
    77. Else
    78. Throw New Win32Exception(Marshal.GetLastWin32Error())
    79. End If
    80. End Sub
    81. End Class


    Dideldum schrieb:

    wenn jemand mein Proggi exakt dann abschiesst, solange die Balloon-Message angezeigt wird oder in dem Moment seinen Rechner an die Wand fährt


    Dann wäre es die bessere Idee das in einer Datei zwischen zu parken. Wenn ein User auch wenn es unwahrscheinlich ist, nach so einem nicht sauberen Beenden den Wert ändert, trägst du was ein, was der User net wollte. Sollte dann beim starten so ein Eintrag in deiner Datei sein, aber der Wert im System anders sein, frage den User was er denn will.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D