​Sammlung: Nim Snippets / Procedures

  • Ich möchte in diesem Thread eine Sammlung erstellen, von all den nützlichen Dingen, die wir so erstellen (werden). ;)

    Bitte jeden Post mit Tags versehen, das vereinfacht dann auch die Suche. Für jede Prozedur einen eigenen Post erstellen. Bsp. kann - muss aber nicht dabei sein, wenn die Handhabung eindeutig ist.

    Diskussionen und Verbesserungsvorschläge etc. können wir gern hier mit führen. Wenn ein Thema dann abgeschlossen ist, würde ich aber die Diskussion auslagern (oder löschen?).


    INHALT:


    D


    E

    F

    I

    K

    P

    S

    T

  • Bsp.:

    Code
    let oWndID = GetIDByWindow(hWnd)
    echo "Process-ID = ", oWndID.pid
    echo "Thread-ID = ", oWndID.tid
    # PID only:
    echo "PID = ", GetIDByWindow(hWnd).pid


    Tags: <Process ID>, <PID>, <Thread ID>

  • EnumWindows (das Gegenstück zu AutoIt WinList mit mehr Inhalt)

    Es werden ermittelt:

    • Fenster Handle
    • ClassName
    • Fenster Titel
    • Process ID
    • Thread ID


    EDIT:

    Ich habe mal noch gefiltert:

    - Parent muss "0" sein

    - Fenster muss Titel haben

    Das schmilzt die Sache deutlich zusammen.

    Code

    Weniger anzeigen


    Tags: <Enum Windows>, <Fenster Handle>, <ClassName>, <Fenster Titel>, <Process ID>, <Thread ID>

  • Ermitteln des Prozessnamens (Pfades) anhand der Process-ID:


    Tags: <Process>, <Process Name>, <Process Path>, <PID>

  • Wenn man ein Programm mit Gui erstellt und man einen "eigenen" Font benutzen will, so müsste man ja den Font nicht nur mitliefern, sonder auch noch installieren.

    Irgendwann stapeln sich bei den Anwendern dann die installierten Fonts. Das ist aber gar nicht notwendig, denn man kann unter Windows einen Font auch temporär ins System einbinden.

    Er wird dann nur von dem einen Programm benutzt und nach Programmende automatisch wieder vom System entfernt.

    Hier mal ein Beispiel dafür:

    Der Font "TeXGyreCursor" befindet sich im ZIP-Archiv (Anhang).

  • Ich habe mich jetzt intensiv mit der "winmm.dll" beschäftigt. Die Sound-UDF von AutoIt basiert ja auf dieser dll und damit kann man problemlos MP3s abspielen.

    Also muss das ja auch unter Nim funktionieren, habe ich mir gedacht und nachdem ich jetzt den halben Tag damit verbracht habe, kann ich eine Erfolgsmeldung abgeben.

    Hier nun der kommentierte Programmcode zum abspielen von MP3s (ganz ohne BASS.dll):

  • Analog zur AutoIt-UDF habe ich mal die wichtigsten Sachen in Prozeduren erstellt. Ich denke, so ist das übersichtlicher.

    Mir sind zwei Einschränkungen aufgefallen:

    - MP3s mit VBR-Kodierung funktionieren nicht!

    - Bei WAV-Dateien funktioniert das aendern der Lautstaerke nicht!


    Im ZIP-Archiv (Anhang) befindet sich der obige Code zum herunterladen.

  • Nim beherrscht ja auch die Objekt-Orientierte-Programmierung (OOP) und eigentlich gefällt mir diese Variante sogar noch besser.

    Hier also mal als OOP-Version:

    Edit: Noch ein paar Korrekturen vorgenommen.

    - Wenn beim öffnen einer Datei, noch eine andere Datei geöffnet war, wird diese erstmal geschlossen.

    - Die Laufzeit wird jetzt nur einmalig beim öffnen ausgelesen und objektintern gespeichert. "length" ist nur noch eine Getter-Methode.


    Im ZIP-Archiv (Anhang) befindet sich der obige Code zum herunterladen.

  • Ich habe mal noch gefiltert:

    - Parent muss "0" sein

    - Fenster muss Titel haben

    Hier eine Version, bei der ein Filter für den Titel/ClassName angeben werden kann... und bei jedem Aufruf wird sEnumWnd zurückgesetzt, damit sich die gefundenen Fenster nicht aufsummieren:



    --------------------------------------------------------------------------------------------------------------------------------
    HWND : 0000000000020CD6 PID : 668 TID : 14828 Window : 633| 876
    TITLE : TmainFrm
    CLASSNAME : HFS ~ HTTP File Server 2.3m Build 300
    --------------------------------------------------------------------------------------------------------------------------------

    Hier ist mir übrigens aufgefallen, dass ich TITLE und CLASSNAME bei der Ausgabe vertauscht hatte... habe es korrigiert.

  • Zum kopieren von (Unicode-)Text in die Windows-Zwischenablage kann man diese Prozedur verwenden:


    Edit: Das freigeben des Speichers erfolgt jetzt nur, falls SetClipboardData fehlschlägt, ansonsten übernimmt das das System:

    Zitat


    If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. The application may not write to or free the data once ownership has been transferred to the system

    Edit 18.07.2020:

    - Ich habe das Ganze mal als Modul ausgebaut. Es gibt jetzt zwei Prozeduren:

    "ClipPut" zum kopieren von Text in die Zwischenablage und

    "ClipGet" zum holen von Text aus der Zwischenablage

    Und das Beispiel:

    Code
    import Clipboard
    # Die letzten beiden Zeichen sind Unicode-Zeichen:
    # "Ohm U+2126" und "doppelte Achtelnote U+266B"
    # zum testen der Unicode-Faehigkeit.
    let sText = "ÄÖÜäöüß^° - who`´s loving you Ω♫"
    echo "ClipPut: ", ClipPut(sText)
    echo "ClipGet: ", ClipGet()
  • Und nochmals zum Enumerieren der Fenster. In dieser Version kann man class/title wie folgt auflisten:

    Parameter kind

    • "l" (Literal, Standard) Klasse/Titel muss identisch mit übergebenem Text sein
    • "p" (Partial) Klasse/Titel enthält übergebenen Text, Groß-/Kleinschreibung wird ignoriert
    • "r" (Regex) Klasse/Titel wird mit dem übergebenen Pattern gefiltert, Flag reIgnoreCase ist gesetzt
  • Angeregt durch einen Beitrag von Oscar habe ich eine Art AdlibRegister erstellt. Ist allerdings an ein Fenster gebunden, da das Timer-Event über das Fenster registriert wird.

    Funktionen:

    • TimedProcRegister - Registriert eine (parameterlose) Funktion zum Intervallaufruf

    • TimedProcUnRegister - Löscht die Funktion aus der Aufrufverwaltung

    • TimedProcPause - Pausiert den Aufruf einer zuvor registrierten Funktion

    • TimedProcResume - Setzt die Ausführung einer zuvor pausierten Funktion fort

    • TimedProcGet - Gibt den Index für das gespeicherte Objekt in der Aufrufverwaltung zurück

    • TimedProcChangeTime - Ändert das Zeitintervall des Aufrufs


    EDIT:

    Alle Prozeduren (ausser ..Register) können jetzt wahlweise über den Prozedurnamen oder die Timer-ID aufgerufen werden.

    Neue Funktion zum Ändern der Timerdauer.

  • Das klassische TimerInit() / TimerDiff() aus AutoIt, allerdings in Nanosekunden Genauigkeit:

  • Nicht schlecht! :):thumbup:


    Oder gleich als OOP-Variante:

    Edit: Oder noch kürzer: :)


  • Projekt: SerialComm

    Für die Kommunikation zwischen einem Arduino und dem PC (Windows) wird die serielle Schnittstelle verwendet (USB->Serial-Adapter auf Arduino-Seite).

    Um die serielle Schnittstelle mit Nim ansprechen zu können, habe ich ein Objekt erstellt, das die entsprechenden Methoden bereitstellt.

    Zum testen habe ich einen Arduino Nano genommen und dieses C++ Programm darauf gepackt:

    Mein Objekt in Nim sieht so aus:

    Und das Beispielprogramm dazu:

    Code
    import SerialComm
    let mySerial = SerialComm() # Objekt erstellen
    mySerial.OpenPort("COM6", 115200, 50) # COM6 oeffnen (115200 Baud, 50 ms Timeout)
    mySerial.Tx("Das ist ein Test.\r\n") # den Text senden
    let ret = mySerial.Rx() # die Antwort empfangen
    echo "Laenge: ", ret.len
    echo "Empfang: ", ret
    mySerial.ClosePort() # die Schnittstelle schliessen

    Wenn man, wie ich, mehrere Arduinos bestzt, dann kommt es schonmal vor, dass man unter Windows COM-Ports mit Nummern größer als 9 hat (COM10, COM11, COM12, usw.).

    Um diese COM-Ports ansprechen zu können, muss man "\\.\" davor schreiben. Mein Objekt berücksichtigt das aber bereits intern und setzt immer diese Kennung davor (falls nicht vorhanden), sodass man auch die "hohen" Ports problemlos benutzen kann.

    Außerdem habe ich die Einstellungen mal fest auf acht Datenbits, keine Parität und ein Stopbit ("8N1") gesetzt, weil das bei den meisten Geräten so Standard ist.

    Man kann also "nur" die Baudrate und die TimeOut-Zeit (in Millisekunden) übergeben. Ich denke, dass das aber wohl ausreicht.


    Die obigen Programme befinden sich auch nochmal im ZIP-Archiv (Anhang) zum herunterladen.

  • Immer wieder im Einsatz: INI-Dateien. Nim stellt dazu das Modul parsecfg bereit. Eine Ini (Config) - Datei wird nach dem Laden temporär in einer Art Dictionary gehalten (ein OrderedTable of OrderedTables). Werden Änderungen vorgenommen, ist also am Programmende ein Schreiben in die Datei zwingend erforderlich (ini.writeConfig(ini_file)).

    Hier mal ein kleines Bsp.:


    EDIT

    Ich habe mal noch ergänzt um den Default-Wert beim Lesen eines Key.

    Für Delete- und Schreiboperationen gibt es Prozeduren im Modul.

  • ShellExecute ist ja ein unverzichtbares Werkzeug.

    Ich habe den Aufruf hier vereinfacht, damit man das ständige Casten nicht an der Backe hat und mit "normalen" Strings arbeiten kann.


  • Immer wieder im Einsatz: INI-Dateien.

    Ich habe mal noch ergänzt um den Default-Wert beim Lesen eines Key.

    Ich habe das gerade gebraucht für mein großes Projekt mit Nim (ein MP3-Player). Insofern schonmal: Vielen Dank für das Beispiel! :):thumbup:

    Allerdings kann man das mit dem Defaultwert auch einfacher hinkriegen:

    Edit:

    Man kann die Prozedur auch überladen und kann sie dann mit unterschiedlichen Datentypen als Defaultwert aufrufen:

  • Um mit meinem MP3-Player voranzukommen, brauchte ich eine Möglichkeit die Reihenfolge der Einträge in der Playlist (ListView) mit der Maus zu verändern (nach oben/unten ziehen).

    Dazu habe ich bei Google nichts finden können. Mit AutoIt hatte ich das bereits umgesetzt. Vom Prinzip her wusste ich also, wie es geht, aber das Ganze mit Nim hinzukriegen war dann doch eine stundenlange Tortur, mit Suchen im AutoIt-Script und den UDFs, auf MSDN und bei C-Sourcecodes.

    Naja, lange Rede, kurzer Sinn: Ich hab's dann doch geschafft. :)

    Man kann jetzt also Dateien vom Explorer auf die Playlist ziehen (das war der einfache Teil) und innerhalb der Playlist die Einträge verschieben (der aufwendige Teil).

    Hier also das Beispielprogramm (ListView Drag and Drop):

  • Wenn wir in AutoIt Optionsparameter verwenden, sind dies üblicherweise Werte in 2er Potenzen, die mittels BitOr in einem Wert verknüpft sind und über BitAnd selektiv geprüft werden.

    Das ist in Nim ebenso möglich, aber nicht empfehlenswert, da es eine wesentlich performantere Lösung gibt: Sets.

    Sets sind eine Art Liste, was den Vorteil hat, dass man auf Inhalt mit "in" prüfen kann. Es gibt Einschränkungen bei den verwendbaren Datentypen, da muss man ein Auge drauf haben (s. hier: https://nim-lang.org/docs/manual.html#types-set-type).


    Bsp.