Euch allen ein frohes Weihnachtsfest und einen guten Rutsch ins neue Jahr! ![]()
Beiträge von Oscar
-
-
Ich muss mich noch mal melden und mich bei euch entschuldigen, denn mir ist da ein gravierender Fehler passiert. Sorry!
Also, nicht was die Empfehlung zur Crucial P510 betrifft. Die bleibt bestehen!Aber "wer misst, misst Mist" traf auf mich ziemlich offensichtlich zu. Die genauen Einzelheiten habe ich im Post #1 ausgebessert/ausgeweitet.
-
Wurde ein Ryzen 9600X und ein Asrock B850M Pro-A Wifi (auch mit einem PCIe Gen5 Steckplatz für SSD) , 32GB RAM habe ich mir auch dazu gegönnt
Ich habe mir auch einen Ryzen 5 9600X geholt. Allerdings als Mainboard das ASUS B650-Plus (WiFi brauche ich nicht). Ich brauche auf jeden Fall min. 4 SATA-Ports für meine drei 3,5 Zoll Festplatten und den DVD-Brenner (auch wenn ich den in letzter Zeit selten benutzt habe).
Außerdem sollten es min. zwei M2-Ports sein (das Asus hat sogar drei) und es sollten schnelle USB3.2 Ports dabei sein. Und ich bin schon seit Jahren Asus-Fan.
Beim RAM habe ich gleich auf 48 GB (2x24) gesetzt. Das war Preis-/Leistungsmäßig am sinnvollsten.
-
Was habt ihr für Anwendungen wo derart hohe Datenraten relevant sind?
Naja, es gibt schon einige Bereiche, wo man diese hohen Transferraten bemerkt (zumindest im Vergleich zu einer SATA-SSD) :
1. Beim laden von 3D-Games (da werden meist mehrere GB geladen).
2. Beim bearbeiten von Videos oder Audiodateien (je nach Größe).
3. Beim kopieren von großen Dateien vom externen USB3-Speicher (falls der schnell genug ist).
4. Wenn mehrere Prozesse gleichzeitig Daten auf die SSD kopieren (ok, das kommt bei mir nicht so oft vor).
Aber ich gebe Dir Recht, wenn man sowieso schon eine M2-SSD besitzt, lohnt sich ein Umstieg auf PCIe Gen5 nicht unbedingt.
Meine andere M2-SSD (per PCIe 4 angebunden) schafft auch schon 1.5 GB/s. Bei mir wurde die Neue halt eine 5er, weil der
Preisunterschied nur gering war. -
Uih, so viele Antworten!

Noch kurz etwas zur SSD: Bei diesen hohen Transferraten fehlt mir in der Praxis ein Laufwerk, dass als Quell-Laufwerk dienen könnte.
Da bleibt eigentlich nur das RAM bzw. halt Programme, die diese Daten so schnell zur Verfügung stellen.
Und zur Installation von Win11 ohne MS-Konto habe ich das hier befolgt (kein Netzwerkkabel anschliessen oder per WLAN verbinden! )
Nach dem Neustart kann man dann auswählen: "Ich habe kein Internet." und man kann ein lokales Konto erstellen. Das hat problemlos
geklappt. -
Ich habe mir nach etwas über 10 Jahren mal wieder einen neuen PC zusammengestellt (ja, auch wegen Win11).
Mein neues Mainboard besitzt 3 M2-Steckplätze. Einen davon mit PCIe Gen5 und weil ich mir sowieso eine neue SSD holen wollte, wurde es die Crucial P510 2TB (Speicher von Micron).
Das ist eine SSD mit PCIe Gen5 und verspricht eine Transferrate von10.000 MBit/s(tatsächlich steht dort 10.000 MB/s).
Im Internet habe ich schon einiges Positives über die SSD gelesen, aber jetzt konnte ich sie selbst testen.Edit:
"Wer misst, misst Mist!" Das trifft auf mich hier voll und ganz zu. Diesen Satz muss ich streichen, weil hier der Fehler im Detail steckt.Ich muss sagen, sie übertrifft sogar die Versprechungen (Test mit H2TestW und 100 GB: >1.8 GB/s also ca. 15.0000 MBit/s).Das Programm H2TestW (vom Heise Verlag) ist für PCIe-SSD nicht gemacht und liefert falsche Ergebnisse, weil dort mit Dateien gearbeitet wird, die lediglich 1 GB groß sind.
Ja, bei diesen hohen Transferraten muss man von "nur" 1 GB großen Dateien sprechen, denn das sind in dem Fall kleine Dateien. Aber die Werte von H2TestW hatten mich
auf die falsche Fährte gelockt, nämlich, dass es sich bei der Angabe um MBit/s handelt und nicht um MB/s.Tatsächlich sind diese PCIe-SSDs aber bereits so schnell, dass wir es hier mit 10.000 MB/s zu tun haben. Naja, da tritt wieder der Schummelfaktor der Speicherhersteller zu Tage,
die im Dezimalsystem rechnen, damit es nach mehr aussieht. Diesen Wert muss man also durch 10 teilen und mit 8 multiplizieren, dann kommt man zu den echten MB/s.Zum testen habe ich dann mal das Programm CrystalDiskMark genommen, beim dem dann auch realistische Werte ausgegeben werden.
Die PCIe5-SSD (Crucial P510):
Und zum Vergleich meine zweite PCIe4-SSD (eine Samsung 970 EVO Plus):

Falls ihr also nach einer SSD mit PCIe 5 Ausschau haltet, die Crucial kann ich sehr empfehlen, vor allem weil sie momentan recht günstig ist.

-
Doch damit fällt meine Modifikation "offiziell" weg. Bleibt es dabei Oscar ?
Den letzten Satz von dem "Rechtlichen" kannst Du auch streichen. Es ging mir eher darum, dass das Programm nicht etwas abgeändert und dann verkauft wird.
-
Wenn Du mehrere Exif-Einträge brauchst, dann ist es besser/schneller, den gesamten Exifbereich auf einmal einzulesen und die Daten im Speicher zu interpretieren.
Das habe ich mal in dieser Funktion gemacht:
AutoIt
Alles anzeigen#include <FileConstants.au3> #include <WinAPIConv.au3> #include <WinAPIFiles.au3> #include <WinAPIHObj.au3> #include <WinAPIInternals.au3> $sEXIF_DT = _GetExifDateTime('test.jpg') ConsoleWrite($sEXIF_DT & @CRLF) Func _GetExifDateTime($sImgfile) Local $hFile, $tBuffer, $iSOI, $iError, $iMarker, $iMarkerLength, $nBytes, $sRet = '' $hFile = _WinAPI_CreateFile($sImgfile, 2, 2) ; Datei zum lesen oeffnen If $hFile = 0 Then Return SetError(1, 0, $sRet) $tBuffer = DllStructCreate('align 1;ushort SOI') _WinAPI_ReadFile($hFile, $tBuffer, DllStructGetSize($tBuffer), $nBytes) $iSOI = _WinAPI_SwapWord($tBuffer.SOI) If $iSOI <> 0xFFD8 Then ; Marker: Start of Image (SOI) nicht vorhanden, dann _WinAPI_CloseHandle($hFile) Return SetError(2, 0, $sRet) Else ; Marker: SOI vorhanden, dann handelt es sich um eine JPG-Datei $tBuffer = DllStructCreate('align 1;ushort Marker;ushort Length') While True If Not _WinAPI_ReadFile($hFile, $tBuffer, DllStructGetSize($tBuffer), $nBytes) Then _WinAPI_CloseHandle($hFile) Return SetError(3, 0, $sRet) ; Fehler beim Lesen oder Dateiende erreicht EndIf $iMarker = _WinAPI_SwapWord($tBuffer.Marker) If $iMarker < 0xFF00 Then _WinAPI_CloseHandle($hFile) Return SetError(4, 0, $sRet) ; JPG ohne Exif-Marker EndIf $iMarkerLength = _WinAPI_SwapWord($tBuffer.Length) If $iMarker = 0xFFE1 Then ExitLoop ; wenn Marker: 0xFFE1, dann Schleife verlassen (vermutlich Exifdaten) _WinAPI_SetFilePointer($hFile, $iMarkerLength - 2, $FILE_CURRENT) ; zum naechsten Marker springen WEnd Local $tExif, $pExif, $iTIFFbegin, $tTIFF, $tEntry, $iDatatyp, $iTyp, $iData, $iX, $iY, $tDT, $sDT, $iTagCount $tExif = DllStructCreate('align 1;char buf[' & $iMarkerLength & ']') ; Buffer fuer den Exif-Bereich erstellen $pExif = DllStructGetPtr($tExif) ; Pointer auf den Buffer _WinAPI_ReadFile($hFile, $tExif, DllStructGetSize($tExif), $nBytes) ; den gesamten Exif-Bereich einlesen _WinAPI_CloseHandle($hFile) ; Datei schliessen $tBuffer = DllStructCreate('align 1;char Exif[6]', $pExif) ; Struktur fuer String "Exif" und zwei Nullbytes If $tBuffer.Exif = 'Exif' Then ; wenn zusaetzlich "Exif" vorhanden, dann handelt es sich um ein JPG mit Exifdaten $pExif += DllStructGetSize($tBuffer) $iTIFFbegin = $pExif ; Anfang des TIFF-Headers merken $tTIFF = DllStructCreate('align 1;ushort Endian;ushort Code;ulong Offset', $pExif) ; Struktur des TIFF-Headers $pExif += DllStructGetSize($tTIFF) For $iIFD = 0 To 1 ; es gibt zwei Image File Directories (IFDs) $tBuffer = DllStructCreate('align 1;ushort TagCount', $pExif) ; die Anzahl der TAGs in dem IFD $pExif += DllStructGetSize($tBuffer) Do $tEntry = DllStructCreate('align 1;ushort Typ;ushort Datatyp;ulong Length;ulong Data', $pExif) ; Struktur der Eintraege $pExif += DllStructGetSize($tEntry) $iTyp = ($tTIFF.Endian = 0x4D4D ? _WinAPI_SwapWord($tEntry.Typ) : $tEntry.Typ) $iDatatyp = ($tTIFF.Endian = 0x4D4D ? _WinAPI_SwapWord($tEntry.Datatyp) : $tEntry.Datatyp) $iData = ($tTIFF.Endian = 0x4D4D ? _WinAPI_SwapDWord($tEntry.Data) : $tEntry.Data) ;~ ConsoleWrite(StringFormat('!> Zeile:%i, Typ: 0x%.4X, Datatyp: %i, RawData: %i\r\n', @ScriptLineNumber, $iTyp, $iDatatyp, $iData)) Switch $iTyp Case 0xA002 ; X-Aufloesung $iX = $iData Case 0xA003 ; Y-Aufloesung $iY = $iData Case 0x0132, 0x9003, 0x9004 ; 0x0132 = Erstellungsdatum (ExifDTCreated) ; 0x9003 = Aufnahmedatum (ExifDTOrig) ; 0x9004 = Digitalisierungsdatum (ExifDTDigitized) $tDT = DllStructCreate('align 1;char DT[20]', $iTIFFbegin + $iData) $sDT = StringReplace(StringLeft($tDT.DT, 10), ':', '/') & StringMid($tDT.DT, 11) $sRet &= '0x' & Hex($iTyp, 4) & ' ' & $sDT & @CR Case 0x8769 ; Position auf den naechsten IFD $pExif = $iTIFFbegin + $iData ExitLoop EndSwitch $iTagCount += 1 ; Anzahl der Tags erhoehen Until $iTagCount > $tBuffer.TagCount $iTagCount = 0 Next $sRet = 'Resolution: ' & $iX & 'x' & $iY & @CR & $sRet EndIf EndIf Return $sRet EndFunc -
Weißt du auch wie man Exif.Photo.DateTimeDigitized und Exif.Photo.DateTimeOriginal auslesen kann?
Ich habe Dir mal die Funktion umgeschrieben:
AutoIt
Alles anzeigen#include <FileConstants.au3> #include <WinAPIConv.au3> #include <WinAPIFiles.au3> #include <WinAPIHObj.au3> #include <WinAPIInternals.au3> $sEXIF_DT = _GetExifDateTime('test.jpg') ConsoleWrite($sEXIF_DT & @CRLF) Func _GetExifDateTime($sImgfile) Local $tDT, $hFile, $tBuffer, $nBytes, $iSOI, $iMarker, $iMarkerLength, $iTIFFbegin, $tTIFF Local $tEntry, $iTyp, $iOffset, $iTagCount, $iError = 0, $iTmpOffset, $sRet, $iX, $iY $tDT = DllStructCreate('char DT[20]') $hFile = _WinAPI_CreateFile($sImgfile, 2, 2) ; Datei zum lesen oeffnen If $hFile = 0 Then Return SetError(1, 0, '') $tBuffer = DllStructCreate('ushort SOI') _WinAPI_ReadFile($hFile, $tBuffer, DllStructGetSize($tBuffer), $nBytes) $iSOI = _WinAPI_SwapWord($tBuffer.SOI) If $iSOI = 0xFFD8 Then ; wenn Marker: Start of Image (SOI) vorhanden, dann JPG $tBuffer = DllStructCreate('ushort Marker;ushort Length') Do If Not _WinAPI_ReadFile($hFile, $tBuffer, DllStructGetSize($tBuffer), $nBytes) Then $iError = 2 ; Fehler beim Lesen oder Dateiende erreicht ExitLoop EndIf $iMarker = _WinAPI_SwapWord($tBuffer.Marker) If $iMarker < 0xFF00 Then $iError = 3 ; JPG ohne Exif-Marker ExitLoop EndIf $iMarkerLength = _WinAPI_SwapWord($tBuffer.Length) If $iMarker = 0xFFE1 Then ExitLoop ; wenn Marker: 0xFFE1, dann Schleife verlassen (vermutlich Exifdaten) _WinAPI_SetFilePointer($hFile, $iMarkerLength - 2, $FILE_CURRENT) ; zum naechsten Marker springen Until $iError > 0 If $iError Then ; wenn keine Exifdaten vorhanden, dann beenden _WinAPI_CloseHandle($hFile) Return SetError($iError, 0, '') EndIf $tBuffer = DllStructCreate('char Exif[6]') ; Struktur fuer String "Exif" und zwei Nullbytes _WinAPI_ReadFile($hFile, $tBuffer, DllStructGetSize($tBuffer), $nBytes) If $tBuffer.Exif = 'Exif' Then ; wenn zusaetzlich "Exif" vorhanden, dann handelt es sich um ein JPG mit Exifdaten $iTIFFbegin = _WinAPI_GetFilePointerEx($hFile) ; Anfang des TIFF-Headers merken $tTIFF = DllStructCreate('ushort Endian; ushort Code; ulong Offset') ; Struktur des TIFF-Headers _WinAPI_ReadFile($hFile, $tTIFF, DllStructGetSize($tTIFF), $nBytes) For $i = 0 To 1 ; es gibt zwei Image File Directories (IFDs) $tBuffer = DllStructCreate('ushort TagCount') ; die Anzahl der TAGs in dem IFD _WinAPI_ReadFile($hFile, $tBuffer, DllStructGetSize($tBuffer), $nBytes) $tEntry = DllStructCreate('align 1; ushort Typ; ushort Datatyp; ulong Length; ulong Offset') ; Struktur der Eintraege Do If Not _WinAPI_ReadFile($hFile, $tEntry, DllStructGetSize($tEntry), $nBytes) Then ExitLoop 2 ; Die Daten können unterschiedlich kodiert sein: 0x4D4D = BigEndian oder 0x4949 = LittleEndian $iTyp = ($tTIFF.Endian = 0x4D4D ? _WinAPI_SwapWord($tEntry.Typ) : $tEntry.Typ) $iOffset = ($tTIFF.Endian = 0x4D4D ? _WinAPI_SwapDWord($tEntry.Offset) : $tEntry.Offset) Switch $iTyp Case 0xA002 ; X-Aufloesung $iX = $iOffset Case 0xA003 ; Y-Aufloesung $iY = $iOffset Case 0x0132, 0x9003, 0x9004 ; 0x0132 = Erstellungsdatum (ExifDTCreated) ; 0x9003 = Aufnahmedatum (ExifDTOrig) ; 0x9004 = Digitalisierungsdatum (ExifDTDigitized) $iTmpOffset = _WinAPI_GetFilePointerEx($hFile) _WinAPI_SetFilePointer($hFile, $iTIFFbegin + $iOffset) _WinAPI_ReadFile($hFile, $tDT, 0x14, $nBytes) ; und ist 20 Bytes (0x14) lang. $sRet &= '0x' & Hex($iTyp, 4) & ' -> ' & $tDT.DT & @CRLF _WinAPI_SetFilePointer($hFile, $iTmpOffset) Case 0x8769 ; Position auf den naechsten IFD _WinAPI_SetFilePointer($hFile, $iTIFFbegin + $iOffset) ExitLoop EndSwitch $iTagCount += 1 ; Anzahl der Tags erhoehen Until $iTagCount > $tBuffer.TagCount $iTagCount = 0 Next $sRet &= $iX & 'x' & $iY & @CRLF EndIf EndIf _WinAPI_CloseHandle($hFile) Return $sRet EndFunc ;==>_GetExifDateTime -
Hintergrundgeschichte:
Mein Schwager hat tausende JPG-Bilder auf seinem Rechner, die meistens von irgendwelchen Digitalkameras oder Smartphones stammen. Alle mit mehr oder weniger kryptischen Dateinamen plus Zaehler.
Zum Teil mit identischen Dateinamen in unterschiedlichen Unterverzeichnissen. Ich schlug ihm vor, dass er diese doch wenigstens nach Datum/Uhrzeit umbenennen kann, um da etwas Ordnung reinzubekommen. Also habe ich mal wieder AutoIt bemüht und ihm ein Programm geschrieben, welches anhand der EXIF-Daten einen entsprechenden Dateinamen generiert und die Datei so umbenennt.Technisches:
Das auslesen der EXIF-Daten kann man entweder mit den GDI+ Funktionen erledigen, was allerdings relativ lange dauert, weil man das Bild erst komplett in den Speicher laden muss. Bei mehreren Hundert Bilder dauert das seeehr lange.
Also habe ich im Internet recherchiert und mir den Aufbau der Struktur direkt in den Binärdaten der Datei angesehen. So kann man die EXIF-Daten sehr viel schneller auslesen, weil man nur wenige Bytes der Datei einlesen muss.
Problematisch war, dass mein Schwager auch Bilder hat, die keinerlei EXIF-Daten enthalten und diverse Bilder, bei denen die EXIF-Daten fehlerhaft sind. Also habe ich noch eine Fallback-Funktion eingebaut, bei der in diesen Fällen das Dateierstellungsdatum verwendet wird und falls das JPG selbst kaputt ist (da waren auch einige dabei), wird "1900-01-01__00-00-00" als Dateiname zurückgegeben. Auf diese Weise sieht er gleich, woran er ist.Naja, lange Rede kurzer Sinn: Vielleicht könnt ihr ja auch so ein Programm gebrauchen.
Eigenschaften:
- "Drag and drop" von Verzeichnissen/Dateien auf ein markiertes Feld im Hauptfenster.
- Verzeichnisse können auch rekursiv eingelesen werden (das kann u.U. aber sehr lange dauern, wenn dort mehrere Tausend Bilder liegen)
- Hauptfenster kann "Immer im Vordergrund" gesetzt werden.
- Ein bereits bestehender Dateiname wird an das EXIF-Datum/Uhrzeit angehängt, wenn der Haken im Listview gesetzt ist.
- Über das Kontextmenü beim Listview kann man das markieren/anhaken etwas komfortabler erledigen.
- Eine Vorschau-Funktion, wenn man eine Datei im Listview doppelt anklickt.
Das Script gibt es als ZIP-Archiv im Anhang zum download.
Screenshot:
-
Gebe ich auf die IN-Kontakte des Relais Moduls direkt GND, zieht das entsprechende Relais.
Wenn die Relais Low-aktiv sind mußt Du im Sketch auch LOW für EIN benutzen.
Pulldown habe ich 10k genommen, sollte völlig ausreichen.
Wozu einen Pulldown-Widerstand, wenn Du im Sketch INPUT_PULLUP definierst?
Bei INPUT_PULLUP brauchst Du gar keinen externen Widerstand. Einfach nach GND tasten.
-
die lediglich die 2 AutoIt exen und ein paar Registry Einträge erstellt.
Die Registry-Einträge bräuchte man gar nicht unbedingt.
Wenn die AutoIt-Exe im a3x Verzeichnis liegt, müsste man nur eine Verknüpfung (in der die AutoIt-Exe mit dem a3x gestartet wird) in dem Verzeichnis erstellen.
-
die auf dem Zielrechner lediglich eine a3x Unterstützung installiert
Dafür bräuchte man ja lediglich die 32/64 Bit exe im a3x-Verzeichnis.
Ich hatte gestern schon die Idee, das alles zu packen und als BASE64 in ein NIM-Programm zu integrieren, sodass man damit die exe ins Scriptverzeichnis entpacken kann.
Allerdings wenn ein AV-Programm bereits auf die AutoIt-Exe anschlägt, wird das auch keine Lösung sein.

-
Bekommt es von euch jemand hin?
Das geht sehr viel kürzer und unabhängig von 32/64 Bit:
AutoIt#include <WinAPIGdi.au3> #include <WinAPIIcons.au3> #include <WinAPIShellEx.au3> #AutoIt3Wrapper_UseX64=y Global $iIconSize = 64 Global $hIcon = _WinAPI_ShellExtractIcon('shell32.dll', -42, $iIconSize, $iIconSize) _WinAPI_SaveHICONToFile(@ScriptDir & '\test.ico', $hIcon) _WinAPI_DestroyIcon($hIcon) -
das ist eine von den 'Shell-Ausrichtungsfallen'. Die Struktur SHChangeNotifyEntry ist in ShlObj_core.h definiert. Da steht am Anfang ein
#include <pshpack1.h> /* Assume byte packing throughout */,
das auch für die Struktur gilt und ein 'Byte-Packing' erzwingt.Ah! Vielen Dank!
So funktioniert es dann:
AutoIt
Alles anzeigen#Region ;************ Includes ************ #include <WinAPISysWin.au3> #include <WinAPIShellEx.au3> #EndRegion ;************ Includes ************ #AutoIt3Wrapper_UseX64=y ;32bit funktioniert / 64bit funktioniert Global $aTest[] = ["C:\_test\", "C:\_test2\", "C:\_test3\", "C:\_test4\"] For $i = 0 To UBound($aTest) - 1 DirCreate($aTest[$i]) Next OnAutoItExitRegister('OnAutoItExit') HotKeySet('{ESC}', '_End') Global $hWnd = GUICreate('') Global $iMsg = _WinAPI_RegisterWindowMessage('SHELLCHANGENOTIFY') GUIRegisterMsg($iMsg, 'WM_SHELLCHANGENOTIFY') Global $g_iID = _WinAPI_ShellChangeNotifyRegister64($hWnd, $iMsg, $SHCNE_ALLEVENTS, BitOR($SHCNRF_INTERRUPTLEVEL, $SHCNRF_SHELLLEVEL, $SHCNRF_RECURSIVEINTERRUPT), $aTest, 1) If @error Then MsgBox(($MB_ICONERROR + $MB_SYSTEMMODAL), 'Fehler', 'Das Fenster wurde nicht registriert.') Exit EndIf While 1 Sleep(1000) WEnd Func _End() Exit EndFunc ;==>_End Func OnAutoItExit() If $g_iID Then _WinAPI_ShellChangeNotifyDeregister($g_iID) EndIf EndFunc ;==>OnAutoItExit Func WM_SHELLCHANGENOTIFY($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $tIDL = DllStructCreate((@AutoItX64 ? 'uint64 Item1;uint64 Item2;' : 'dword Item1;dword Item2;'), $wParam) ; bei 64 Bit ist das ein QWord (8 Byte) Local $sPath = _WinAPI_ShellGetPathFromIDList(DllStructGetData($tIDL, 'Item1')) If $sPath Then ConsoleWrite('Event: 0x' & Hex($lParam) & ' | Pfad: ' & $sPath & @CRLF) Else ConsoleWrite('Event: 0x' & Hex($lParam) & @CRLF) EndIf EndFunc ;==>WM_SHELLCHANGENOTIFY Func _WinAPI_ShellChangeNotifyRegister64($hWnd, $iMsg, $iEvents, $iSources, $aPaths, $bRecursive = False) Local $iPath = $aPaths, $tagStruct = 'align 1;' If IsArray($aPaths) Then If UBound($aPaths, $UBOUND_COLUMNS) Then Return SetError(1, 0, 0) Else Dim $aPaths[1] = [$iPath] EndIf For $i = 0 To UBound($aPaths) - 1 If Not _WinAPI_PathIsDirectory($aPaths[$i]) Then Return SetError(2, 0, 0) Next For $i = 0 To UBound($aPaths) - 1 $tagStruct &= 'ptr;int;' Next Local $tEntry = DllStructCreate($tagStruct) For $i = 0 To UBound($aPaths) - 1 $aPaths[$i] = _WinAPI_ShellILCreateFromPath(_WinAPI_PathSearchAndQualify($aPaths[$i])) DllStructSetData($tEntry, 2 * $i + 1, $aPaths[$i]) DllStructSetData($tEntry, 2 * $i + 2, $bRecursive) Next Local $iError = 0 Local $aCall = DllCall('shell32.dll', 'ulong', 'SHChangeNotifyRegister', 'hwnd', $hWnd, 'int', $iSources, 'long', $iEvents, _ 'uint', $iMsg, 'int', UBound($aPaths), 'struct*', $tEntry) If @error Or Not $aCall[0] Then $iError = @error + 10 For $i = 0 To UBound($aPaths) - 1 _WinAPI_CoTaskMemFree($aPaths[$i]) Next Return SetError($iError, 0, $aCall[0]) EndFunc ;==>_WinAPI_ShellChangeNotifyRegister64 -
Ich denke, dass sich der Feldindex (@AutoItX64 ? 4 : 2) * $i + 1 von 32- zu 64-Bit nicht ändert.
Ja, das war falsch!
Der Feldindex bleibt gleich, auch wenn das damit funktioniert hat (warum versuche ich gerade rauszukriegen).
-
Ich habe das mal auf 64 Bit angepasst:
AutoIt
Alles anzeigen#Region ;************ Includes ************ #include <WinAPISysWin.au3> #include <WinAPIShellEx.au3> #EndRegion ;************ Includes ************ #AutoIt3Wrapper_UseX64=y ;32bit funktioniert / 64bit funktioniert Global $aTest[2] = ["C:\_test\", "C:\_test2\"] DirCreate($aTest[0]) DirCreate($aTest[1]) OnAutoItExitRegister('OnAutoItExit') ConsoleWrite((@AutoItX64 ? 4 : 2) & @CRLF) Local $hWnd = GUICreate('') Local $iMsg = _WinAPI_RegisterWindowMessage('SHELLCHANGENOTIFY') GUIRegisterMsg($iMsg, 'WM_SHELLCHANGENOTIFY') Global $g_iID = _WinAPI_ShellChangeNotifyRegister64($hWnd, $iMsg, $SHCNE_ALLEVENTS, BitOR($SHCNRF_INTERRUPTLEVEL, $SHCNRF_SHELLLEVEL, $SHCNRF_RECURSIVEINTERRUPT), $aTest, 1) If @error Then MsgBox(($MB_ICONERROR + $MB_SYSTEMMODAL), 'Fehler', 'Das Fenster wurde nicht registriert.') Exit EndIf While 1 Sleep(1000) WEnd Func WM_SHELLCHANGENOTIFY($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg Local $tIDL = DllStructCreate((@AutoItX64 ? 'uint64 Item1; uint64 Item2' : 'dword Item1; dword Item2'), $wParam) ; bei 64 Bit ist das ein QWord (4 Byte) Local $sPath = _WinAPI_ShellGetPathFromIDList(DllStructGetData($tIDL, 'Item1')) If $sPath Then ConsoleWrite('Event: 0x' & Hex($lParam) & ' | Pfad: ' & $sPath & @CRLF) Else ConsoleWrite('Event: 0x' & Hex($lParam) & @CRLF) EndIf EndFunc ;==>WM_SHELLCHANGENOTIFY Func OnAutoItExit() If $g_iID Then _WinAPI_ShellChangeNotifyDeregister($g_iID) EndIf EndFunc ;==>OnAutoItExit Func _WinAPI_ShellChangeNotifyRegister64($hWnd, $iMsg, $iEvents, $iSources, $aPaths, $bRecursive = False) Local $iPath = $aPaths, $tagStruct = '' If IsArray($aPaths) Then If UBound($aPaths, $UBOUND_COLUMNS) Then Return SetError(1, 0, 0) Else Dim $aPaths[1] = [$iPath] EndIf For $i = 0 To UBound($aPaths) - 1 If Not _WinAPI_PathIsDirectory($aPaths[$i]) Then Return SetError(2, 0, 0) Next For $i = 0 To UBound($aPaths) - 1 $tagStruct &= 'ptr;int;' Next Local $tEntry = DllStructCreate($tagStruct) For $i = 0 To UBound($aPaths) - 1 $aPaths[$i] = _WinAPI_ShellILCreateFromPath(_WinAPI_PathSearchAndQualify($aPaths[$i])) DllStructSetData($tEntry, (@AutoItX64 ? 4 : 2) * $i + 1, $aPaths[$i]) ; bei 64Bit ist PIDLIST_ABSOLUTE = 64 Bit (4 Byte) DllStructSetData($tEntry, (@AutoItX64 ? 4 : 2) * $i + 2, $bRecursive) Next Local $iError = 0 Local $aCall = DllCall('shell32.dll', 'ulong', 'SHChangeNotifyRegister', 'hwnd', $hWnd, 'int', $iSources, 'long', $iEvents, _ 'uint', $iMsg, 'int', UBound($aPaths), 'struct*', $tEntry) If @error Or Not $aCall[0] Then $iError = @error + 10 For $i = 0 To UBound($aPaths) - 1 _WinAPI_CoTaskMemFree($aPaths[$i]) Next Return SetError($iError, 0, $aCall[0]) EndFunc ;==>_WinAPI_ShellChangeNotifyRegister -
Man kommt auch ganz ohne Adlib und mit nur einem Timer aus:
AutoIt
Alles anzeigen$iTimer = TimerInit() $iIntervallmeldung = 60000 $iDauermeldung = 5000 HotKeySet('{ESC}', _Exit) While Sleep(1000) _CheckMeldung() WEnd Func _CheckMeldung() Local Static $iLastMillis = 0, $bMeldung = False Local $iMillis = TimerDiff($iTimer) ConsoleWrite(Int(($iMillis - $iLastMillis) / 1000) & @CRLF) If $iMillis - $iLastMillis > $iIntervallmeldung Then $iLastMillis = $iMillis $bMeldung = True EndIf If $bMeldung Then ConsoleWrite(' Alarm' & @CRLF) If $iMillis - $iLastMillis > $iDauermeldung Then ConsoleWrite(' Alarm aus' & @CRLF) $bMeldung = False EndIf EndIf EndFunc Func _Exit() Exit EndFunc -
Dann will ich auch noch eine Möglichkeit beisteuern (vom Prinzip her wie bei Kanashius, nur mit 32Bit UINT):
AutoIt
Alles anzeigen#include <Array.au3> Local $aListViewData[10][4] = [ _ ["PC-001", "00:1A:2B:3C:4D:5E", "192.168.23.145", "Büro 101"], _ ["PC-002", "00:2B:3C:4D:5E:6F", "10.0.15.87", "Empfang"], _ ["PC-003", "00:3C:4D:5E:6F:7G", "172.16.78.209", "Besprechungsraum"], _ ["PC-004", "00:4D:5E:6F:7G:8H", "192.168.1.3", "Buchhaltung"], _ ["PC-005", "00:5E:6F:7G:8H:9I", "10.10.55.201", "Marketing"], _ ["PC-006", "00:6F:7G:8H:9I:0J", "172.20.100.50", "Entwicklung 1"], _ ["PC-007", "00:7G:8H:9I:0J:1K", "192.168.0.11", "Entwicklung 2"], _ ["PC-008", "00:8H:9I:0J:1K:2L", "10.1.1.254", "Personalabteilung"], _ ["PC-009", "00:9I:0J:1K:2L:3M", "172.31.255.1", "Kantine"], _ ["PC-010", "00:0J:1K:2L:3M:4N", "192.168.100.100", "Serverraum"] _ ] For $i = 0 To UBound($aListViewData) - 1 $aListViewData[$i][2] = _IPaddrToUInt($aListViewData[$i][2]) Next _ArraySort($aListViewData, 1, 0, 0, 2) For $i = 0 To UBound($aListViewData) - 1 $aListViewData[$i][2] = _UIntToIPaddr($aListViewData[$i][2]) Next _ArrayDisplay($aListViewData) Func _IPaddrToUInt($sIP) Local $tAddr = DllStructCreate('uint IP') Local $aTmp = StringSplit($sIP, '.', 2) Local $iAddr = BitOR(BitShift(Int($aTmp[0]), -24), BitShift(Int($aTmp[1]), -16), BitShift(Int($aTmp[2]), -8), Int($aTmp[3])) $tAddr.IP = $iAddr Return $tAddr.IP EndFunc Func _UIntToIPaddr($iAddr) Local $tAddr = DllStructCreate('uint IP') $tAddr.IP = $iAddr Local $tIP = DllStructCreate('byte D;byte C;byte B;byte A', DllStructGetPtr($tAddr)) Return $tIP.A & '.' & $tIP.B & '.' & $tIP.C & '.' & $tIP.D EndFuncWenn man die Daten gleich im UINT-Format speichert, braucht man sie nur bei der Anzeige zurückwandeln.
-
Besten Dank, ich werde mal schauen ob ich das erweitern kann, so wie ich das möchte.
Gern geschehen!
Ja, es kommt noch darauf an, was Du mit dem Listview vor hast. Wenn es nicht nur eine Auswahlbox sein soll, muss man da evtl. noch zusätzliche GUI-Elemente ein-/ausblenden.
Wenn Du Hilfe brauchst, sag Bescheid!