Ich hatte mal eine UDF dazu geschrieben (_WinAPI_ThemeSetProgress).
Da kann man nicht nur die Farbe ändern, sondern auch eine Beschriftung (Prozentangabe) hinzufügen.
Ich hatte mal eine UDF dazu geschrieben (_WinAPI_ThemeSetProgress).
Da kann man nicht nur die Farbe ändern, sondern auch eine Beschriftung (Prozentangabe) hinzufügen.
Euch allen ein frohes Weihnachtsfest und einen guten Rutsch ins neue Jahr! ![]()
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 von 10.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:
#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
Alles anzeigen
Weißt du auch wie man Exif.Photo.DateTimeDigitized und Exif.Photo.DateTimeOriginal auslesen kann?
Ich habe Dir mal die Funktion umgeschrieben:
#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
Alles anzeigen
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.
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:
#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:
#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
Alles anzeigen
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:
#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
Alles anzeigen
Man kommt auch ganz ohne Adlib und mit nur einem Timer aus:
$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
Alles anzeigen
Dann will ich auch noch eine Möglichkeit beisteuern (vom Prinzip her wie bei Kanashius, nur mit 32Bit UINT):
#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
EndFunc
Alles anzeigen
Wenn man die Daten gleich im UINT-Format speichert, braucht man sie nur bei der Anzeige zurückwandeln.