﻿; autoiter
; https://autoit.de/index.php/Thread/84750-Schlagwortsuche-in-Textdateien/

Global $sAppName = "Textsuche" ; Der Programmname (steht ganz oben, weil er auch in der UDF ChooseFileFolder_MOD.au3 verwendet wird.)

#include <GuiListView.au3>
#include <FileConstants.au3>
#include <Array.au3>
#include <Excel.au3>
#include <Word.au3>
#include <File.au3>
#include <GuiEdit.au3>
#include <GuiRichEdit.au3>
#include <SQLite.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>
#include ".\Includes\included_Base64_db.au3"
#include ".\Includes\ChooseFileFolder_MOD.au3"
#include <TrayConstants.au3>
#include <GuiComboBox.au3>
#include <ProgressConstants.au3>
#include <GuiStatusBar.au3>

#include <WinAPI.au3>
#include <WinAPISys.au3>
#include <GuiMenu.au3>

#Region File-Includes
Global $sWorkDir = @ScriptDir & "\" & $sAppName & "-Data\"
Global $hIni = $sWorkDir & $sAppName & ".ini"

If Not FileExists($hIni) Then ; Die Ini für gespeicherte Einstellungen wird erstellt.
	$sString = "[Settings]" & @CRLF & "Startordner=" & @CRLF & "Unterordner=0" & @CRLF & "Ignoriertes=" & @CRLF
	$sString &= "Schreibe je 500 eingelesene Dateien in DB=1" & @CRLF & "Vacuum=0" & @CRLF & "Umlaute=0" & @CRLF
	$sString &= "[Position]"
	$hFileOpenIni = FileOpen($hIni, 10)
	FileWrite($hFileOpenIni, $sString)
	FileClose($hFileOpenIni)
EndIf

If @AutoItX64 Then ; Die SQLite.dll wird entpackt.
	If Not FileExists($sWorkDir & "SQLite3_x64.dll") Then _sqlite3_x64dll(True, $sWorkDir)
Else
	If Not FileExists($sWorkDir & "SQLite3_x86.dll") Then _sqlite3_x86dll(True, $sWorkDir)
EndIf

Global $sXPDF = $sWorkDir & "pdftotext\pdftotext.exe"
If Not FileExists($sWorkDir & "pdftotext\pdftotext.exe") Then ; zum Start wird die pdftotext.exe entpackt, falls nötig (übernimmt PDF auslesen).
	DirCreate($sWorkDir & "pdftotext")
	_pdftotexttxt(True, $sWorkDir & "pdftotext")
	_pdftotext86(True, $sWorkDir & "pdftotext")
EndIf
#EndRegion File-Includes


Global $hFiletypes = $sWorkDir & "unterstützte Textdatei-Typen.txt" ; die hier gelisteten Dateien werden als Textdateien behandelt.
If Not FileExists($hFiletypes) Then
	$sString = "AU3,PAGES,TEX,MSG,WPS,WPD,TXT,LOGABW,DWD,FDX,LST,BIB,WTT,STY,SIG,GDOC,WPT,EMLWPS,TDF,RST,RZN,AIM,U3I,HHT,OFL,"
	$sString &= "GSD,BAD,BDRSCRIVX,GTHR,CRWL,QDL,NOTES,GV,LNT,HS,LXFML,BDPTDF,UNAUTH,KNT,BOC,LP2,KWD,SGM,BIB,IDX,XWP,XWPCHORD,PSW,"
	$sString &= "SSA,MWP,SMS,LYX,LUF,FBL,MELLEL,MELLASE,CYI,BEAN,RZK,TAB,RVF,GPD,SUBLIME-WORKSPACESUBLIME-PROJECT,QPF,PAGES-TEF,CNM,"
	$sString &= "PWD,FODT,BTD,NJXMD5TXT,NB,BIBTEX,ADOC,CALCA,FWD,FOUNTAIN,NWPPLANTUML,PU,EIO,KES,UOT,ZABW,BZABW,TEMPLATE,HWPTEXTCLIPPING,"
	$sString &= "TMD,RIS,EMULECOLLECTION,MWD,FLR,SLA,SLAGZAWW,XBDOC,IPSPOT,SCRIV,STORY,FCF,FDXT,FDT,WEBDOC,LTXBNA,SCW,MBOX,DIZ,VCT,DNE,"
	$sString &= "SDW,RPT,UTF8,EMLX,DXOTT,LWP,PJT,RTD,README,KON,FPT,ASC,DVI,LBT,FRTTEXT,LST,MNT,XY3,XYP,SXW,STRINGS,UNX,WPA,WPD,KLG,"
	$sString &= "KLGETF,ERR,DOCM,XDL,XDL,FDR,CHARSET,SCT,XYW,P7S,NFO,SUBPWI,ANS,SAFETEXT,UTXT,LIS,RTX,SESSION,PFS,TMV,OCR,SKCARDCWS,UOF,"
	$sString &= "WBK,SMF,PWDP,PWDPL,XBPLATE,WPT,JIS,AWP,BRX,HZAPT,SAM,FADEINTEMPLATE,TRELBY,DXB,DXP,BML,GMD,SE,DROPBOXPDPCMD,BBS,APKG,FDF,"
	$sString &= "PWR,SAM,NGLOSS,WP5,OPEICO,WP4,HBKCHART,MIN,EMF,WRI,TAB,WP,EIT,NWM,FGS,TVJ,TLB,TPC,PMOJNP,ATY,MW,EPP,NWCTXT,PVJ,GPN,ERR,ACT,"
	$sString &= "ORT,WP7,PVM,TMFDS,RUN,VNT,SCC,SDM,NDOC,STW,1ST,ASC,PRT,ODM,SXG,PFXDGS,AWT,SCM,COD,ZW,DOCZ,DFTI,VW,ETX,UPD,XWP,WPL,JOEFAQ,"
	$sString &= "NOW,SAF,SDOC,XY,LATEX,HWP,WN,DSC,FWDN,PRTASCII,THP,OPENBSD,LYT,MAN,JRTF,ODIF,IIL,WTX,LTR,ODO,EUCSAVE,LUE,WPD,WP6,ME,JP1,MCW,"
	$sString &= "WSD,IPF,RFT,DOX,FFT,DCAJARVIS,WPW,RAD"
	FileWrite($hFiletypes, $sString)
EndIf

Global $aFileTypes = StringSplit(FileRead($hFiletypes), ",", 2)
;~ _ArrayDisplay($aFileTypes)

OnAutoItExitRegister("_Exit")

#Region Deklarationen ; Hier werden die wichtigsten globalen Variablen deklariert.

; Start aus der XLSXReadToArray-UDF - hier deklariert, weil ich die UDF der Übersicht halber nicht includiere, sondern unten bei den Auslese-Funktionen einsortiere.
If Not ObjEvent("AutoIt.Error") Then Global Const $_XLSXZip_COMErrorFunc = ObjEvent("AutoIt.Error", "_XLSXZip_COMErrorFunc")
Global $DateSSN[27] = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
; Ende aus der XLSXReadToArray-UDF

Global $bAbort = False ; Die Variable bekommt in der _SetAbort-Funktion den Wert true, wenn während der Suche der Hotkey "Esc" gedrückt wird.
Global $sStartFolder = IniRead($hIni, "Settings", "Startordner", "") ; In dieser Variable wird der Ausgangspunkt der Suche gespeichert.
Global $aSearchString[1] ; Das Array für den Suchbegriff, das überall Verwendung findet.
Global $aAllHits[1][0] ; globales Array, in dem die Trefferpositionen zum Springen in der Listview gespeichert werden.
Global $bExcelInstalled = True, $bOldExcel = False ; Diese Variablen dienen als Flag für Excel installiert, Excel kann mit XLSX umgehen. (.. und für Word)
Global $bObjectError = False ; Globale Variable, die gesetzt wird, wenn ADODB in der _XLSReadToArray-Funktion auf dem Computer nicht funktioniert.
Global $oWord = _Word_Create(False, True) ; Variable für das Word Objekt. Es wird beim Beenden geschlosssen.
Global $oExcel = _Excel_Open(False, False, True, True, True) ; Damit bei Rechtsklick die Excel-Anwendung schnell geöffnet wird, wird hier global eine Instanz geöffnet und beim Beenden geschlossen.
If @error Then $bExcelInstalled = False
Global $iFontsize = Number(IniRead($hIni, "Font", "Edit", "8.5")) ; Die Standard-Schriftgröße für die $hDocGUI.
Global $aIgnoreToIni ; Das Array mit den Ignorierten Ordnern ist global, weil es auch in der modifizierten ChooseFileFolder.au3 benutzt wird.
Global $hTimer, $bEndSize = True ; Zwei Variablen, die ich für die _EndSize Funktion brauche.
Global $iListposition = 1, $bExpanded = False ; Zwei Variablen, die ich für das Springen und Feldgröße-Anpassen in der $hListGUI benötige
Global $aSQLFiles, $iRows, $iColumns, $iRval ; Die Variablen für die für die SQL-Tabelle. $aSQLFiles ist das Array mit allen Dateien in den Ordnern.
Global $MainGUIminWid = 505, $MainGUIminHt = 500 ; Mindest- und Maximal-Größen für das Hauptfenster
Global $ListGUIminWid = 800, $ListGUIminHt = 150 ; Mindest- und Maximal-Größen für das Tabellenfenster
Global $hDocGUIminWid = 730, $hDocGUIminHt = 150 ; Mindest- und Maximal-Größen für das Textfenster
Global $aSQLResultFiles[0][3]
#EndRegion Deklarationen ; Hier werden die wichtigsten globalen Variablen deklariert.

Opt("TrayMenuMode", 3) ; Das Tray-Icon soll kein Standardmenü haben. Ein Klick auf das Icon blendet das Programm ein/aus (in den Tray!).
TraySetClick(8) ; Hierdurch wird das Tray-Menü nur bei Rechtsklick angezeigt. Den Linksklick möchte ich zum Ein-/Ausblenden verwenden.

#Region Tray Menü ; Das Menü für die Systemablage (Symbole unten rechts in der Windows-Taskleiste)
Local $idT_Show = TrayCreateItem("Anzeigen")
Local $idT_Close = TrayCreateItem("Minimieren statt beenden")
Local $idT_Minimize = TrayCreateItem("Schließen minimiert in Tray")
Local $idT_Start = TrayCreateItem("Mit Windows starten")
TrayCreateItem("")
Local $idT_Exit = TrayCreateItem("Beenden")

If IniRead($hIni, "Settings", "Minimiere in Tray", "") Then TrayItemSetState($idT_Minimize, $TRAY_CHECKED)
If IniRead($hIni, "Settings", "Minimieren statt beenden", "") Then TrayItemSetState($idT_Close, $TRAY_CHECKED)
If IniRead($hIni, "Settings", "Autostart", "") Then TrayItemSetState($idT_Start, $TRAY_CHECKED)
#EndRegion Tray Menü ; Das Menü für die Systemablage (Symbole unten rechts in der Windows-Taskleiste)

#Region MainGUI ; Das Hauptfenster

Global $iMainXPos = IniRead($hIni, "Position", "Mainx", "0")
Global $iMainYPos = IniRead($hIni, "Position", "Mainy", "0")
Global $iMainWidth = IniRead($hIni, "Position", "Mainwidth", "490")
Global $iMainHeight = IniRead($hIni, "Position", "Mainheight", "700")

Opt("GUIResizeMode", 2 + 32 + 256 + 512) ; Standard Resizing-Verhalten der folgenden Controls.

Global $hMainGUI = GUICreate($sAppName, 500, 500, $iMainXPos, $iMainYPos, BitOR($WS_SYSMENU, $WS_SIZEBOX, $WS_MAXIMIZEBOX, $WS_MINIMIZEBOX))
GUISetFont(9.5, 500, 0, "Segoe UI", $hMainGUI, 5)
Global $FontThemeColor = 0x00060B
Global $idM_SSettings = GUICtrlCreateMenu("Such-Einstellungen")
Global $idM_Umlauts = GUICtrlCreateMenuItem("Bei Umlauten und ß auch ae, ue, oe, ss finden", $idM_SSettings)
Global $idM_WriteStepsDB = GUICtrlCreateMenuItem("Je 500 neue Dateien in DB schreiben", $idM_SSettings)
Global $idM_Vacuum = GUICtrlCreateMenuItem("DB Speicherplatz freigeben, wenn möglich", $idM_SSettings)
Global $idM_PSettings = GUICtrlCreateMenu("Programm-Verhalten")
Global $idM_Close = GUICtrlCreateMenuItem("Fenster Schließen minimiert " & $sAppName, $idM_PSettings)
Global $idM_Minimize = GUICtrlCreateMenuItem($sAppName & " minimiert in Tray-Bereich", $idM_PSettings)
Global $idM_Start = GUICtrlCreateMenuItem($sAppName & " mit Windows starten", $idM_PSettings)
Global $idM_Reset = GUICtrlCreateMenu("Zurücksetzen")
Global $idM_ResetDB = GUICtrlCreateMenuItem("Datenbank leeren", $idM_Reset)
Global $idM_ResetHist = GUICtrlCreateMenuItem("Suchbegriffe löschen", $idM_Reset)


If IniRead($hIni, "Settings", "Umlaute", "") = 1 Then GUICtrlSetState($idM_Umlauts, $GUI_CHECKED)
If IniRead($hIni, "Settings", "Schreibe je 500 eingelesene Dateien in DB", "") = 1 Then GUICtrlSetState($idM_WriteStepsDB, $GUI_CHECKED)
If IniRead($hIni, "Settings", "Vacuum", "") = 1 Then GUICtrlSetState($idM_Vacuum, $GUI_CHECKED)
If IniRead($hIni, "Settings", "Minimiere in Tray", "") Then GUICtrlSetState($idM_Minimize, $GUI_CHECKED)
If IniRead($hIni, "Settings", "Minimieren statt beenden", "") Then GUICtrlSetState($idM_Close, $GUI_CHECKED)
If IniRead($hIni, "Settings", "Autostart", "") Then GUICtrlSetState($idM_Start, $GUI_CHECKED)


Global $idM_Menu = GUICtrlCreateMenu("?")
Global $idM_About = GUICtrlCreateMenuItem("Über", $idM_Menu)

Global $sLabeltext = $sStartFolder
If StringLen($sStartFolder) >= 26 Then
	$aSFSplit = StringSplit($sStartFolder, "\")
	If Not @error Then $sLabeltext = "..\" & $aSFSplit[$aSFSplit[0]] ; evtl. gekürzte Variante des Startverzeichnisses.
EndIf

Global $idB_StartFolder = GUICtrlCreateButton("Such-Ordner wählen", 10, 20, 135, 35)

Global $idL_StartFolder = GUICtrlCreateLabel($sLabeltext, 10, 65, 135, 14)
GUICtrlSetFont($idL_StartFolder, 8.5)
GUICtrlSetColor($idL_StartFolder, $FontThemeColor)
GUICtrlSetTip($idL_StartFolder, $sStartFolder, "Ausgangspunkt der Suche")

Global $idB_Ignore = GUICtrlCreateButton("Ordner ignorieren", 345, 20, 135, 35)
If $sStartFolder == "" Then GUICtrlSetState($idB_Ignore, $GUI_DISABLE)

Global $sToIgnore = IniRead($hIni, "Settings", "Ignoriertes", "")
$sToIgnore = StringReplace($sToIgnore, "|", @CRLF)
Global $iToIgnore = @extended
If $sToIgnore == "" Then $iToIgnore = -1

Global $idL_Ignore = GUICtrlCreateLabel("Ignorierte Ordner: " & $iToIgnore + 1, 345, 65, 135, 14)
GUICtrlSetFont($idL_Ignore, 8.5)
GUICtrlSetColor($idL_Ignore, $FontThemeColor)
GUICtrlSetTip($idL_Ignore, $sToIgnore, "Ignorierte Elemente")

Global $idC_Subfolders = GUICtrlCreateCheckbox("inklusive Unterordner", 175, 5, 155, 30)
GUICtrlSetFont($idC_Subfolders, 10.5)
If IniRead($hIni, "Settings", "inklusive Unterordner", "") Then
	GUICtrlSetState($idC_Subfolders, $GUI_CHECKED)
Else
	GUICtrlSetState($idB_Ignore, $GUI_DISABLE)
EndIf

Global $idC_DBcleaning = GUICtrlCreateCheckbox("Datenbankbereinigung", 175, 30, 160, 30)
GUICtrlSetFont($idC_DBcleaning, 10.5)
If IniRead($hIni, "Settings", "Datenbankbereinigung", "") Then
	GUICtrlSetState($idC_DBcleaning, $GUI_CHECKED)
EndIf
GUICtrlSetTip($idC_DBcleaning, "Während der Suche werden nicht mehr vorhandene Dateien aus der Datenbank gelöscht." & @CRLF & "Achtung: " & @CRLF & " Wurden bei einer vorherigen Suche Unterordner mit einbezogen und nun nicht mehr, werden auch diese Dateien nicht gefunden und gelöscht.", "Datenbankbereinigung", 1)

Global $idC_DBonly = GUICtrlCreateCheckbox("Nur Datenbanksuche", 175, 55, 155, 30)
GUICtrlSetFont($idC_DBonly, 10.5)
If IniRead($hIni, "Settings", "Datenbanksuche", "") Then
	GUICtrlSetState($idC_DBonly, $GUI_CHECKED)
	GUICtrlSetState($idB_Ignore, $GUI_DISABLE)
	GUICtrlSetState($idC_Subfolders, $GUI_DISABLE)
	GUICtrlSetState($idC_DBcleaning, $GUI_DISABLE)
EndIf
GUICtrlSetTip($idC_DBonly, "Bei dieser Suche wird direkt in der Datenbank gesucht. Ordner und Dateien werden nicht geprüft ( - sehr schnell).", "Nur Datenbanksuche", 1)

Global $idB_Search = GUICtrlCreateButton("Suche starten", 345, 115, 135, 35)
GUICtrlSetTip($idB_Search, "Auch durch Tastendruck auf die Enter-Taste", "Suche starten")

Global $idCombo_SearchString = GUICtrlCreateCombo("", 10, 116, 305, 34)
GUICtrlSetFont($idCombo_SearchString, 15)

Global $idD_Delete = GUICtrlCreateDummy()

Global $aAccelKeys[2][2] = [["{ENTER}", $idB_Search], ["{DELETE}", $idD_Delete]]
GUISetAccelerators($aAccelKeys)

$idL_Clickhint = GUICtrlCreateLabel("Doppelklick links = Anzeigefenster / Rechtsklick = Öffnen mit Standardprogramm", 10, 155, 480, 16)
;~ GUICtrlSetFont($idL_Clickhint, 9.5)
GUICtrlSetColor($idL_Clickhint, $FontThemeColor)
GUICtrlSetState($idL_Clickhint, $GUI_HIDE)

Global $idLV_MainGUI = GUICtrlCreateListView("Datei(en) mit Treffer(n)", 10, 175, 480, 150, -1, $LVS_EX_INFOTIP + $LVS_EX_FULLROWSELECT + $LVS_EX_DOUBLEBUFFER)
$hLV_MainGUI = GUICtrlGetHandle($idLV_MainGUI)
_GUICtrlListView_SetColumnWidth($idLV_MainGUI, 0, 453)

Global $idL_Preview = GUICtrlCreateLabel("Treffer-Vorschau:", 10, 315, 480, 16)

Global $idLE_LinesMainGUI = _GUICtrlRichEdit_Create($hMainGUI, "", 10, 335, 480, 145, BitOR($ES_READONLY, $ES_MULTILINE, $WS_VSCROLL))
_GUICtrlRichEdit_SetBkColor($idLE_LinesMainGUI, 0xF0F0F0)


Global $idL_Files = GUICtrlCreateLabel("", 10, 325, 105, 14) ; Controls für Infos in der Statusbar.
Global $idL_Hits = GUICtrlCreateLabel("555", 135, 325, 100, 14)
Global $idL_Ignored = GUICtrlCreateLabel("", 255, 325, 150, 14)
Global $idL_Time = GUICtrlCreateLabel("", 400, 325, 150, 14)

Global $hStatus = _GUICtrlStatusBar_Create($hMainGUI)
_GUICtrlStatusBar_SetMinHeight($hStatus, 13)

Global $aParts[4] = [115, 235, 405, 550]
_GUICtrlStatusBar_SetParts($hStatus, $aParts)
_GUICtrlStatusBar_EmbedControl($hStatus, 0, GUICtrlGetHandle($idL_Files), 4)
_GUICtrlStatusBar_EmbedControl($hStatus, 1, GUICtrlGetHandle($idL_Hits), 4)
_GUICtrlStatusBar_EmbedControl($hStatus, 2, GUICtrlGetHandle($idL_Ignored), 4)
_GUICtrlStatusBar_EmbedControl($hStatus, 3, GUICtrlGetHandle($idL_Time), 4)

GUICtrlSetState($idB_Search, $GUI_FOCUS)
#EndRegion MainGUI ; Das Hauptfenster

#Region $hProgressGUI
Global $hProgressGUI = GUICreate("", 400, 68, $iMainXPos + $iMainWidth / 2 - 200, $iMainYPos + $iMainHeight / 2 - 34, $WS_POPUPWINDOW, -1, $hMainGUI) ; Fortschrittsanzeige
$idProgress = GUICtrlCreateProgress(10, 12, 380, 36, $PBS_MARQUEE + $PBS_SMOOTH)
$idL_Abort = GUICtrlCreateLabel('Datenbank wird geladen..', 10, 50, 390, 15)
;~ 		WinMove($hProgressGUI, '', $iMainXPos + $iMainWidth / 2 - 200, $iMainYPos + $iMainHeight / 2 - 34)

#EndRegion $hProgressGUI

#Region DocGUI ; In diesem Fenster werden Texte angezeigt.

$iDocWidth = IniRead($hIni, "Position", "Docw", "730")
$iDocHeight = IniRead($hIni, "Position", "Doch", "500")

$iXPos = IniRead($hIni, "Position", "Docx", "")
$iYPos = IniRead($hIni, "Position", "Docy", "")


$hDocGUI = GUICreate("", $iDocWidth, $iDocHeight, $iXPos, @DesktopHeight + $iYPos, $WS_SIZEBOX + $WS_MAXIMIZEBOX)
GUISetFont(14, 500, 0, "Segoe UI", $hDocGUI, 5)
$id_DocTxtField = _GUICtrlRichEdit_Create($hDocGUI, "", 10, 10, $iDocWidth - 30, $iDocHeight - 100, BitOR($ES_READONLY, $ES_MULTILINE, $WS_VSCROLL))

$idL_DocHits = GUICtrlCreateLabel("0 Treffer", 300, $iDocHeight - 60, 135, 40)
$idB_DocNext = GUICtrlCreateButton("Vor", 155, $iDocHeight - 70, 135, 40)
$idB_DocPrev = GUICtrlCreateButton("Zurück", 10, $iDocHeight - 70, 135, 40)
$idB_DocZoomUp = GUICtrlCreateButton("Zoom +", $iDocWidth - 150, $iDocHeight - 70, 135, 40)
$idB_DocZoomDown = GUICtrlCreateButton("Zoom -", $iDocWidth - 300, $iDocHeight - 70, 135, 40)

WinMove($hDocGUI, "", $iXPos, $iYPos, $iDocWidth, $iDocHeight)
#EndRegion DocGUI ; In diesem Fenster werden Texte angezeigt.

#Region ListGUI ; In diesem Fenster werden Tabellen angezeigt.

$iDocWidth = IniRead($hIni, "Position", "Listw", "800")
$iDocHeight = IniRead($hIni, "Position", "Listh", "500")
$iXPos = IniRead($hIni, "Position", "Listx", "0")
$iYPos = IniRead($hIni, "Position", "Listy", "0")

Opt("GUIResizeMode", 2 + 256 + 512 + 64) ; Standard Resizing-Verhalten der Controls.

$hListGUI = GUICreate("", $iDocWidth, $iDocHeight, $iXPos, $iYPos, $WS_SIZEBOX + $WS_MAXIMIZEBOX + $LVS_LIST)
GUISetFont(14, 500, 0, "Segoe UI", $hListGUI, 5)

$idB_ListExpand = GUICtrlCreateButton("Ausklappen", 10, $iDocHeight - 70, 135, 40)
$idB_ListPrev = GUICtrlCreateButton("Zurück", 155, $iDocHeight - 70, 135, 40)
$idB_ListNext = GUICtrlCreateButton("Vor", 300, $iDocHeight - 70, 135, 40)
$idL_ListHits = GUICtrlCreateLabel("0 Treffer", 445, $iDocHeight - 45, 135, 15)
GUICtrlSetFont(-1, 8.5, 400, "", "Segoe UI", 5)
$idL_ListClick = GUICtrlCreateLabel("Mit Doppelklick in Zwischenablage: ", 445, $iDocHeight - 65, 1050, 15)
GUICtrlSetFont(-1, 8.5, 400, "", "Segoe UI", 5)

$idLV_ListArrays = GUICtrlCreateListView("", 10, 5, $iDocWidth - 20, $iDocHeight - 80, -1) ; Mit der _WM_NOTIFY-Funktion zum SubItem-Klick klappt das nicht. Da müssen die Stile wieder weg.
GUICtrlSetFont(-1, 10, 400, "", "Segoe UI", 5)
_GUICtrlListView_SetExtendedListViewStyle($idLV_ListArrays, BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_DOUBLEBUFFER, $LVS_EX_GRIDLINES))


GUICtrlSetResizing($idLV_ListArrays, 102) ; Resizing-Verhalten der Listview.

#EndRegion ListGUI ; In diesem Fenster werden Tabellen angezeigt.

#Region AboutGUI ; In diesem Fenster ist der Hinweis auf XPDF-Tools hinterlegt.

Local $hAboutGUI = GUICreate("", 500, 465, -1, -1, -1, -1, $hMainGUI)
GUICtrlSetDefColor($FontThemeColor, $hAboutGUI)
Local $idB_About_Close = GUICtrlCreateButton("Zurück", 183, 400, 135, 40)

GUICtrlCreateLabel($sAppName, 0, 15, 500, 40, 0x01)
GUICtrlSetFont(-1, 15.5, 600, "", "Segoe UI", 5)

GUICtrlCreateLabel("Dieses Programm durchsucht Dateien in einer ausgewählten Ordnerstruktur nach Suchbegriffen.", 15, 60, 470, 40, 0x01)
GUICtrlSetFont(-1, 10.5, 500, "", "Segoe UI", 5)

GUICtrlCreateLabel("Unterstützte Dateiformate sind:" & @CRLF & "DOC, DOCX, XLS, XLSX, CSV, PDF sowie eine unvollständige und erweiterbare Liste aller per Texteditor lesbaren Dateien." & @CRLF & "(..\Textsuche-Data\unterstützte Textdatei-Typen.txt)", 15, 110, 470, 195, 0x01)
GUICtrlSetFont(-1, 10.5, 500, "", "Segoe UI", 5)

GUICtrlCreateLabel("Hinweis:", 15, 210, 470, 20, 0x01)
GUICtrlSetFont(-1, 12.5, 500, "", "Segoe UI", 5)

GUICtrlCreateLabel('Zum Auslesen von PDF wird das externe Programm "pdftotext.exe" genutzt. Dieses steht unter der GNU General Public License (GPL). ' & @CRLF _
		 & "Der Quelltext kann eingesehen werden auf: ", 15, 245, 470, 60, 0x01)
GUICtrlSetFont(-1, 10.5, 500, "", "Segoe UI", 5)



$idL_XPDFLink = GUICtrlCreateLabel("http://www.foolabs.com/xpdf/", 15, 315, 470, 20, 0x01)
GUICtrlSetFont(-1, 12.5, 500, 4, "Segoe UI", 5)
#EndRegion AboutGUI ; In diesem Fenster ist der Hinweis auf XPDF-Tools hinterlegt.


GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY") ; Registriere die Funktion zum Reagiern auf Mausklicks.
GUIRegisterMsg($WM_GETMINMAXINFO, "_WM_GETMINMAXINFO") ; Registriere die Funktion zum Erzwingen der festgelegten Mindestgröße.
GUIRegisterMsg($WM_SIZE, "_WM_SIZE") ; Registriere die Funktion zum Reagieren auf Größenänderungen.
GUIRegisterMsg($WM_MOVE, "_WM_MOVE") ; Registriere die Funktion zum Reagieren auf Positionsänderungen.


#Region Fensterposition bei Programmstart
If $iMainWidth >= 980 Then ; Wenn die GUI beim Start breit genug ist, werden die oberen Controls in einer Reihe angezeigt.
	GUICtrlSetPos($idCombo_SearchString, 500, 20)
	GUICtrlSetPos($idB_Search, 825, 20)
	GUICtrlSetPos($idL_Clickhint, 10, 85)
	GUICtrlSetPos($idLV_MainGUI, 10, 105)
EndIf

WinMove($hMainGUI, "", $iMainXPos, $iMainYPos, $iMainWidth, $iMainHeight) ; Initial wird die Hauptfenster Position und Größe gesetzt und einige Controls richtig positioniert.
GUICtrlSetPos($idL_Files, 10, $iMainHeight - 18, 105, 14)
GUICtrlSetPos($idL_Hits, 135, $iMainHeight - 18, 100, 14)
GUICtrlSetPos($idL_Ignored, 255, $iMainHeight - 18, 150, 16)
GUICtrlSetPos($idL_Time, 400, $iMainHeight - 18, 100, 14)
GUICtrlSetState($idCombo_SearchString, $GUI_FOCUS)


If StringInStr($CmdLineRaw, "/min") Then ; Wenn das Programm mit Windows gestartet wird, wird der Parameter /min mitgegeben. Hier wird das ausgewertet und das Fenster gegebenenfalls minimiert.
	If IniRead($hIni, "Settings", "Minimiere in Tray", "") Then ; Minimiere in Tray == Verstecke das Fenster.
		GUISetState(@SW_HIDE, $hMainGUI)
	Else
		GUISetState(@SW_SHOWMINIMIZED, $hMainGUI)
	EndIf
Else
	If IniRead($hIni, "Position", "MainMax", "") == "1" Then
		GUISetState(@SW_SHOWMAXIMIZED, $hMainGUI) ; Wenn letzte Fensterposition maximiert war.
	Else
		GUISetState(@SW_SHOW, $hMainGUI)
	EndIf
EndIf
#EndRegion Fensterposition bei Programmstart


#Region SQLite-Startup ; SQLite wird gestartet und der Inhalt der Datenbank in das Array $aSQLFiles (gespeicherte Dateien und Inhalte) und das Array $aSQLSearchStrings (genutze Suchbegriffe) gelesen.
Global $aWinPos = WinGetPos($hMainGUI)
;~ SplashTextOn($sAppName, 'Datenbank wird geladen..', 400, 68, $aWinPos[0] + $aWinPos[2] / 2 - 200, $aWinPos[1] + $aWinPos[3] / 2 - 34, $DLG_NOTITLE + $DLG_TEXTVCENTER, 'Segoe UI')
GUISetState(@SW_SHOW, $hProgressGUI)
$hProgress = GUICtrlGetHandle($idProgress)
_SendMessage($hProgress, $PBM_SETMARQUEE, True, 0) ; Der Stil 'marquee' funktioniert bei Windows XP und neuer
$aWinPos = 0
FileChangeDir($sWorkDir)
If @AutoItX64 Then
	_SQLite_Startup($sWorkDir & "SQLite3_x64.dll", False, 1)
Else
	_SQLite_Startup($sWorkDir & "SQLite3_x86.dll", False, 1)
EndIf
ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & "_SQLite_LibVersion=" & _SQLite_LibVersion() & @CRLF)
$hDB = _SQLite_Open($sWorkDir & $sAppName & ".db")
_SQLite_Exec(-1, "CREATE TABLE IF NOT EXISTS FILES (MODIFIED,FULLPATH,CONTENT);")
$iRval = _SQLite_GetTable2d(-1, "SELECT MODIFIED,FULLPATH FROM FILES;", $aSQLFiles, $iRows, $iColumns)
If $iRval <> $SQLITE_OK Then ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & "SQLite Error: " & $iRval & " - " & _SQLite_ErrMsg() & @CRLF)
;~ _ArrayDisplay($aSQLFiles)
_ArrayDelete($aSQLFiles, 0) ; Entferne die Tabellenküberschriften aus dem Array.

Global $aSQLSearchStrings, $sSQLSearchStrings
_SQLite_Exec(-1, "CREATE TABLE IF NOT EXISTS HISTORY (SEARCHSTRINGS);")
$iRval = _SQLite_GetTable(-1, "SELECT * FROM HISTORY;", $aSQLSearchStrings, $iRows, $iColumns)
If $iRval <> $SQLITE_OK Then ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & "SQLite Error: " & $iRval & " - " & _SQLite_ErrMsg() & @CRLF)

For $i = 2 To $aSQLSearchStrings[0] ; Hier wird die Combobox $idCombo_SearchString mit den Suchbegriffen gefüllt.
	$sSQLSearchStrings &= $aSQLSearchStrings[$i] & "|"
Next
GUICtrlSetData($idCombo_SearchString, $sSQLSearchStrings, "")
;~ SplashOff()
GUISetState(@SW_HIDE, $hProgressGUI)
#EndRegion SQLite-Startup ; SQLite wird gestartet und der Inhalt der Datenbank in das Array $aSQLFiles (gespeicherte Dateien und Inhalte) und das Array $aSQLSearchStrings (genutze Suchbegriffe) gelesen.


If UBound($aSQLFiles) = 0 Then ; Wenn noch keine Dateien in der DB sind, werden die Controls angepasst.
	GUICtrlSetState($idC_DBonly, $GUI_UNCHECKED)
;~ 	GUICtrlSetState($idC_DBonly, $GUI_DISABLE)
	IniDelete($hIni, "Settings", "Datenbanksuche")
	GUICtrlSetState($idC_DBcleaning, $GUI_UNCHECKED)
;~ 	GUICtrlSetState($idC_DBcleaning, $GUI_DISABLE)
	IniDelete($hIni, "Settings", "Datenbankbereinigung")
EndIf


_MainLoop()

Func _MainLoop() ; Die Schleife, mit den Reaktionen auf die Buttonclicks u.s.w.

	; Ganz unten in der Schleife werden die Tasten Hoch/Runter ausgewertet, um in der Trefferliste zu navigieren.
	; $iLV_MainIndex = -1 als Hinweis, die Liste ist nicht markiert.
	Local $iLV_MainIndex = -1

	While 1

		; Tray Menü-Klicks
		Switch TrayGetMsg()
			Case $TRAY_EVENT_PRIMARYDOWN ; Minimieren/Wiederherstellen des Hauptfensters durch Klick auf Tray-Icon.
				Local $iWinStateMainGUI = WinGetState($hMainGUI)
				If $iWinStateMainGUI = 7 Or $iWinStateMainGUI = 15 Or $iWinStateMainGUI = 39 Then
					If IniRead($hIni, "Settings", "Minimiere in Tray", "") Then
						GUISetState(@SW_HIDE, $hMainGUI)
					Else
						GUISetState(@SW_MINIMIZE, $hMainGUI)
					EndIf
				Else
					If IniRead($hIni, "Settings", "Minimiere in Tray", "") Then
						GUISetState(@SW_SHOW, $hMainGUI)
					Else
						GUISetState(@SW_RESTORE, $hMainGUI)
					EndIf
				EndIf
			Case $idT_Show ; Anzeigen
				GUISetState(@SW_SHOW, $hMainGUI)
				GUISetState(@SW_RESTORE, $hMainGUI)
			Case $idT_Close ; Programm wird durch Beenden im Programmfenster nur minimiert.
				If BitAND(TrayItemGetState($idT_Close), $TRAY_CHECKED) Then
					GUICtrlSetState($idM_Close, $GUI_UNCHECKED)
					TrayItemSetState($idT_Close, $TRAY_UNCHECKED)
					IniDelete($hIni, "Settings", "Minimieren statt beenden")
				Else
					GUICtrlSetState($idM_Close, $GUI_CHECKED)
					TrayItemSetState($idT_Close, $TRAY_CHECKED)
					IniWrite($hIni, "Settings", "Minimieren statt beenden", "1")
				EndIf
			Case $idT_Minimize ; Minimieren
				If BitAND(TrayItemGetState($idT_Minimize), $TRAY_CHECKED) Then
					GUICtrlSetState($idM_Minimize, $GUI_UNCHECKED)
					TrayItemSetState($idT_Minimize, $TRAY_UNCHECKED)
					IniDelete($hIni, "Settings", "Minimiere in Tray")
				Else
					GUICtrlSetState($idM_Minimize, $GUI_CHECKED)
					TrayItemSetState($idT_Minimize, $TRAY_CHECKED)
					IniWrite($hIni, "Settings", "Minimiere in Tray", "1")
				EndIf
			Case $idT_Start ; Autostart
				If BitAND(TrayItemGetState($idT_Start), $TRAY_CHECKED) Then
					If @Compiled Then
						RegDelete('HKCU\Software\Microsoft\Windows\CurrentVersion\Run', $sAppName)
						GUICtrlSetState($idM_Start, $GUI_UNCHECKED)
						TrayItemSetState($idT_Start, $TRAY_UNCHECKED)
						IniDelete($hIni, "Settings", "Autostart")
					EndIf
				Else
					If @Compiled Then
						RegWrite('HKCU\Software\Microsoft\Windows\CurrentVersion\Run', $sAppName, 'REG_SZ', @ScriptFullPath & ' /Min')
						GUICtrlSetState($idM_Start, $GUI_CHECKED)
						TrayItemSetState($idT_Start, $TRAY_CHECKED)
						IniWrite($hIni, "Settings", "Autostart", "1")
					EndIf
				EndIf
			Case $idT_Exit ; Programm beenden
				_Exit()
		EndSwitch
		; Ende Tray Menü-Klicks

		$nMsg = GUIGetMsg()
		Switch $nMsg
			Case $GUI_EVENT_MINIMIZE
				If BitAND(WinGetState($hMainGUI), 2) Then
					If BitAND(TrayItemGetState($idT_Close), $TRAY_CHECKED) Then
						If BitAND(TrayItemGetState($idT_Minimize), $TRAY_CHECKED) Then
							GUISetState(@SW_HIDE, $hMainGUI)
						Else
							GUISetState(@SW_MINIMIZE, $hMainGUI)
						EndIf
					EndIf
				EndIf
			Case $GUI_EVENT_CLOSE ; Programm beenden oder vorhandene andere Fenster schließen.
				If BitAND(WinGetState($hDocGUI), 2) Then ; Wenn die Dokumentenanzeige aktiv ist, wird sie geschlossen und die Position gespeichert.
					_GUICtrlEdit_SetText($id_DocTxtField, "")
					If Not BitAND(WinGetState($hDocGUI), 32) Then
						Local $aPos = WinGetPos($hDocGUI)
						If Not @error Then
							IniWrite($hIni, "Position", "Docx", $aPos[0])
							IniWrite($hIni, "Position", "Docy", $aPos[1])
							IniWrite($hIni, "Position", "Docw", $aPos[2])
							IniWrite($hIni, "Position", "Doch", $aPos[3])
							IniWrite($hIni, "Position", "DocMax", "0")
						EndIf
					Else
						IniWrite($hIni, "Position", "DocMax", "1")
					EndIf
					GUISetState(@SW_HIDE, $hDocGUI)
				ElseIf BitAND(WinGetState($hListGUI), 2) Then ; Wenn die Tabellenanzeige aktiv ist, wird sie geschlossen und die Position gespeichert.
					_GUICtrlEdit_SetText($id_DocTxtField, "")
					If Not BitAND(WinGetState($hListGUI), 32) Then
						Local $aPos = WinGetPos($hListGUI)
						If Not @error Then
							IniWrite($hIni, "Position", "Listx", $aPos[0])
							IniWrite($hIni, "Position", "Listy", $aPos[1])
							IniWrite($hIni, "Position", "Listw", $aPos[2])
							IniWrite($hIni, "Position", "Listh", $aPos[3])
							IniWrite($hIni, "Position", "ListMax", "0")
						EndIf
					Else
						IniWrite($hIni, "Position", "ListMax", "1")
					EndIf
					GUISetState(@SW_HIDE, $hListGUI)
				ElseIf BitAND(WinGetState($hAboutGUI), 2) Then ; $WIN_STATE_VISIBLE Wenn das Hinweisfenster aktiv ist, wird sie geschlossen und die Position gespeichert.
					GUISetState(@SW_ENABLE, $hMainGUI)
					GUISetState(@SW_HIDE, $hAboutGUI)
				Else
					If BitAND(WinGetState($hMainGUI), 2) Then
						If Not BitAND(WinGetState($hMainGUI), 32) Then
							$aGuiPos = WinGetPos($hMainGUI)
							IniWrite($hIni, "Position", "Mainx", $aGuiPos[0])
							IniWrite($hIni, "Position", "Mainy", $aGuiPos[1])
							IniWrite($hIni, "Position", "Mainwidth", $aGuiPos[2])
							IniWrite($hIni, "Position", "Mainheight", $aGuiPos[3])
							IniWrite($hIni, "Position", "MainMax", "0")
						Else
							IniWrite($hIni, "Position", "MainMax", "1")
						EndIf
					EndIf
					If BitAND(TrayItemGetState($idT_Close), $TRAY_CHECKED) Then
						If BitAND(TrayItemGetState($idT_Minimize), $TRAY_CHECKED) Then
							GUISetState(@SW_HIDE, $hMainGUI)
						Else
							GUISetState(@SW_MINIMIZE, $hMainGUI)
						EndIf
					Else
						_Exit()
					EndIf
				EndIf


				; Controls der $hMainGUI ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

			Case $idD_Delete ; Eintrag aus der Suchbegriffs-Liste per "Entf"-Taste löschen.
				If _GUICtrlComboBox_GetDroppedState($idCombo_SearchString) Then
					Local $sDeleteString
					_GUICtrlComboBox_GetLBText($idCombo_SearchString, _GUICtrlComboBox_GetCurSel($idCombo_SearchString), $sDeleteString)
					_GUICtrlComboBox_DeleteString($idCombo_SearchString, _GUICtrlComboBox_GetCurSel($idCombo_SearchString))
					_SQLite_Exec(-1, "DELETE FROM HISTORY WHERE SEARCHSTRINGS = '" & $sDeleteString & "';")
				EndIf
			Case $idM_Umlauts
				If BitAND(GUICtrlRead($idM_Umlauts), $GUI_CHECKED) = $GUI_CHECKED Then
					GUICtrlSetState($idM_Umlauts, $GUI_UNCHECKED)
					IniWrite($hIni, "Settings", "Umlaute", "0")
				Else
					GUICtrlSetState($idM_Umlauts, $GUI_CHECKED)
					IniWrite($hIni, "Settings", "Umlaute", "1")
				EndIf
			Case $idM_WriteStepsDB
				If BitAND(GUICtrlRead($idM_WriteStepsDB), $GUI_CHECKED) = $GUI_CHECKED Then
					GUICtrlSetState($idM_WriteStepsDB, $GUI_UNCHECKED)
					IniWrite($hIni, "Settings", "Schreibe je 500 eingelesene Dateien in DB", "0")
				Else
					GUICtrlSetState($idM_WriteStepsDB, $GUI_CHECKED)
					IniWrite($hIni, "Settings", "Schreibe je 500 eingelesene Dateien in DB", "1")
				EndIf
			Case $idM_Vacuum
				If BitAND(GUICtrlRead($idM_Vacuum), $GUI_CHECKED) = $GUI_CHECKED Then
					GUICtrlSetState($idM_Vacuum, $GUI_UNCHECKED)
					IniWrite($hIni, "Settings", "Vacuum", "0")
				Else
					GUICtrlSetState($idM_Vacuum, $GUI_CHECKED)
					IniWrite($hIni, "Settings", "Vacuum", "1")
				EndIf
			Case $idM_Close ; Programm wird durch Beenden im Programmfenster nur minimiert.
				If BitAND(GUICtrlRead($idM_Close), $GUI_CHECKED) = $GUI_CHECKED Then
					GUICtrlSetState($idM_Close, $GUI_UNCHECKED)
					TrayItemSetState($idT_Close, $TRAY_UNCHECKED)
					IniDelete($hIni, "Settings", "Minimieren statt beenden")
				Else
					GUICtrlSetState($idM_Close, $GUI_CHECKED)
					TrayItemSetState($idT_Close, $TRAY_CHECKED)
					IniWrite($hIni, "Settings", "Minimieren statt beenden", "1")
				EndIf
			Case $idM_Minimize ; Minimieren in Traybereich ja/nein
				If BitAND(GUICtrlRead($idM_Minimize), $GUI_CHECKED) = $GUI_CHECKED Then
					GUICtrlSetState($idM_Minimize, $GUI_UNCHECKED)
					TrayItemSetState($idT_Minimize, $TRAY_UNCHECKED)
					IniDelete($hIni, "Settings", "Minimiere in Tray")

				Else
					GUICtrlSetState($idM_Minimize, $GUI_CHECKED)
					TrayItemSetState($idT_Minimize, $TRAY_CHECKED)
					IniWrite($hIni, "Settings", "Minimiere in Tray", "1")
				EndIf
			Case $idM_Start ; Autostart
				If BitAND(GUICtrlRead($idM_Start), $GUI_CHECKED) = $GUI_CHECKED Then
					If @Compiled Then
						RegDelete('HKCU\Software\Microsoft\Windows\CurrentVersion\Run', $sAppName)
						GUICtrlSetState($idM_Start, $GUI_UNCHECKED)
						TrayItemSetState($idT_Start, $TRAY_UNCHECKED)
						IniDelete($hIni, "Settings", "Autostart")
					EndIf
				Else
					If @Compiled Then
						RegWrite('HKCU\Software\Microsoft\Windows\CurrentVersion\Run', $sAppName, 'REG_SZ', @ScriptFullPath & ' /Min')
						GUICtrlSetState($idM_Start, $GUI_CHECKED)
						TrayItemSetState($idT_Start, $TRAY_CHECKED)
						IniWrite($hIni, "Settings", "Autostart", "1")
					EndIf
				EndIf
			Case $idM_ResetDB ; Datenbank zurücksetzen
				_SQLite_Exec(-1, "DELETE FROM FILES;")
				_SQLite_Exec(-1, "VACUUM;")
				ReDim $aSQLFiles[0][2]
				Local $aPos = WinGetPos($hMainGUI)
				Local $iX = $aPos[0] + $aPos[2] / 2 - 125 ; x+Breite MainGUI-Breite Splash / 2
				Local $iY = $aPos[1] + $aPos[3] / 2 - 25 ; y+Höhe MainGUI-Höhe Splash / 2
				SplashTextOn("", "Datenbank geleert", 250, 50, $iX, $iY, $DLG_CENTERONTOP + $DLG_NOTITLE, "Segoe UI")
				Sleep(1000)
				SplashOff()
			Case $idM_ResetHist ; Suchbegriffsliste löschen
				_SQLite_Exec(-1, "DELETE FROM HISTORY;")
				$sSQLSearchStrings = ""
				GUICtrlSetData($idCombo_SearchString, "")
				Local $aPos = WinGetPos($hMainGUI)
				Local $iX = $aPos[0] + $aPos[2] / 2 - 125 ; x+Breite MainGUI-Breite Splash / 2
				Local $iY = $aPos[1] + $aPos[3] / 2 - 25 ; y+Höhe MainGUI-Höhe Splash / 2
				SplashTextOn("", "Suchbegriffe gelöscht", 250, 50, $iX, $iY, $DLG_CENTERONTOP + $DLG_NOTITLE, "Segoe UI")
				Sleep(1000)
				SplashOff()
			Case $idM_About ; Menü "?"
				Local $aMGpos = WinGetPos($hMainGUI)
				WinMove($hAboutGUI, "", $aMGpos[0] + 5, $aMGpos[1])
				GUISetState(@SW_DISABLE, $hMainGUI)
				GUISetState(@SW_SHOW, $hAboutGUI)
			Case $idB_About_Close ; Schließen Button im $hAboutGUI-Fenster.
				GUISetState(@SW_ENABLE, $hMainGUI)
				GUISetState(@SW_HIDE, $hAboutGUI)
			Case $idL_XPDFLink
				ShellExecute("http://www.foolabs.com/xpdf/")
			Case $idB_StartFolder ; Startordner Button.
				$sStartFolder = IniRead($hIni, "Settings", "Startordner", "")
				Local $sFileSelectFolder = FileSelectFolder("Wählen Sie den Ausgangspunkt Ihrer Suche", $sStartFolder)
				If Not @error Then
					$sLabeltext = $sFileSelectFolder
					If StringLen($sFileSelectFolder) >= 26 Then
						$aSFSplit = StringSplit($sFileSelectFolder, "\")
						If Not @error Then $sLabeltext = "..\" & $aSFSplit[$aSFSplit[0]]
					EndIf
					GUICtrlSetData($idL_StartFolder, $sLabeltext)
					GUICtrlSetTip($idL_StartFolder, $sFileSelectFolder, "Ausgangspunkt der Suche")
					IniWrite($hIni, "Settings", "Startordner", $sFileSelectFolder)
					If $sStartFolder <> $sFileSelectFolder Then
						IniDelete($hIni, "Settings", "Ignoriertes")
						GUICtrlSetData($idL_Ignore, "Ignorierte Elemente: 0")
						GUICtrlSetTip($idL_Ignore, "", "Ignorierte Elemente")
						GUICtrlSetData($idL_Files, "")
						GUICtrlSetState($idC_DBonly, $GUI_UNCHECKED)
						IniDelete($hIni, "Settings", "Datenbanksuche")
					EndIf
					If BitAND(GUICtrlRead($idC_Subfolders), $GUI_CHECKED) And Not BitAND(GUICtrlRead($idC_DBonly), $GUI_CHECKED) Then GUICtrlSetState($idB_Ignore, $GUI_ENABLE)
					$sStartFolder = $sFileSelectFolder
				EndIf
			Case $idB_Ignore ; Ignorierte Ordner Button.
				$sRet = _CFF_RegMsg() ; Register handlers - Siehe ChooseFileFolder_MOD UDF.
				$aIgnoreToIni = StringSplit(IniRead($hIni, "Settings", "Ignoriertes", ""), "|", 2)

				_CFF_SetPreCheck($aIgnoreToIni) ; Ignorierte Elemente werden angehakt.

				$sRet = _CFF_Choose("Zu Ignorierende Elemente auswählen", -300, 500, -1, -1, $sStartFolder, Default, 2 + 4 + 8 + 16 + 512, -1, $hMainGUI) ; Die Auswahl-GUI wird geöffnet  - Siehe ChooseFileFolder_MOD UDF.

				If @error <> 5 Then ; Falls nicht abgebrochen wurde.
					If $sRet Then ; Wenn etwas ausgewählt wurde.
						IniWrite($hIni, "Settings", "Ignoriertes", $sRet)
						$aRet = StringSplit($sRet, "|")
						$sRet = ""
						For $i = 1 To $aRet[0]
							$sRet &= $aRet[$i] & @CRLF
						Next
						GUICtrlSetData($idL_Ignore, "Ignorierte Elemente: " & $aRet[0])
						GUICtrlSetTip($idL_Ignore, $sRet, "Ignorierte Elemente")
						GUICtrlSetData($idL_Files, "")
					Else
						IniWrite($hIni, "Settings", "Ignoriertes", "")
						GUICtrlSetData($idL_Ignore, "Ignorierte Elemente: " & "0")
						GUICtrlSetTip($idL_Ignore, "")
						GUICtrlSetData($idL_Files, "")
					EndIf
				EndIf
				GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")
			Case $idB_Search ; Button Suche
				GUICtrlSetState($idL_Clickhint, $GUI_HIDE)
				ReDim $aSearchString[1]
				$aSearchString[0] = GUICtrlRead($idCombo_SearchString)

				If $aSearchString[0] <> "" Then
					GUISetState($hMainGUI, @SW_DISABLE)
					_SearchAndProgress()
					GUISetState($hMainGUI, @SW_ENABLE)
				Else
					_HintBoxes_By_Handle($hMainGUI, $idCombo_SearchString, 5, 500)
				EndIf
			Case $idC_Subfolders ; Checkbox Unterordner
				If BitAND(GUICtrlRead($idC_Subfolders), $GUI_CHECKED) Then ; Wenn Subfolders abgewählt wird, wird die Liste ignorierter Unterordner gelöscht.
					IniWrite($hIni, "Settings", "inklusive Unterordner", "1")
					GUICtrlSetState($idC_Subfolders, $GUI_CHECKED)
					If $sStartFolder <> "" And Not BitAND(GUICtrlRead($idC_DBonly), $GUI_CHECKED) Then GUICtrlSetState($idB_Ignore, $GUI_ENABLE)
				Else
					GUICtrlSetState($idC_Subfolders, $GUI_UNCHECKED)
					IniDelete($hIni, "Settings", "inklusive Unterordner")
;~ 					GUICtrlSetState($idB_Ignore, $GUI_DISABLE)
;~ 					IniWrite($hIni, "Settings", "Ignoriertes", "")
;~ 					GUICtrlSetData($idL_Ignore, "Ignorierte Elemente: " & "0")
;~ 					GUICtrlSetTip($idL_Ignore, "")
;~ 					GUICtrlSetData($idL_Files, "")
				EndIf
			Case $idC_DBcleaning ; Checkbox Datenbankbereinigung
				If BitAND(GUICtrlRead($idC_DBcleaning), $GUI_CHECKED) Then ; Wenn Datenbankbereinigung markiert ist..
					IniWrite($hIni, "Settings", "Datenbankbereinigung", "1")
					GUICtrlSetState($idC_DBcleaning, $GUI_CHECKED)
				Else
					GUICtrlSetState($idC_DBcleaning, $GUI_UNCHECKED)
					IniDelete($hIni, "Settings", "Datenbankbereinigung")
				EndIf
			Case $idC_DBonly ; Checkbox Datenbanksuche
				If BitAND(GUICtrlRead($idC_DBonly), $GUI_CHECKED) Then ; Wenn Datenbanksuche markiert ist..
					IniWrite($hIni, "Settings", "Datenbanksuche", "1")
					GUICtrlSetState($idC_DBonly, $GUI_CHECKED)
					GUICtrlSetState($idC_Subfolders, $GUI_DISABLE)
					GUICtrlSetState($idB_Ignore, $GUI_DISABLE)
					GUICtrlSetState($idC_DBcleaning, $GUI_DISABLE)
				Else
					GUICtrlSetState($idC_DBonly, $GUI_UNCHECKED)
					IniDelete($hIni, "Settings", "Datenbanksuche")
					GUICtrlSetState($idC_Subfolders, $GUI_ENABLE)
					GUICtrlSetState($idB_Ignore, $GUI_ENABLE)
					GUICtrlSetState($idC_DBcleaning, $GUI_ENABLE)
				EndIf

				; Ende Controls der $hMainGUI ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


				; Controls der $hListGUI ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

			Case $idB_ListNext ; Button Nächster in der Tabellenanzeige
				If $iListposition = Int($aAllHits[0]) Then
					$iListposition = 1
				Else
					$iListposition += 1
				EndIf
				_GUICtrlListView_EnsureVisible($idLV_ListArrays, $aAllHits[$iListposition])
				_GUICtrlListView_SetItemFocused($idLV_ListArrays, $aAllHits[$iListposition])
				_GUICtrlListView_ClickItem($idLV_ListArrays, $aAllHits[$iListposition])
			Case $idB_ListExpand ; Button Ausklappen/Einklappen in der Tabellenanzeige
				_GUICtrlListView_BeginUpdate($idLV_ListArrays)

				If $bExpanded Then
					For $i = 0 To _GUICtrlListView_GetColumnCount($idLV_ListArrays)
						_GUICtrlListView_SetColumnWidth($idLV_ListArrays, $i, 200)
					Next
					GUICtrlSetData($idB_ListExpand, "Ausklappen")
				Else
					For $i = 0 To _GUICtrlListView_GetColumnCount($idLV_ListArrays)
						_GUICtrlListView_SetColumnWidth($idLV_ListArrays, $i, $LVSCW_AUTOSIZE)
					Next
					GUICtrlSetData($idB_ListExpand, "Einklappen")
				EndIf
				_GUICtrlListView_EndUpdate($idLV_ListArrays)

				$bExpanded = Not $bExpanded
			Case $idB_ListPrev ; Button Zurück in der Tabellenanzeige
				If $iListposition = 1 Then
					$iListposition = Int($aAllHits[0])
				Else
					$iListposition -= 1
				EndIf
				_GUICtrlListView_EnsureVisible($idLV_ListArrays, $aAllHits[$iListposition])
				_GUICtrlListView_SetItemFocused($idLV_ListArrays, $aAllHits[$iListposition])
				_GUICtrlListView_ClickItem($idLV_ListArrays, $aAllHits[$iListposition])

				; Ende Controls der $hListGUI ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


				; Controls der $hDocGUI ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

			Case $idB_DocNext ; Button Nächster in der Dokumentenanzeige
				Local $aAllHitsSplit = StringSplit($aAllHits[$iListposition], "|")
				Local $iStringLen = StringLen($aAllHitsSplit[2])
				_GUICtrlRichEdit_PauseRedraw($id_DocTxtField)
				_GUICtrlRichEdit_SetSel($id_DocTxtField, $aAllHitsSplit[1], $aAllHitsSplit[1] + $iStringLen)
				_GUICtrlRichEdit_SetCharBkColor($id_DocTxtField, 0xFFE78F)
				If $iListposition = $aAllHits[0] Then
					$iListposition = 1
				Else
					$iListposition += 1
				EndIf
				$aAllHitsSplit = StringSplit($aAllHits[$iListposition], "|")
				_GUICtrlRichEdit_SetSel($id_DocTxtField, $aAllHitsSplit[1], $aAllHitsSplit[1] + $iStringLen)
				_GUICtrlRichEdit_SetCharBkColor($id_DocTxtField, 0xFFFF)
				ControlSend($hDocGUI, "", $id_DocTxtField, "{LEFT}") ; _GUICtrlRichEdit_HideSelection scheint nicht zu funktionieren, daher wird die Auswahl durch Cursor-Bewegung aufgehoben.
				_GUICtrlRichEdit_ResumeRedraw($id_DocTxtField)
			Case $idB_DocPrev ; Button Zurück in der Dokumentenanzeige
				Local $aAllHitsSplit = StringSplit($aAllHits[$iListposition], "|")
				Local $iStringLen = StringLen($aAllHitsSplit[2])
				_GUICtrlRichEdit_PauseRedraw($id_DocTxtField)
				_GUICtrlRichEdit_SetSel($id_DocTxtField, $aAllHitsSplit[1], $aAllHitsSplit[1] + $iStringLen)
				_GUICtrlRichEdit_SetCharBkColor($id_DocTxtField, 0xFFE78F)
				If $iListposition = 1 Then
					$iListposition = $aAllHits[0]
				Else
					$iListposition -= 1
				EndIf
				$aAllHitsSplit = StringSplit($aAllHits[$iListposition], "|")
				_GUICtrlRichEdit_SetSel($id_DocTxtField, $aAllHitsSplit[1], $aAllHitsSplit[1] + $iStringLen)
				_GUICtrlRichEdit_SetCharBkColor($id_DocTxtField, 0xFFFF)
				ControlSend($hDocGUI, "", $id_DocTxtField, "{LEFT}") ; _GUICtrlRichEdit_HideSelection scheint nicht zu funktionieren, daher wird die Auswahl durch Cursor-Bewegung aufgehoben.
				_GUICtrlRichEdit_ResumeRedraw($id_DocTxtField)
			Case $idB_DocZoomUp ; Button Zoom + in der Dokumentenanzeige
				$iFontsize += 1
				$iLength = _GUICtrlRichEdit_GetTextLength($id_DocTxtField, True, True)
				_GUICtrlRichEdit_PauseRedraw($id_DocTxtField)
				Local $aPos = _GUICtrlRichEdit_GetSel($id_DocTxtField) ; Ein möglicherweise markierter Textbereich wird erfasst.
				_GUICtrlRichEdit_SetSel($id_DocTxtField, 0, $iLength)
;~ 				_GUICtrlRichEdit_HideSelection($id_DocTxtField, True)
				_GUICtrlRichEdit_SetFont($id_DocTxtField, $iFontsize, "Segoe UI")
				_GUICtrlRichEdit_SetSel($id_DocTxtField, $aPos[0], $aPos[1]) ; Wenn ein Textbereich vorher markiert war, wird er nun wieder markiert.
				_GUICtrlRichEdit_ResumeRedraw($id_DocTxtField)
				IniWrite($hIni, "Font", "Edit", $iFontsize)
			Case $idB_DocZoomDown ; Button Zoom - in der Dokumentenanzeige
				If $iFontsize > 8.5 Then
					$iFontsize -= 1
					$iLength = _GUICtrlRichEdit_GetTextLength($id_DocTxtField, True, True)
					_GUICtrlRichEdit_PauseRedraw($id_DocTxtField)
					Local $aPos = _GUICtrlRichEdit_GetSel($id_DocTxtField)
					_GUICtrlRichEdit_SetSel($id_DocTxtField, 0, $iLength)
					_GUICtrlRichEdit_SetFont($id_DocTxtField, $iFontsize, "Segoe UI")
					_GUICtrlRichEdit_SetSel($id_DocTxtField, $aPos[0], $aPos[1])
					_GUICtrlRichEdit_ResumeRedraw($id_DocTxtField)
					IniWrite($hIni, "Font", "Edit", $iFontsize)
				EndIf

				; Ende Controls der $hDocGUI ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

		EndSwitch

		If _IsPressed(26) Or _IsPressed(28) Then ; Falls mit Pfeil oben oder unten durch die Ergebnisliste gegangen wird, soll die Treffervorschau aktualisiert werden.
			If BitAND(WinGetState($hMainGUI), 8) And _GUICtrlListView_GetSelectionMark($idLV_MainGUI) <> -1 Then
				If $iLV_MainIndex <> _GUICtrlListView_GetSelectedIndices($idLV_MainGUI) Then
					$iLV_MainIndex = _GUICtrlListView_GetSelectedIndices($idLV_MainGUI)
					$sFullPath = $sStartFolder & "\" & _GUICtrlListView_GetItemText($hLV_MainGUI, $iLV_MainIndex) ; Die ausgewählte Datei wird ermittelt.
					If $sFullPath <> $sStartFolder & "\" Then
						_GUICtrlListView_DeleteAllItems($idLE_LinesMainGUI) ; Listview wird geleert.
						_ShowLines($sFullPath)
					EndIf
				EndIf
			EndIf
		EndIf

	WEnd

EndFunc   ;==>_MainLoop



; ### Funktionen: Zentrale Suchfunktionen ###

Func _SearchAndProgress() ; Zentrale Suche.

	If $sStartFolder == "" Then Return MsgBox(0, $sAppName, "Wählen Sie erst einen Start-Ordner für die Suche aus", 4)
	If UBound($aSQLFiles) = 0 Then MsgBox(0, $sAppName, "Bei dieser ersten Suche werden alle Dateien in eine Datenbank eingelesen. Je nach Anzahl der Dateien kann der Vorgang mehrere Minuten in Anspruch nehmen.", 5)

	ReDim $aSQLResultFiles[0][3]

	_ArraySearch($aSQLSearchStrings, $aSearchString[0]) ; Wenn der neue Suchstring noch nicht in der Suchliste zu finden ist, wird er hinzugefügt.
	If @error Then
		_SQLite_Exec(-1, "INSERT INTO HISTORY VALUES ('" & $aSearchString[0] & "');") ; Ergebnisse werden in die DB geschrieben.
		$sSQLSearchStrings &= $aSearchString[0] & "|"
		_GUICtrlComboBox_AddString($idCombo_SearchString, $aSearchString[0])
		_ArrayAdd($aSQLSearchStrings, $aSearchString[0])
	EndIf

	Local $iHits = 0, $iIgnored = 0, $sIgnored, $aIndex, $sString, $bNotFound = True, $iAllSQLFiles = UBound($aSQLFiles), $iAllFiles
	Local $hTimer = TimerInit() ; ab hier wird die Dauer der Suche gestoppt.

	Local $bDBSearchOnly = False
	If BitAND(GUICtrlRead($idC_DBonly), $GUI_CHECKED) Then $bDBSearchOnly = True ; Wenn nur DB-Suche, werden die Dateien im Verzeichnis nicht geprüft.


	GUICtrlSetTip($idL_Ignored, "") ; Die evtl. vorhandenen Ergebnisse der vorherigen Suche werden gelöscht.
	_GUICtrlStatusBar_SetText($hStatus, "", 0)
	_GUICtrlStatusBar_SetText($hStatus, "", 1)
	_GUICtrlStatusBar_SetText($hStatus, "", 2)
	_GUICtrlStatusBar_SetText($hStatus, "", 3)
	_GUICtrlListView_DeleteAllItems($idLV_MainGUI)
	_GUICtrlRichEdit_SetText($idLE_LinesMainGUI, "")

	; Damit $hProgressGUI direkt an der richtigen Stelle angezeigt wird. Sonst gibt es einen kleinen Sprung beim Verschieben des Hauptfensters.
	Local $aWinPos = WinGetPos($hMainGUI) ; Beim Verschieben übernimmt WM_Move
	$iMainXPos = $aWinPos[0]
	$iMainYPos = $aWinPos[1]

	If $bDBSearchOnly Then ; Bei reiner DB-Suche, wird ein Fortschrittsbalken mit Marqee-Style angezeigt, statt Suche mit Fortschritt.

		$hProgressGUI = GUICreate("", 400, 68, $iMainXPos + $iMainWidth / 2 - 200, $iMainYPos + $iMainHeight / 2 - 34, $WS_POPUPWINDOW, -1, $hMainGUI) ; Fortschrittsanzeige
		$idProgress = GUICtrlCreateProgress(10, 12, 380, 36, $PBS_MARQUEE + $PBS_SMOOTH)
		$idL_Abort = GUICtrlCreateLabel('Datenbanksuche läuft.."', 10, 50, 390, 15)
		WinMove($hProgressGUI, '', $iMainXPos + $iMainWidth / 2 - 200, $iMainYPos + $iMainHeight / 2 - 34)
		GUISetState(@SW_SHOW)
		$hProgress = GUICtrlGetHandle($idProgress)
		_SendMessage($hProgress, $PBM_SETMARQUEE, True, 0) ; Der Stil 'marquee' funktioniert bei Windows XP und neuer
	Else
		HotKeySet("{ESC}", "_SetAbort") ; Escape-Taste zum Abbruch der Suche


		$hProgressGUI = GUICreate("", 400, 68, $iMainXPos + $iMainWidth / 2 - 200, $iMainYPos + $iMainHeight / 2 - 34, $WS_POPUPWINDOW, -1, $hMainGUI) ; Fortschrittsanzeige
		$idProgress = GUICtrlCreateProgress(10, 12, 380, 36)
		$idL_Abort = GUICtrlCreateLabel('Dateiliste wird erstellt...', 10, 50, 390, 15)
		GUISetState(@SW_SHOW)

		Local $bSubfolder = IniRead($hIni, "Settings", "inklusive Unterordner", "")
		Local $bWriteStep = False
		If BitAND(GUICtrlRead($idM_WriteStepsDB), $GUI_CHECKED) = $GUI_CHECKED Then $bWriteStep = True

		If $bSubfolder Then ; Auflistung aller Dateien im Verzeichnis oder auch aller Unterverzeichnisse.
			$aFolder = _FileList($sStartFolder)
		Else
			$aFolder = _FileList($sStartFolder, False)
		EndIf
		$iAllFiles = @extended ; _FileList gibt in @extended die Anzahl der Array-Elemente aus.
		GUICtrlSetData($idL_Abort, 'Abbruch der Suche durch drücken von "Esc"')
;~ _ArrayDisplay($aFolder,$iAllFiles )
		Local $sQuery = ""
		If IniRead($hIni, "Settings", "Datenbankbereinigung", "") Then
			GUICtrlSetData($idL_Abort, 'Bereinige Datenbank...  Abbruch der Suche durch drücken von "Esc"')

			; ## Mit Array
			For $i = $iAllSQLFiles To 1 Step -1 ; Dateien, die nicht mehr in $aFolder sind, aber aus einer früheren Suche noch in der Datenbank sind, werden nun entfernt.
				If $bAbort Then ExitLoop ; Abbruch wenn Hotkey gedrückt wurde.
				GUICtrlSetData($idProgress, 100 - ($i * 100 / $iAllSQLFiles))
				$iIndex = _ArraySearch($aFolder, $aSQLFiles[$i][1], 0, 0, 0, 0, 1, 0)
				If $iIndex = -1 Then
					$sQuery &= "DELETE FROM FILES WHERE fullpath = '" & $aSQLFiles[$i][1] & "';"
					_ArrayDelete($aSQLFiles, $i)
;~ 					ConsoleWrite("Lösche: " & $aSQLFiles[$i][1] & @CRLF)
				EndIf
			Next

			GUICtrlSetData($idL_Abort, 'Konsolidiere Datenbank...')
			If $sQuery <> "" Then _SQLite_Exec(-1, $sQuery) ; Das Query wird ausgeführt.
			If BitAND(GUICtrlRead($idM_Vacuum), $GUI_CHECKED) = $GUI_CHECKED Then _SQLite_Exec(-1, "VACUUM")
			$sQuery = "" ; Die Query-Variable wird für die weitere Verwendung geleert.
			GUICtrlSetData($idL_Abort, 'Abbruch der Suche durch drücken von "Esc"')
		EndIf

		Local $aTempSQLFiles[$iAllFiles][2] ; Ein temporäres Array sowie eine Index Variable zum Zwischenspeichern der Treffer. Werden nach der Schleife an $aSQLFiles angehängt. (Sollte schneller gehen, als _ArrayAdd in der Schleife).
		Local $iCount = 0 ; hier Zählervariable für neu gefundene Dateien

		If $iAllFiles > 0 Then
			For $i = 0 To $iAllFiles - 1 ; Hier beginnt nun der Suchlauf mit dem Einlesen der Dateien.
				If $bAbort Then ExitLoop ; Abbruch wenn Hotkey gedrückt wurde.
				$bNotFound = True ; Dient als Flag, ob die Datei eingelesen werden muss.
				GUICtrlSetData($idProgress, $i * 100 / $iAllFiles)
				$iIndex = _ArraySearch($aSQLFiles, $aFolder[$i][0], 0, 0, 0, 0, 1, 1) ; Hier wird die aktuelle Datei in der SQL-DB gesucht.
				If $iIndex <> -1 Then
					$bNotFound = False
					If $aFolder[$i][1] <> $aSQLFiles[$iIndex][0] Then ; Wenn sie gefunden wird, aber (FileGetTime) zwischendurch bearbeitet wurde, wird die Datei aus der SQL-DB gelöscht.
						_SQLite_Exec(-1, "DELETE FROM FILES WHERE fullpath = '" & $aSQLFiles[$iIndex][1] & "';")
						_ArrayDelete($aSQLFiles, $iIndex)
						$bNotFound = True
					EndIf
				EndIf

				If $bNotFound Then ; Wenn der Flag gültig, dann wird die Datei eingelesen.
					$iCount += 1

					$aPathSplit = StringSplit($aFolder[$i][0], ".")
;~ 					FileWrite(@ScriptDir & "\Log1.txt", $aFolder[$i][0] & "wird gelesen. Index: " & $i & @CRLF)
					Select ; je nach Datei-Endung wird die entsprechende Funktion aufgerufen.
						Case $aPathSplit[$aPathSplit[0]] = "docx" Or $aPathSplit[$aPathSplit[0]] = "doc"
							$sString = _GetContent_DOC_DOCX($aFolder[$i][0])
						Case $aPathSplit[$aPathSplit[0]] = "xls" Or $aPathSplit[$aPathSplit[0]] = "xlsx"
							$sString = _GetContent_XLS_XLSX($aFolder[$i][0])
						Case _ArraySearch($aFileTypes, $aPathSplit[$aPathSplit[0]]) <> -1
							$sString = _GetContent_TXT($aFolder[$i][0])
						Case $aPathSplit[$aPathSplit[0]] = "csv"
							$sString = _GetContent_CSV($aFolder[$i][0])
						Case $aPathSplit[$aPathSplit[0]] = "pdf"
							$sString = _GetContent_PDF($aFolder[$i][0])
					EndSelect

					$aTempSQLFiles[$i][0] = $aFolder[$i][1] ; Wenn die Datei gelesen wurde, wird sie dem temporären Array zugewiesen.
					$aTempSQLFiles[$i][1] = $aFolder[$i][0]
;~ 					$sQuery &= "INSERT INTO FILES(modified,fullpath,content) VALUES (" & _SQLite_Escape($aFolder[$i][1]) & "," & _SQLite_Escape($aFolder[$i][0]) & "," & _SQLite_Escape($sString) & ");" ; Eintrag in SQL-Query: Datei-Baerbeitungszeit, voller Dateipfad, Datei-Inhalt.
					$sQuery = "INSERT INTO FILES(modified,fullpath,content) VALUES (" & _SQLite_Escape($aFolder[$i][1]) & "," & _SQLite_Escape($aFolder[$i][0]) & "," & _SQLite_Escape($sString) & ");" ; Eintrag in SQL-Query: Datei-Baerbeitungszeit, voller Dateipfad, Datei-Inhalt.

;~ 					_SQLite_Exec(-1, $sQuery)
					If $SQLITE_OK <> _SQLite_Exec(-1, $sQuery) Then
						ConsoleWrite(StringFormat("%s - %s:%s:%s - %s", "Fehler", @MIN, @SEC, @MSEC, $aFolder[$i][0]) & @CRLF)
					Else
						ConsoleWrite(StringFormat("%s - %s:%s:%s - %s", "Ok", @MIN, @SEC, @MSEC, $aFolder[$i][0]) & @CRLF)
					EndIf
				EndIf

				_GUICtrlStatusBar_SetText($hStatus, $i + 1 & " / " & $iAllFiles & " Dateien") ; aktueller Fortschritt für das Label.
			Next
			ReDim $aTempSQLFiles[$iCount][2] ; Das temporäre Array wird auf die benötigte Größe verkleinert.
			_ArrayConcatenate($aSQLFiles, $aTempSQLFiles) ; Das temporäre Array wird $aSQLFiles angehängt.
		EndIf
	EndIf

	Local $iCount = 0 ; hier Zählervariable für die Größe von $aSearchString. Siehe unten.

	If BitAND(GUICtrlRead($idM_Umlauts), $GUI_CHECKED) = $GUI_CHECKED Then ; Wenn die Option Umlaute auch in Vokalvariante finden aktiviert ist, wird folgende Prüfung durchgeführt.
		Local $aUmlauts[3][2] = [["ä", "ae"], ["ö", "oe"], ["ü", "ue"]]
		Local $iIndex = 0, $sNoUmlaut, $sSearchString

		For $i = 0 To 2
			$sNoUmlaut = StringReplace($aSearchString[0], $aUmlauts[$i][0], $aUmlauts[$i][1]) ; Es wird auf jeden Umlaut geprüft und je nach Anzahl der Treffer

			Local $iCountNU = @extended ;
			If $iCountNU > 0 Then
				If $iCountNU > 1 Then
					$iCount += $iCountNU * 2
				Else
					$iCount += 2
				EndIf
				ReDim $aSearchString[$iCount]
				$aSearchString[$iIndex] = $aSearchString[0]
				$aSearchString[$iIndex + 1] = $sNoUmlaut
				$iIndex += 2
			EndIf
		Next
	EndIf
;~ _ArrayDisplay($aSearchString)
	If $iCount <= 1 Then
		$sSearchString = StringReplace($aSearchString[0], "*", "\*") ; * und % im Suchbegriff werden mit \ maskiert, weil es sich hierbei um SQlite Operatoren handelt.
		$sSearchString = StringReplace($sSearchString, "%", "\%")
		$iPercentsCheck = @extended ; Notwendig, weil aus irgendeinem Grund, bei der Suche nach Strings mit % auch Texte ohne Prozent rauskommen - trotz escapen!
		$sSearchString = StringReplace($sSearchString, "_", "\_")
		$iRval = _SQLite_GetTable2d(-1, "SELECT * FROM FILES WHERE content LIKE '%" & $sSearchString & "%';", $aSQLResultFiles, $iRows, $iColumns)
		If $iRval <> $SQLITE_OK Then ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & "SQLite Error: " & $iRval & " - " & _SQLite_ErrMsg() & @CRLF)
		_ArrayDelete($aSQLResultFiles, 0)
		If $iPercentsCheck > 0 Then
			For $i = UBound($aSQLResultFiles) - 1 To 0 Step -1
				If Not StringInStr($aSQLResultFiles[$i][2], $aSearchString[0]) Then _ArrayDelete($aSQLResultFiles, $i)
			Next
		EndIf
	Else
		Local $aTempResults
		$aSearchString = _ArrayUnique($aSearchString)
		Local $iMaxIndex = $aSearchString[0]
		_ArrayDelete($aSearchString, 0)
		ReDim $aSearchString[$iMaxIndex]
;~ 		_ArrayDisplay($aSearchString)
		$sQuery = "SELECT * FROM FILES WHERE"

		For $i = 0 To $iMaxIndex - 1
			$sSearchString = StringReplace($aSearchString[$i], "*", "\*") ; * und % im Suchbegriff werden mit \ maskiert, weil es sich hierbei um SQlite Operatoren handelt.
			$sSearchString = StringReplace($sSearchString, "%", "\%")
			$iPercentsCheck = @extended ; Notwendig, weil aus irgendeinem Grund, bei der Suche nach Strings mit % auch Texte ohne Prozent rauskommen - trotz escapen!
			$sSearchString = StringReplace($sSearchString, "_", "\_")
;~ 			ConsoleWrite($i & " " & $aSearchString[$i] & @CRLF)
			If $i = 0 Then
				$sQuery &= " content LIKE '%" & $sSearchString & "%'"
			Else
				$sQuery &= " OR content LIKE '%" & $sSearchString & "%'"
			EndIf
		Next
		$sQuery &= ";"
		$iRval = _SQLite_GetTable2d(-1, $sQuery, $aTempResults, $iRows, $iColumns)
		If $iRval <> $SQLITE_OK Then ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & "SQLite Error: " & $iRval & " - " & _SQLite_ErrMsg() & @CRLF)
		_ArrayDelete($aTempResults, 0)
		_ArrayConcatenate($aSQLResultFiles, $aTempResults) ; Das temporäre Array wird $aSQLResultFiles angehängt.
;~ 			_ArrayDisplay($aSQLResultFiles)
		If $iPercentsCheck > 0 Then
			For $ii = UBound($aSQLResultFiles) - 1 To 0 Step -1
				If Not StringInStr($aSQLResultFiles[$ii][2], $aSearchString[$i]) Then _ArrayDelete($aSQLResultFiles, $i)
			Next
		EndIf
	EndIf

	If Not $bDBSearchOnly Then ; Falls keine DB-Suche durchgeführt wurde..
		For $i = UBound($aSQLResultFiles) - 1 To 0 Step -1 ; Hier werden alle Treffer aus Unterordnern entfernt, falls sie durch frühere Suchen in der DB sind, aber jetzt nicht angezeigt werden sollen.
			If Not FileExists($aSQLResultFiles[$i][1]) Then _ArrayDelete($aSQLResultFiles, $i)
		Next
		If Not $bSubfolder Then
			For $i = UBound($aSQLResultFiles) - 1 To 0 Step -1 ; Hier werden alle Treffer aus Unterordnern entfernt, falls sie durch frühere Suchen in der DB sind, aber jetzt nicht angezeigt werden sollen.
				If StringInStr(StringReplace($aSQLResultFiles[$i][1], $sStartFolder & "\", ""), "\") Then _ArrayDelete($aSQLResultFiles, $i)
			Next
		EndIf
	EndIf

	_ArraySort($aSQLResultFiles, 0, 0, 0, 1) ; Ergebnisse werden nach Speicherort sortiert.
	$iHits = UBound($aSQLResultFiles)
	Local $sListViewItem = ""
	For $i = 0 To $iHits - 1 ; Alle Treffer werden in die Listview übernommen.
		$sListViewItem = StringReplace($aSQLResultFiles[$i][1], $sStartFolder & "\", "")
		If @extended <> 0 Then _GUICtrlListView_AddItem($idLV_MainGUI, $sListViewItem, $iHits) ; @extended weil bei Startordnerwechsel Treffer aus dem alten Pfad ignoriert werden. (Kann passieren, wenn man keine Datenbankbereinigung durchführt.)
	Next


	GUIDelete($hProgressGUI) ; Fortschrittsfenster löschen.

	$iDiff_Sec = TimerDiff($hTimer) / 1000
	$sDiff = StringFormat("%0.2f", $iDiff_Sec)
	$sDiff = StringReplace($sDiff, ".", ",")

	GUICtrlSetTip($idL_Ignored, $sIgnored, "Übergangene Dateie(n)") ; Die Info-Labels werden mit den Ergebnissen gefüllt.
	If Not $bDBSearchOnly Then
		_GUICtrlStatusBar_SetText($hStatus, $iAllFiles & " Dateien")
	Else
		_GUICtrlStatusBar_SetText($hStatus, $iAllSQLFiles & " Dateien")
	EndIf
	If $iHits > 0 Then GUICtrlSetState($idL_Clickhint, $GUI_SHOW)
	_GUICtrlStatusBar_SetText($hStatus, $iHits & " Treffer", 1)
	_GUICtrlStatusBar_SetText($hStatus, $sDiff & " Sekunden", 3)

	GUICtrlSetState($idLV_MainGUI, $GUI_SHOW)
;~ 	_ArrayDisplay($aSQLFiles)

	HotKeySet("{ESC}") ; Hotkey wird wieder freigegeben und der Abbruchflag zurückgesetzt.
	$bAbort = False

EndFunc   ;==>_SearchAndProgress

Func _SetAbort() ; Wird duch Hotkey aus Funktion_SearchAndProgress() aufgerufen. Dient dem Abbruch der Suche.
	$bAbort = True
EndFunc   ;==>_SetAbort

Func _FileList($sFolder, $bRec = True, $iTimeStep = 1, $iSort = 0) ; In dieser Funktion werden die Dateien für SearchAndProgress gelistet. (Array mit Dateien und Filetime - Siehe: https://autoit.de/index.php/Thread/84971-Dateien-nach-Alter-Bearbeitungszeit-Zugriffszeit-auflisten/?postID=679896#post679896).
	If Not StringInStr(FileGetAttrib($sFolder), "D") Then Return SetError(1)
	If Not (0 <= $iTimeStep And $iTimeStep <= 2) Then Return SetError(3)
	$sFolder = StringRegExpReplace($sFolder, "\\$", "")
	Local $iArraySize = 100000
	Local $aFiles[$iArraySize][2], $iCount, $aSearchFile[256], $sFile, $iDepth, $sTime, $sExtension
	Local $aFileTypes = StringSplit(FileRead($hFiletypes) & ",docx,doc,xls,xlsx,csv,pdf", ",", 2)
	Local $iIgnored = 0, $sIgnored, $sToIgnore = IniRead($hIni, "Settings", "Ignoriertes", "")

	If $sToIgnore And StringInStr($sToIgnore, "|") Then ; Zu ignorierende Ordner werden in ein Array geholt.
		Local $aIgnoreToIni = StringSplit($sToIgnore, "|", 2)
	Else
		Local $aIgnoreToIni[1] = [$sToIgnore]
	EndIf

	$aSearchFile[$iDepth] = FileFindFirstFile($sFolder & "\*")
	While $iDepth >= 0 ; In dieser Schleife werden alle Dateien/Ordner abgehandelt
		$sFile = FileFindNextFile($aSearchFile[$iDepth])
		If @extended And $bRec Then ; Wenn es sich um ein Ordner handelt wird in diesem weiter gesucht
			If Not $sToIgnore Or _ArraySearch($aIgnoreToIni, $sFolder) = -1 Then
				$iDepth += 1
				$sFolder &= "\" & $sFile
				$aSearchFile[$iDepth] = FileFindFirstFile($sFolder & "\*")
			EndIf
		ElseIf @error Then ; Wenn keine Dateien mehr im Ordner vorhanden sind wird das "Handle" Freigegeben
			FileClose($aSearchFile[$iDepth])
			$iDepth -= 1
			$sFolder = StringRegExpReplace($sFolder, "\\[^\\]*$", "")
		Else ; Hier werden die Dateien dem $aFiles hinzugefügt, wenn sie mit den vorgaben übereinstimmen
			$sExtension = StringTrimLeft($sFile, StringInStr($sFile, '.', 2, -1))
			If _ArraySearch($aFileTypes, $sExtension) <> -1 Then
				If Not $sToIgnore Or _ArraySearch($aIgnoreToIni, $sFolder) = -1 Then
					$sTime = FileGetTime($sFolder & "\" & $sFile, $iTimeStep, 1)
					If @error Then ContinueLoop
					If $iCount >= $iArraySize Then
						$iArraySize += 100000
						ReDim $aFiles[$iArraySize][2]
					EndIf
					$aFiles[$iCount][0] = $sFolder & "\" & $sFile
					$aFiles[$iCount][1] = $sTime
					$iCount += 1
					_GUICtrlStatusBar_SetText($hStatus, $iCount & " Dateien") ; aktueller Fortschritt für das Label.
				EndIf
			Else
				$iIgnored += 1
				$sIgnored &= $sExtension & " - " & $sFolder & "\" & $sFile & @CRLF
				_GUICtrlStatusBar_SetText($hStatus, $iIgnored & " Dateie(n) übergangen", 2)
			EndIf
		EndIf
	WEnd
	ReDim $aFiles[$iCount][2]
	If $iSort = 0 Or $iSort = 1 Then _ArraySort($aFiles, $iSort, Default, Default, 1)
	Return SetExtended($iCount, $aFiles)
EndFunc   ;==>_FileList

; ### Ende Funktionen: Zentrale Suchfunktionen ###



; ### Funktionen: Steuerung zum Zeigen/Holen Text ### Diese Funktionen werden aufgerufen, wenn Dateien ausgelesen, oder angezeigt werden sollen. Das wirkliche Auslesen passiert aber unten im Bereich "Dateien lesen" (und evtl. in den Office UDF). Hier findet nur die Vermittlung/Prüfung statt.

Func _GetContent_XLS_XLSX($sFullPath, $iShow = 0)
	Local $aExtension = StringSplit($sFullPath, ".", 1)
	$sExtension = StringLower($aExtension[$aExtension[0]])
	Local $aData, $sData

	If $sExtension == "xls" Then ; Der Zusatz "Not $iShow" soll die initiale Suche beschleunigen, solange ich der _XLSReadToArray-Funktion auf Korrektheit vertraue.
		Local $aExcelSheets = _XLSReadToArray($sFullPath)
		If Not @error And Not $bObjectError Then ; Wenn _XLSReadToArray keinen Fehler zurückgegeben hat und kein Objektfehler aufgetreten ist.. Sonst geht es weiter mit Excel wenn möglich.
			Local $iSheetCount = UBound($aExcelSheets)
			If $iSheetCount > 1 Then
				For $i = $iSheetCount - 1 To 0 Step -1
					If Not IsArray($aExcelSheets[$i]) Then _ArrayDelete($aExcelSheets, $i)
				Next
				$iSheetCount = UBound($aExcelSheets)
				For $i = 1 To $iSheetCount - 1
					_ArrayConcatenate($aExcelSheets[0], $aExcelSheets[$i])
				Next
;~ 			_ArrayDisplay($aExcelSheets)
			EndIf
			$aData = $aExcelSheets[0]

			$sData = _ArrayToString($aData)
			If $iShow = 1 Then Return _Show_ArrayInGUI($aData)
			Return $sData
		EndIf
	EndIf

	If $sExtension == "xlsx" Then ; xlsx-Dateien werden mit der UDF _XLSXReadToArray gelesen.
		$aData = _XLSXReadToArray($sFullPath, 0, 0, 0)
		If Not @error Then
			_ArrayDelete($aData, 0) ; Beinhaltet nur die _Arrayelemente von $aData (Wird gelöscht, weil die anderen Funktionen das nicht zurückgeben und die Arrays ja gleich sein sollen.)
			If $iShow = 1 Then Return _Show_ArrayInGUI($aData)
			$sData = _ArrayToString($aData)
			Return $sData
		EndIf
	EndIf

	; Wenn durch Fehler oder duch bereits erfolgreiches Lesen, die Funktion noch nicht verlassen wurde, wird die Excel-UDF ausprobiert.

	Local $oWorkbook = _Excel_BookOpen($oExcel, $sFullPath, True)
	If @error Then ; Wenn hier ein Fehler auftritt, ist Excel wohl nicht installiert.
		ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & $sFullPath & " _Excel_BookOpen-Fehler: " & @error & @CRLF)

		If $bObjectError And $sExtension == "xls" Then Return ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & $sFullPath & "ADODB-Fehler und _Excel_BookOpen-Fehler: " & @error & " # Datei kann nicht ausgelesen werden!!" & @CRLF) ; Wenn ein Objektfehler aufgetreten ist und Excel nicht installiert ist, kann xls nicht gelesen werden.
		Return MsgBox(0, "", "Fehler _Excel_BookOpen")
	EndIf

	With $oWorkbook.ActiveSheet ; Aus dem Wiki. Ermittelt den Bereich von A1 bis zur letzten benutzten Zelle. https://www.autoitscript.com/wiki/Excel_Range#Last_Cell
		$oRangeLast = .UsedRange.SpecialCells($xlCellTypeLastCell)
		$oRange = .Range(.Cells(1, 1), .Cells($oRangeLast.Row, $oRangeLast.Column))
	EndWith

	$aData = _Excel_RangeRead($oWorkbook, Default, $oRange)
	If @error Then
		ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & $sFullPath & " _Excel_RangeRead-Fehler: " & @error & @CRLF)
		$aData = _Excel_RangeRead($oWorkbook, Default, Default, 1, True)
		If @error Then
			ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & $sFullPath & " _Excel_RangeRead-Fehler mit Methode 2: " & @error & @CRLF)
			Return MsgBox(0, "", "Fehler _Excel_RangeRead")
		EndIf
	EndIf

	_Excel_BookClose($oWorkbook, False)

	If @error Then ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & $sFullPath & " _Excel_Close-Fehler: " & @error & @CRLF)

	If $iShow = 1 Then Return _Show_ArrayInGUI($aData)

	Return IsArray($aData) ? _ArrayToString($aData) : 0


EndFunc   ;==>_GetContent_XLS_XLSX

Func _GetContent_CSV($sFullPath, $iShow = 0)
	Local $aData, $iDelim, $sDelim
	$sData = FileRead($sFullPath)

	If $sDelim = "" Then ; Diese If-Abfrage ist derzeit eigentlich sinnlos. Vielleicht baue ich aber noch eine Möglichkeit ein, den Trenner selbst zu wählen, wenn ein falsches Zeichen verwendet wird.
		Local $aDelim[4][2]

		StringReplace($sData, ";", "") ; Die möglichen Trennzeichen werden in gezählt und in ein Array eingetragen.
		$aDelim[0][0] = @extended
		$aDelim[0][1] = ";"
		StringReplace($sData, @TAB, "")
		$aDelim[1][0] = @extended
		$aDelim[1][1] = @TAB
		StringReplace($sData, ",", "")
		$aDelim[2][0] = @extended
		$aDelim[2][1] = ","
		StringReplace($sData, "|", "")
		$aDelim[3][0] = @extended
		$aDelim[3][1] = "|"

		_ArraySort($aDelim, 1) ; Das Array wird absteigend sortiert und oben steht das mögliche Trennzeichen mit dem häufigste Vorkommen. Dieses wird nun als Trennzeichen verwendet.
		$iDelim = $aDelim[0][0]
		$sDelim = $aDelim[0][1]
	Else
		StringReplace($sData, $sDelim, "")
		$iDelim = @extended
	EndIf

	If Not $iDelim And $iShow = 1 Then ; Bei fehlendem Trennzeichen und Ergebnis soll angezeigt werden in GUI

;~ 		Return $bExcelInstalled ? _GetContent_XLS_XLSX($sFullPath, 1) : _Show_StringInGUI($sData) ; Wenn Excel installiert ist, wird es mit der Excel UDF versucht. Andernfalls wird die Funktion mit dem Funtkionsaufruf für das Textfenster verlassen.
		Return $bExcelInstalled ? _Show_ArrayInGUI($sFullPath) : _Show_StringInGUI($sData) ; Wenn Excel installiert ist, wird es mit der Excel UDF versucht. Andernfalls wird die Funktion mit dem Funtkionsaufruf für das Textfenster verlassen.

	EndIf

	StringReplace($sData, @LF, "")
	Local $iBreak = @extended

	If $iDelim >= $iBreak Then ; Wenn das Trennzeichen häufiger als Umbrüche sind, versuchen wir es mit einem Array - sonst Text.

		Local $aRows = StringSplit($sData, @LF)

		Local $iResultRows = $aRows[0]
		Local $iResultCols = 500 ; Die Spalten werden erst einmal pauschal mit 500 angegenben und später angepasst.
		Local $aResult[$iResultRows][$iResultCols] ; Einfach ein großes Array, das alle einträge der aktuellen Tabelle fassen können sollte. Andernfalls ändern.

		Local $iColCount = 0
		For $i = 1 To $aRows[0] - 1
			$aColValues = StringSplit($aRows[$i], $sDelim) ; Jeder Datensatz (Zeile) wird am Trennzeichen in ein Array getrennt.
			If $aColValues[0] > $iColCount Then $iColCount = $aColValues[0] ; $iColCount startete als 0 und nimmt nun den maximalen Spaltenwert an. Es dient zum späteren ReDim auf die notwendige Größe.

			If $aColValues[0] > $iResultCols Then ; Wenn es mehr Spalten in diesem Datensatz gibt, als im $aResult-Array vorgesehen, wird das $aResult-Array angepasst.
				$iResultCols = $aColValues[0]
				ReDim $aResult[$iResultRows][$iResultCols]
			EndIf

			For $ii = 1 To $aColValues[0] ; Die $aResult-Zeile wird mit dem Inhalt der Zeile aus der Datei gefüllt.
				$aResult[$i - 1][$ii - 1] = $aColValues[$ii]
			Next
		Next
		If $iColCount < 500 Then ReDim $aResult[$aRows[0] - 1][$iColCount] ; Wenn $iColCount kleiner 500 ist, wird das Array auf die notwendige Spaltenzahl reduziert.

		Return $iShow ? _Show_ArrayInGUI($aResult) : _ArrayToString($aResult) ; Wenn es angezeigt werden soll, in die GUI. Andernfalls als String zurückgeben.

	Else
		If $iShow = 1 Then

			Return $bExcelInstalled ? _GetContent_XLS_XLSX($sFullPath, 1) : _Show_StringInGUI($sData) ; Wenn Excel installiert ist, wird es mit der Excel UDF versucht. Andernfalls wird die Funktion mit dem Funtkionsaufruf für das Textfenster verlassen.

		Else
			Return $sData
		EndIf
	EndIf
EndFunc   ;==>_GetContent_CSV

Func _GetContent_TXT($sFullPath, $iShow = 0)
	Local $sString = FileRead($sFullPath)
	If $iShow = 1 Then
		Return _Show_StringInGUI($sString)
	Else
		Return $sString
	EndIf
EndFunc   ;==>_GetContent_TXT

Func _GetContent_DOC_DOCX($sFullPath, $iShow = 0) ; Bei DOC verbleiben oft unerwünschte Zeichen im Text, wenn etwa Tabellen im Text sind. Hier wird die Word UDF verwendet.

	Local $aExtension = StringSplit($sFullPath, ".", 1)
	$sExtension = StringLower($aExtension[$aExtension[0]])
	Local $sTempFile = _TempFile()

	If $sExtension == "docx" Then ; Soll die Suche und Anzeige beschleunigen, solange ich der _DOCXToString-Funktion auf Korrektheit vertraue.
		$sString = _DOCXToString($sFullPath)
		If $iShow = 1 Then Return _Show_StringInGUI($sString)
		Return $sString
	EndIf

	If $sExtension == "doc" Then ; Soll die Suche und Anzeige beschleunigen, solange keine der unten aufgeführten Zeichen im Text verbleiben.
		$sString = _DOCToString($sFullPath)
		If StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Or StringInStr($sString, "") Then
;~ 			ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & $sFullPath & " - Unerwünschte Zeichen in DOC. Fortfahren mit Word" & @CRLF)
		Else
			If $iShow = 1 Then Return _Show_StringInGUI($sString)
			Return $sString
		EndIf
	EndIf

	; Wenn in der Rückgabe von _DOCToString unerwünschte Zeichen sind, wird es mit der Word UDF probiert.

	Local $oDoc = _Word_DocOpen($oWord, $sFullPath, Default, Default, True, True) ; Bei jedem Schritt wird im Fehlerfall doch auf die String-Funktionen zurückgegriffen.
	If @error Then
		ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & $sFullPath & " - _Word_DocOpen-Fehler: " & @error & @CRLF)
		If $sExtension == "doc" Then ; Diese und die folgenden If Else Abfrage ist eigentlich nicht notwendig, da sie eh nur bei "doc" aufgerufen werden können. Ich habe es drin gelassen, falls ich das oben bei "docx" noch einmal ändere.
			$sString = _DOCToString($sFullPath)
			If $iShow = 1 Then Return _Show_StringInGUI($sString)
			Return $sString
		Else
			$sString = _DOCXToString($sFullPath)
			If $iShow = 1 Then Return _Show_StringInGUI($sString)
			Return $sString
		EndIf
	EndIf
	_Word_DocSaveAs($oDoc, $sTempFile, $WdFormatText)
	If @error Then
		ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & $sFullPath & " - _Word_DocSaveAs-Fehler: " & @error & @CRLF)
		If $sExtension == "doc" Then ; Diese und die folgenden If Else Abfrage ist eigentlich nicht notwendig, da sie eh nur bei "doc" aufgerufen werden können. Ich habe es drin gelassen, falls ich das oben bei "docx" noch einmal ändere.
			$sString = _DOCToString($sFullPath)
			If $iShow = 1 Then Return _Show_StringInGUI($sString)
			Return $sString
		Else
			$sString = _DOCXToString($sFullPath)
			If $iShow = 1 Then Return _Show_StringInGUI($sString)
			Return $sString
		EndIf
	EndIf
	$sString = FileRead($sTempFile)
	FileDelete($sTempFile)
	_Word_DocClose($oDoc)

	If $iShow = 1 Then
		Return _Show_StringInGUI($sString)
	Else
		Return $sString
	EndIf

EndFunc   ;==>_GetContent_DOC_DOCX

Func _GetContent_PDF($sFullPath, $iShow = 0) ; Mittels der _XPDF_ToText UDF und der pdftotext.exe
	Local $sTempFile = _TempFile()

	_GUICtrlEdit_SetText($id_DocTxtField, "")
	GUISetState(@SW_HIDE, $hListGUI)

	Local $sFile = StringReplace($sTempFile, @TempDir & "\", "")

	Local $sTestread = _XPDF_ToText($sFullPath, $sFile, @TempDir)
	If @error Then Return MsgBox(0, $sAppName, "Fehler beim Lesen der PDF-Datei! (" & @error & ")", 4)
	Local $sString = FileRead($sTempFile)
	FileDelete($sTempFile)
	If $iShow = 1 Then
		Return _Show_StringInGUI($sString)
	Else
		Return $sString
	EndIf
EndFunc   ;==>_GetContent_PDF

; ### Ende Funktionen: Steuerung zum Zeigen/Holen Text ###




; ### Funktionen: Dateien lesen ### Hier finden sich die Funktionen zum Auslesen der Dateien. Zusätzlich werden wenn nötig und möglich die Word und Excel UDF benutzt.

Func _DOCToString($sFullPath) ; https://www.autoitscript.com/forum/topic/80782-extracting-text-out-of-doc-file/
	Local $aExtension = StringSplit($sFullPath, ".", 1)
	$sExtension = $aExtension[$aExtension[0]]

	Local $hwnd = FileOpen($sFullPath, 16)
	Local $content = FileRead($hwnd)
	FileClose($hwnd)

	Local $contentdoc = BinaryMid($content, 513, 2) ;    0xECA5 - for .doc file of our interest

	Select
		Case ($sExtension <> "doc" Or $sExtension <> "DOC") And $contentdoc <> "0xECA5"
			Return SetError(1) ; not doc file or quasi doc file with wrong extension
		Case ($sExtension <> "doc" Or $sExtension <> "DOC") And $contentdoc == "0xECA5"
			Return SetError(2) ; extension incorrect, header indicates doc file
		Case ($sExtension == "doc" Or $sExtension == "DOC") And $contentdoc <> "0xECA5"
			Return SetError(3) ; extension incorrect or quasi doc file (extracting code required)
	EndSelect

	Local $complex_bin = BinaryMid($content, 523, 2) ; little endian
	Local $complex
	For $a = 1 To 2
		; little endian -> big endian
		$complex &= Hex(BinaryMid($complex_bin, 3 - $a, 1))
	Next
	$complex = Dec($complex)
	If Mod(Floor($complex / 4), 2) <> 0 Then Return SetError(4) ; complex doc file (extracting code required)

	Local $start_bin = BinaryMid($content, 537, 4) ; little endian
	Local $start
	For $i = 1 To 4
		; little endian -> big endian
		$start &= Hex(BinaryMid($start_bin, 5 - $i, 1))
	Next
	$start = Dec($start) ; text starts here

	Local $end_bin = BinaryMid($content, 541, 4) ; little endian
	Local $end
	For $i = 1 To 4
		; little endian -> big endian
		$end &= Hex(BinaryMid($end_bin, 5 - $i, 1))
	Next
	$end = Dec($end) ; text ends here

	If $start > $end Then Return SetError(5) ; corrupted header

	Local $content1 = BinaryMid($content, 513 + $start, $end - $start)

	Local $text

	$text = StringReplace(BinaryToString($content1), Chr(0), "")
	$text = StringRegExpReplace($text, "(?s)(\x13.+?)\x14(.*?)\x15?", "$1" & Chr(21) & "$2")
	$text = StringRegExpReplace($text, '(?s)\x13(.*?)\x15', "")
;~ 	$text = StringRegExpReplace($text, "[^[:space:]|[:print:]]", "")
	$text = StringRegExpReplace($text, "\v", @CRLF)

	Return $text
EndFunc   ;==>_DOCToString

Func _DOCXToString($sFullPath) ; https://www.autoitscript.com/forum/topic/80806-reading-docx-files/?do=findComment&comment=581526

	Local $hwnd = FileOpen($sFullPath, 16)
	Local $header = FileRead($hwnd, 2)
	FileClose($hwnd)

	If $header <> '0x504B' Then Return SetError(1) ; not .docx file

	Local $Name, $UnZipName, $TempZipName

	Local $i, $f_name = "~TempDoc"
	Do
		$i += 1
		$Name = @TempDir & "\" & $f_name & $i & ".zip"
	Until Not FileExists($Name)

	FileCopy($sFullPath, $Name, 9)

	Local $j
	Do
		$j += 1
		$UnZipName = @TempDir & "\~DocXdoc" & $j
	Until Not FileExists($UnZipName)

	DirCreate($UnZipName)

	Local $k
	Do
		$k += 1
		$TempZipName = @TempDir & "\Temporary Directory " & $k & " for " & $f_name & $i & ".zip"
	Until Not FileExists($TempZipName)

	Local $oApp = ObjCreate("Shell.Application")

	If Not IsObj($oApp) Then Return SetError(2) ; highly unlikely but could happen

	$oApp.NameSpace($UnZipName).CopyHere($oApp.NameSpace($Name & '\word').ParseName("document.xml"), 4)

	Local $text = FileRead($UnZipName & "\document.xml")

	DirRemove($UnZipName, 1)
	FileDelete($Name)
	DirRemove($TempZipName, 1)

	$text = StringReplace($text, @CRLF, "")
	$text = StringRegExpReplace($text, "<w:body>(.*?)</w:body>", '$1', 0)
	$text = StringReplace($text, "</w:p>", @CRLF)
	$text = StringReplace($text, "<w:cr/>", @CRLF)
	$text = StringReplace($text, "<w:br/>", @CRLF)
	$text = StringReplace($text, "<w:tab/>", @TAB)

	$text = StringRegExpReplace($text, "<(.*?)>", "")

	$text = StringReplace($text, "&lt;", "<")
	$text = StringReplace($text, "&gt;", ">")
	$text = StringReplace($text, "&amp;", "&")

	$text = StringReplace($text, Chr(226) & Chr(130) & Chr(172), Chr(128))
	$text = StringReplace($text, Chr(194) & Chr(129), Chr(129))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(154), Chr(130))
	$text = StringReplace($text, Chr(198) & Chr(146), Chr(131))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(158), Chr(132))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(166), Chr(133))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(160), Chr(134))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(161), Chr(135))
	$text = StringReplace($text, Chr(203) & Chr(134), Chr(136))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(176), Chr(137))
	$text = StringReplace($text, Chr(197) & Chr(160), Chr(138))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(185), Chr(139))
	$text = StringReplace($text, Chr(197) & Chr(146), Chr(140))
	$text = StringReplace($text, Chr(194) & Chr(141), Chr(141))
	$text = StringReplace($text, Chr(197) & Chr(189), Chr(142))
	$text = StringReplace($text, Chr(194) & Chr(143), Chr(143))
	$text = StringReplace($text, Chr(194) & Chr(144), Chr(144))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(152), Chr(145))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(153), Chr(146))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(156), Chr(147))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(157), Chr(148))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(162), Chr(149))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(147), Chr(150))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(148), Chr(151))
	$text = StringReplace($text, Chr(203) & Chr(156), Chr(152))
	$text = StringReplace($text, Chr(226) & Chr(132) & Chr(162), Chr(153))
	$text = StringReplace($text, Chr(197) & Chr(161), Chr(154))
	$text = StringReplace($text, Chr(226) & Chr(128) & Chr(186), Chr(155))
	$text = StringReplace($text, Chr(197) & Chr(147), Chr(156))
	$text = StringReplace($text, Chr(194) & Chr(157), Chr(157))
	$text = StringReplace($text, Chr(197) & Chr(190), Chr(158))
	$text = StringReplace($text, Chr(197) & Chr(184), Chr(159))

	For $X = 160 To 191
		$text = StringReplace($text, Chr(194) & Chr($X), Chr($X))
	Next

	For $X = 192 To 255
		$text = StringReplace($text, Chr(195) & Chr($X - 64), Chr($X))
	Next

	Return $text

EndFunc   ;==>_DOCXToString

Func _XLSReadToArray($sFullPath) ; Siehe Bemerkungen in der Funktion.
	Local Const $ADO_adSchemaTables = 20
	Local Const $iCursorType = 0
	Local Const $iLockType = 1
	Local Const $iOptions = 512

	; Eine Verbindung, zum Auslesen der Tabellennamen.
	Local $oADOConnection = ObjCreate("ADODB.Connection") ; Das ADODB-Verbindungsobjekt.

	Local $oErrorHandler = ObjEvent("AutoIt.Error", "_ErrFunc") ; Fehlerhandling (bei Objektfehlern wird die Funtkion _ErrFunc aufgerufen.

	; Hier folgt die Verbindungszeichenkette. Infos dazu im ersten Link. Im zweiten Link Erklärung für den hier notwendigen Parameter IMEX=1.
	; https://support.microsoft.com/de-de/kb/278973
	; https://support.microsoft.com/de-de/kb/509360
	Local $sADOConnectionString = 'Provider=Microsoft.Jet.OLEDB.4.0 ' & _
			';Data Source=' & $sFullPath & _
			';Extended Properties="Excel 8.0' & _
			';HDR=NO' & _
			';IMEX=1"'

	$oADOConnection.Open($sADOConnectionString)

	If $bObjectError Then Return SetError(1, 0, 0) ; Bei einem Objektfehler wird der Aufruf zurück an _GetContent_XLS_XLSX gegeben, damit Excel benutzt wird, wenn möglich.

	Local $aSheetnames[0] ; Array, in dem die Tabellennamen gespeichert werden.

	; Beginn: Hier werden die Tabellen-Namen ausgelesen
	Local $oTablesSchema = $oADOConnection.OpenSchema($ADO_adSchemaTables)

	While Not $oTablesSchema.EOF
		_ArrayAdd($aSheetnames, $oTablesSchema.Fields("TABLE_NAME").Value)
		$oTablesSchema.MoveNext
	WEnd
	; Ende: Hier werden die Tabellen-Namen ausgelesen


	Local $iNrOfSheets = UBound($aSheetnames)

	Local $aExcelSheets[$iNrOfSheets] ; Das Rückgabe Array. In jedem Element soll ein Tabellenblatt gespeichert werden. Daher bekommt das Array die Ubound-Größe von $aSheetnames als Elementeanzahl


	; Nun werden in einer Schleife alle Tabellenblätter der Excel-Datei ausgelesen.
	For $i = 0 To $iNrOfSheets - 1

		If $bObjectError Then Return _GetContent_XLS_XLSX($sFullPath) ; Bei einem Objektfehler wird der Aufruf zurück an _GetContent_XLS_XLSX gegeben, damit Excel benutzt wird, wenn möglich.

		$sSNReplace = StringReplace($aSheetnames[$i], "'", "")
		If StringRight($sSNReplace, 1) <> "$" Then ContinueLoop ; Zur Absturzvermeidung: In einer Excel-Datei führte die scheinbar versteckte Tabelle "Druckbereich" zum Absturz nach dem Select Statement!?!

		Local $oADORecordset = ObjCreate("ADODB.Recordset") ; Das Rekordset-Objekt für das jeweilige Tabellenblatt

;~ 		ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & "$sFilename=" & $sFilename & " - $iNrOfSheets=" & $iNrOfSheets & " - $aSheetnames[" & $i & "]=" & $aSheetnames[$i] & @CRLF)

		Local $sSheet = "", $iSheetRows = 0

		Local $sADOSQL = "Select * FROM [" & $aSheetnames[$i] & "]" ; Hier wird in Schleife verwendet zeilenweise alles aus dem Tabellenblatt ausgelesen (Select *).
		$oADORecordset.Open($sADOSQL, $oADOConnection, $iCursorType, $iLockType, $iOptions)

		If $bObjectError Then Return SetError(1, 0, 0) ; Bei einem Objektfehler wird der Aufruf zurück an _GetContent_XLS_XLSX gegeben, damit Excel benutzt wird, wenn möglich.

		With $oADORecordset
			While Not .EOF
				For $oField In .Fields
					$sSheet &= $oField.Value & "|"
				Next
				$sSheet = StringTrimRight($sSheet, 1) & @LF
				$iSheetRows += 1
				.MoveNext
			WEnd
		EndWith

		Local $iSheetCols = 500
		Local $aSheets[$iSheetRows][$iSheetCols] ; Einfach ein großes Array, das alle einträge der aktuellen Tabelle fassen können sollte. Andernfalls ändern.

		; $sSheet ist jetzt ein String mit @LF Umbrüchen nach jeder Zeile und dem Verkettungszeichen | als Trenner zwischen den Spalten.
		; Das wird nun in einigen Umständlichen Operationen zu einem Array gewandelt.
		$sSheet = StringTrimRight($sSheet, 1)
		$aSheet = StringSplit($sSheet, @LF, 2)
		$iColCount = 0
		For $ii = 0 To $iSheetRows - 1
			$aColValues = StringSplit($aSheet[$ii], "|")
			If $aColValues[0] > $iSheetRows Then
				$iSheetCols = $aColValues[0]
				ReDim $aSheets[$iSheetRows][$iSheetCols]
			EndIf
			If $aColValues[0] > $iColCount Then $iColCount = $aColValues[0]
			For $iii = 1 To $aColValues[0]
				$aSheets[$ii][$iii - 1] = $aColValues[$iii]
			Next
		Next

		$oADORecordset.Close ; Recordset Objekt wird geschlossen.
		$oADORecordset = 0

		ReDim $aSheets[$iSheetRows][$iColCount] ; Das große Array wird auf die ermittelte, nötige Größe geschrumpft und in der folgenden Zeile zu einem $aExcelSheets-Element.
		$aExcelSheets[$i] = $aSheets
	Next
	$oADOConnection.Close ; Abschließend wird das Verbindungsobjekt Objekt geschlossen.
	$oADOConnection = 0


	Return $aExcelSheets
EndFunc   ;==>_XLSReadToArray

Func _XPDF_Search($sPDFFile, $sSearch, $iCase = 0, $iFlag = 0, $iStart = 1, $iEnd = 0) ; https://www.autoitscript.com/forum/topic/160718-code-to-extract-plain-text-from-a-pdf-file/?do=findComment&comment=1166469
	; #FUNCTION# ====================================================================================================================
	; Name...........: _XPDF_Search
	; Description....: Retrives informations from a PDF file
	; Syntax.........: _XFDF_Info ( "File" [, "String" [, Case = 0 [, Flag = 0 [, FirstPage = 1 [, LastPage = 0]]]]] )
	; Parameters.....: File    - PDF File.
	;                  String    - String to search for
	;                  Case      - If set to 1, search is case sensitive (default is 0)
	;                  Flag      - A number to indicate how the function behaves. See below for details. The default is 0.
	;                  FirstPage  - First page to convert (default is 1)
	;                  LastPage   - Last page to convert (default is 0 = last page of the document)
	; Return values..: Success -
	;                   Flag = 0 - Returns 1 if the search string was found, or 0 if not
	;                   Flag = 1 - Returns the number of occcurrences found in the whole PDF File
	;                   Flag = 2 - Returns an array containing the number of occurrences found for each page
	;                              (only pages containing the search string are returned)
	;                              $array[0][0] - Number of matching pages
	;                              $array[0][1] - Number of occcurrences found in the whole PDF File
	;                              $array[n][0] - Page number
	;                              $array[n][1] - Number of occcurrences found for the page
	;                  Failure - 0, and sets @error to :
	;                   1 - PDF File not found
	;                   2 - Unable to find the external programm
	; ===============================================================================================================================
	Local $sOptions = " -layout -f " & $iStart
	Local $iCount = 0, $aResult[1][2] = [[0, 0]], $aSearch, $sContent, $iPageOccCount

	If Not FileExists($sPDFFile) Then Return SetError(1, 0, 0)
	If Not FileExists($sXPDF) Then Return SetError(2, 0, 0)

	If $iEnd > 0 Then $sOptions &= " -l " & $iEnd

	Local $iPid = Run($sXPDF & $sOptions & ' "' & $sPDFFile & '" -', @ScriptDir, @SW_HIDE, 2)
	While 1
		$sContent &= StdoutRead($iPid)
		If @error Then ExitLoop
	WEnd


	Local $aPages = StringSplit($sContent, Chr(12))

	For $i = 1 To $aPages[0]
		$iPageOccCount = 0
		While StringInStr($aPages[$i], $sSearch, $iCase, $iPageOccCount + 1)
			If $iFlag <> 1 And $iFlag <> 2 Then
				$aResult[0][1] = 1
				ExitLoop
			EndIf
			$iPageOccCount += 1
		WEnd

		If $iPageOccCount Then
			ReDim $aResult[UBound($aResult, 1) + 1][2]
			$aResult[0][1] += $iPageOccCount
			$aResult[0][0] = UBound($aResult) - 1
			$aResult[UBound($aResult, 1) - 1][0] = $i + $iStart - 1
			$aResult[UBound($aResult, 1) - 1][1] = $iPageOccCount
		EndIf
	Next

	If $iFlag = 2 Then Return $aResult
	Return $aResult[0][1]

EndFunc   ;==>_XPDF_Search

Func _XPDF_ToText($sPDFFile, $sTXTFile, $sTXTPath = @ScriptDir, $iFirstPage = 1, $iLastPage = 0, $bLayout = True) ; https://www.autoitscript.com/forum/topic/160718-code-to-extract-plain-text-from-a-pdf-file/?do=findComment&comment=1166469
	; #FUNCTION# ====================================================================================================================
	; Name...........: _XPDF_ToText
	; Description....: Converts a PDF file to plain  text.
	; Syntax.........: _XPDF_ToText ( "PDFFile" , "TxtFile" [ TxtPath[, FirstPage [, LastPage [, Layout ]]]] )
	; Parameters.....: PDFFile    - PDF Input File.
	;                  TxtFile    - Plain text fileneme to convert to
	;                  TxtPath    - Path to the txt file (default is @ScriptDir)
	;                  FirstPage  - First page to convert (default is 1)
	;                  LastPage   - Last page to convert (default is last page of the document)
	;                  Layout     - If true, maintains (as  best as possible) the original physical layout of the text
	;                               If false, the behavior is to 'undo'  physical  layout  (columns, hyphenation, etc.)
	;                                 and output the text in reading order.
	;                               Default is True
	; Return values..: Success - 1
	;                  Failure - 0, and sets @error to :
	;                   1 - PDF File not found
	;                   2 - Unable to find the external program
	; ===============================================================================================================================
	Local $sOptions

	If Not FileExists($sPDFFile) Then Return SetError(1, 0, 0)
	If Not FileExists($sXPDF) Then Return SetError(2, 0, 0)

	If $iFirstPage <> 1 Then $sOptions &= " -f " & $iFirstPage
	If $iLastPage <> 0 Then $sOptions &= " -l " & $iLastPage
	If $bLayout = True Then $sOptions &= " -layout"

	Local $iReturn = ShellExecuteWait($sXPDF, $sOptions & ' "' & $sPDFFile & '" "' & $sTXTFile & '"', $sTXTPath, "", @SW_HIDE)
	If $iReturn = 0 Then Return 1

	Return 0

EndFunc   ;==>_XPDF_ToText

#Region XLSXReadToArray-UDF ; https://www.autoitscript.com/forum/topic/145160-_xlsxreadtoarray-using-only-autoit/
#include-once

; #UDF# =======================================================================================================================
; Title .........: XLSX Read To Array
; AutoIt Version : 3.3.8.1
; Language ......: English
; Description ...: Fuction Reads the EXCEL XLSX Sheet into an Array
; Author(s) .....: DXRW4E
; Notes .........:
; ===============================================================================================================================

; #CURRENT# =====================================================================================================================
;~ _XLSXReadToArray
;~ _XLSXSheetGetColumnNumber
;~ _SSNToDate
;~ _DateToSSN
;~ _FileListToArrayEx
; ===============================================================================================================================

; Folgende zwei Zeilen in die Deklarationen am Anfang aufgenommen.
;~ If Not ObjEvent("AutoIt.Error") Then Global Const $_XLSXZip_COMErrorFunc = ObjEvent("AutoIt.Error", "_XLSXZip_COMErrorFunc")
;~ Global $DateSSN[27] = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]

; #FUNCTION# ================================================================================================================================
; Name...........: _XLSXReadToArray
; Description ...: The _XLSXReadToArray Fuction Reads the EXCEL XLSX Sheet into an Array
; Syntax.........: _XLSXReadToArray($XLSXFilePath, $iFlag)
; Parameters ....: $XLSXFilePath - Path and filename of the XLSX file to be read.
;                  $iFlag   - Optional
;                  |$iFlag = 0 (Default) None
;                  |$iFlag = 1 if there are also add HyperLinks in the Array
;                    Strings\Test in Column\Rows will separate from HyperLink by @LF, example "Value" & @LF & http://www.autoitscript.com/forum/
;                  |$Cols   - Optional, Columns Number to Read (read only X column)
;                  |$Rows   - Optional, Rows Number to Read (read only X Row)
;                  |$iSheet - Optional, Number of Sheet*.xml to Read, Default is 1
; Return values .: Success  - Return
;                    Array ($Array[0][0] = Rows Number & @Extended = Column Nmmber)
;                    If Set $Cols and $Rows Return is String Data, if Return Strigs = "" @Extended is Set to 1
;                  @Error - Set Error
;                  |1 = XLSX file not found or invalid (Can not Read\Extract XLSX file)
;                  |2 = [Content_Types].xml not found or invalid
;                  |3 = sheet1.xml file not found or invalid
;                  |4 = Sheet Dimension Not found Or is Greater than 15999999 (Array Size Limit)
;                  |5 = No SheetDate (Columns & Rows) Found
; Author ........: DXRW4E
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: __XLSXReadToArray("C:\file.xlsx")
; Note ..........:
; ===========================================================================================================================================
Func _XLSXReadToArray($XLSXFilePath, $iFlag = 0, $Cols = 0, $Rows = 0, $iSheet = 1)
	If ($Cols * ($Rows + 1)) > 15999999 Then Return SetError(4, 0, "")
	Local $XLSXExtractDir = @WindowsDir & "\Temp\XLSX_" & @YEAR & @MON & @MDAY & @HOUR & @MIN & @SEC & @MSEC, $XLSXZip, $oShell, $X

	$XLSXZip = FileCopy($XLSXFilePath, $XLSXExtractDir & "\__xlsx.zip", 9)
	If Not $XLSXZip Then Return SetError(1, DirRemove($XLSXExtractDir, 1), "")
	$oShell = ObjCreate("shell.application")
	$oShell.Namespace($XLSXExtractDir).CopyHere($oShell.Namespace($XLSXExtractDir & "\__xlsx.zip").items, 20)

	Local $ContentTypesXML = StringReplace(FileRead($XLSXExtractDir & "\[Content_Types].xml"), "/", "\", 0, 1)
	If Not $ContentTypesXML Then
		$ContentTypesXML = _FileListToArrayEx($XLSXExtractDir, "*Content*Types*.xml", 37)
		If Not @error Then $ContentTypesXML = StringReplace(FileRead($XLSXExtractDir & "\" & $ContentTypesXML[0]), "/", "\", 0, 1)
		If Not $ContentTypesXML Then Return SetError(2, DirRemove($XLSXExtractDir, 1), "")
	EndIf
	Local $SharedStringsXMLPath = StringRegExp($ContentTypesXML, '(?si)<Override\s*PartName="([^"]*\\sharedStrings\.xml)"', 1)
	If @error Then $SharedStringsXMLPath = _FileListToArrayEx($XLSXExtractDir, "sharedStrings.xml", 165)
	If Not @error Then $SharedStringsXMLPath = $XLSXExtractDir & $SharedStringsXMLPath[0]
	Local $SheetXMLPath = StringRegExp($ContentTypesXML, '(?si)<Override\s*PartName="([^"]*\\sheet' & $iSheet & '\.xml)"', 1)
	If @error Then $SheetXMLPath = _FileListToArrayEx($XLSXExtractDir, "sheet" & $iSheet & ".xml", 165)
	If @error Then $SheetXMLPath = StringRegExp($ContentTypesXML, '(?si)<Override\s*PartName="([^"]*\\sheet[^"]*\.xml)"', 1)
	If @error Then $SheetXMLPath = _FileListToArrayEx($XLSXExtractDir, "sheet*.xml", 165)
	If Not @error Then $SheetXMLPath = $XLSXExtractDir & $SheetXMLPath[0]

	Local $WorkSheet = FileRead($SheetXMLPath)
	If Not $WorkSheet Then Return SetError(3, DirRemove($XLSXExtractDir, 1), "")
	Local $SharedStringsXML = FileRead($SharedStringsXMLPath)

	;;  	Example Get File Path using the StringRegExpReplace(), but more slowly than StringRegExp Mod.
	;;  Local $WorkBookXMLPath = $XLSXExtractDir & StringRegExpReplace($ContentTypesXML, '(?si).*<Override\s+PartName="([^"]*\\workbook\.xml)".*', "$1")
	;;  Local $StylesXMLPath = $XLSXExtractDir & StringRegExpReplace($ContentTypesXML, '(?si).*<Override\s+PartName="([^"]*\\styles\.xml)".*', "$1")
	;;  Local $SharedStringsXMLPath = $XLSXExtractDir & StringRegExpReplace($ContentTypesXML, '(?si).*<Override\s+PartName="([^"]*\\sharedStrings\.xml)".*', "$1")
	;;  Local $SheetXMLPath = $XLSXExtractDir & StringRegExpReplace($ContentTypesXML, '(?si).*<Override\s+PartName="([^"]*\\sheet1\.xml)".*', "$1")
	;;
	;;	  ;; read other ect ect ect
	;;  Local $WorkBookXMLPath = StringRegExp($ContentTypesXML, '(?si)<Override\s*PartName="([^"]*\\workbook\.xml)"', 1)
	;;  If @Error Then $WorkBookXMLPath = _FileListToArrayEx($XLSXExtractDir, "workbook.xml", 165)
	;; 	If Not @Error Then $WorkBookXMLPath = $XLSXExtractDir & $WorkBookXMLPath[0]
	;;  $WorkBookXML = FileRead($WorkBookXMLPath)
	;;    ;Example using the StringRegExpReplace()
	;;	Local $SheetName = $XLSXExtractDir & StringRegExpReplace($WorkBookXML, '(?si).*<sheet\s+name="([^"]*)".*', "$1")
	;;
	;;  Local $AppXMLPath = StringRegExp($ContentTypesXML, '(?si)<Override\s*PartName="([^"]*\\app\.xml)"', 1)
	;;  If @Error Then $AppXMLPath = _FileListToArrayEx($XLSXExtractDir, "app.xml", 165)
	;; 	If Not @Error Then $AppXMLPath = $XLSXExtractDir & $AppXMLPath[0]
	;;  $AppXML = FileRead($AppXMLPath)
	;;    ;Example using the StringRegExpReplace()
	;;	Local $AppVersion = $XLSXExtractDir & StringRegExpReplace($AppXML, '(?si).*<AppVersion>([^<]*)</AppVersion>.*', "$1")
	;;
	;;  Local $CoreXMLPath = StringRegExp($ContentTypesXML, '(?si)<Override\s*PartName="([^"]*\\core\.xml)"', 1)
	;;  If @Error Then $CoreXMLPath = _FileListToArrayEx($XLSXExtractDir, "core.xml", 165)
	;; 	If Not @Error Then $CoreXMLPath = $XLSXExtractDir & $CoreXMLPath[0]
	;;  $CoreXML = FileRead($CoreXMLPath)
	;;    ;Example using the StringRegExpReplace()
	;;	Local $Modified = $XLSXExtractDir & StringRegExpReplace($CoreXML, '(?si).*<dcterms\:modified[^>]([^<]*)</dcterms:modified>.*', "$1")
	;;
	;;  Local $StylesXMLPath = StringRegExp($ContentTypesXML, '(?si)<Override\s*PartName="([^"]*\\styles\.xml)"', 1)
	;;  If @Error Then $StylesXMLPath = _FileListToArrayEx($XLSXExtractDir, "styles.xml", 165)
	;;  If Not @Error Then $StylesXMLPath = $XLSXExtractDir & $StylesXMLPath[0]
	;;	$StylesXML = FileRead($StylesXMLPath)
	;;  ;ect ect ect ect
	;;
	;;  Local $SheetViews = StringRegExp($WorkSheet, '(?si)<sheetView\s+tabSelected="([^"]*)".*?\sworkbookViewId="([^"]*)".*?\stopLeftCell="([A-Z]{1,3})([0-9]+)".*?\sactiveCell="([A-Z]{1,3})([0-9]+)".*?\sdefaultRowHeight="([^"]*)"', 1)
	;;  If @Error Then Local $SheetViews[7]
	;;  $SheetViews[2] = _XLSXSheetGetColumnNumber($SheetViews[2])
	;;  $SheetViews[4] = _XLSXSheetGetColumnNumber($SheetViews[4])
	;;  ;;;;  $SheetViews....
	;;  ;;;;	$SheetViews[0] = tabSelected
	;;  ;;;;	$SheetViews[1] = workbookViewId
	;;  ;;;;	$SheetViews[2] = top Left Cell - Column Number
	;;  ;;;;	$SheetViews[3] = top Left Cell - Rows Nmmber
	;;  ;;;;	$SheetViews[4] = active Cell - Column Number
	;;  ;;;;	$SheetViews[5] = active Cell - Rows Nmmber
	;;  ;;;;	$SheetViews[6] = default Row Height
	DirRemove($XLSXExtractDir, 1)
	Local $nCols = Number($Cols), $nRows = "[0-9]+", $X = StringRegExp($WorkSheet, '(?si)<([^:><]*:?)?worksheet\s+', 1)
	If Not @error Then $X = $X[0]
	If $Rows > 0 Then ;;;;	StringRegExp($WorkSheet, '(?s)<' & $X & 'row\s+r="' & $Rows  & '".*?</' & $X & 'row>', 1)
		$nRows = $Rows
		$Rows = 1
	EndIf
	Local $SheetDimension = StringRegExp($WorkSheet, '(?si)<' & $X & '(?:dimension|autoFilter)\s+ref="([A-Z]{1,3})([0-9]+):([A-Z]{1,3})(?i)([0-9]+)', 1)
	If Not @error Then
		$Cols = _XLSXSheetGetColumnNumber($SheetDimension[2])
		If $nRows = "[0-9]+" Then $Rows = $SheetDimension[3]
	EndIf
	$SheetDimension = StringRegExp($WorkSheet, '(?si)<' & $X & 'col\s+min="?(\d+)[^>]*></' & $X & 'cols>', 1)
	If Not @error And $SheetDimension[0] > $Cols Then $Cols = $SheetDimension[0]
	If $nRows = "[0-9]+" Then
		$SheetDimension = StringRegExp($WorkSheet, '(?si).*<' & $X & 'c\s+r="?[A-Z]*(\d+)', 1)
		If Not @error And $SheetDimension[0] > $Rows Then $Rows = $SheetDimension[0]
	EndIf
	If $nCols > ($Cols + 1) Then Return SetError(5, 0, "")
	If $Cols < 1 Or $Rows < 1 Or ($Cols * ($Rows + 1)) > 15999999 Then Return SetError(4, 0, "")
	Local $SheetData = StringRegExp($WorkSheet, '(?s)<' & $X & 'c\s+r="([A-Z]{1,3})(?i)(' & $nRows & ')"\s*(?:s=")?([0-9]*)"?\s*(?:t=")?([^">]*)"?\s*><' & $X & 'v>([^<]*)\s*</' & $X & 'v>\s*</' & $X & 'c>', 3)
	If @error Then Return SetError(5, 0, "")
	If $nCols Then $Cols = 1
	Local $SheetDataA[($Rows + 1)][$Cols] = [[UBound($SheetData) - 1]], $ColumnName, $ColumnNumber, $ColumnSize, $SharedStringsXMLSize
	If $SharedStringsXML Then
		Local $S = StringRegExp($SharedStringsXML, '(?si)<([^:><]*:?)?sst\s+', 1)
		If Not @error Then $S = $S[0]
		$SharedStringsXML = StringRegExp($SharedStringsXML, '(?si)<' & $S & 'si>(?:<' & $S & 'r>.*?)?<' & $S & 't(?:/|\s[^>]*)?>(.*?)(?:</' & $S & 't>)?(?:</' & $S & 'r>)?</' & $S & 'si>', 3)
		If Not @error Then
			$SharedStringsXMLSize = UBound($SharedStringsXML)
			For $i = 0 To $SharedStringsXMLSize - 1
				If StringInStr($SharedStringsXML[$i], "<", 1) Then $SharedStringsXML[$i] = StringRegExpReplace($SharedStringsXML[$i], '</' & $S & 't>.*?<' & $S & 't>', "")
				If StringInStr($SharedStringsXML[$i], "&", 1) Then $SharedStringsXML[$i] = StringReplace(StringReplace(StringReplace($SharedStringsXML[$i], "&lt;", "<", 0, 1), "&gt;", ">", 0, 1), "&amp;", "&", 0, 1)
			Next
		EndIf
	EndIf
	For $i = 0 To $SheetDataA[0][0] Step 5
		$ColumnSize = StringLen($SheetData[$i]) - 1
		If Not $ColumnSize Then
			$ColumnNumber = Asc($SheetData[$i]) - 65
		Else
			$ColumnName = StringToASCIIArray($SheetData[$i])
			$ColumnNumber = $ColumnName[$ColumnSize] - 65
			$ColumnNumber += 26 * ($ColumnName[$ColumnSize - 1] - 64) ;(26 ^ 1) * ($ColumnName[1] - 64)
			If $ColumnSize > 1 Then $ColumnNumber += 676 * ($ColumnName[0] - 64) ;(26 ^ 2) * ($ColumnName[0] - 64)
			;;;$ColumnNumber = _XLSXSheetGetColumnNumber($SheetData[$i], 1)
		EndIf
		If $nCols Then
			If $nCols <> ($ColumnNumber + 1) Then ContinueLoop
			$ColumnNumber = 0
		EndIf
		If $Rows = 1 Then $SheetData[$i + 1] = 1
		If $SheetData[$i + 3] = "s" And $SharedStringsXMLSize > $SheetData[$i + 4] Then
			$SheetDataA[$SheetData[$i + 1]][$ColumnNumber] = $SharedStringsXML[$SheetData[$i + 4]]
		ElseIf $SheetData[$i + 2] = 2 Then
			$SheetDataA[$SheetData[$i + 1]][$ColumnNumber] = _SSNToDate($SheetData[$i + 4])
		Else
			$SheetDataA[$SheetData[$i + 1]][$ColumnNumber] = $SheetData[$i + 4]
		EndIf
	Next
	$SheetDataA[0][0] = $Rows
	If $iFlag Then
		$HyperLinks = StringRegExp($WorkSheet, '(?si)<' & $X & 'hyperlink\s+ref="([A-Z]{1,3})(?i)(' & $nRows & ')".*?\s+display="([^"]*)"', 3)
		;;$HyperLinks = StringRegExp($WorkSheet, '(?si)<' & $X & 'hyperlink\s+ref="([A-Z]{1,3})(?i)' & $nRows & '"\s+r:id="([^"]*)"\s+display="([^"]*)"', 3)
		If Not @error Then
			Local $HyperLinksSize = UBound($HyperLinks) - 1
			For $i = 0 To $HyperLinksSize Step 3
				$ColumnNumber = _XLSXSheetGetColumnNumber($HyperLinks[$i], 1)
				If $Rows = 1 Then $HyperLinks[$i + 1] = 1
				$SheetDataA[$HyperLinks[$i + 1]][$ColumnNumber] &= @LF & $HyperLinks[$i + 2]
			Next
		EndIf
	EndIf
	If $nCols And $Rows = 1 Then Return SetError(0, $SheetDataA[1][0] = "", $SheetDataA[1][0])
	Return SetError(0, UBound($SheetDataA, 2), $SheetDataA)
EndFunc   ;==>_XLSXReadToArray


; #FUNCTION# =================================================================================================================
; Name...........: _XLSXSheetGetColumnNumber
; Description ...: The _XLSXSheetGetColumnNumber Fuction return Column Number of EXCEL XLSX Sheet
; Syntax.........: _XLSXSheetGetColumnNumber($ColumnName)
; Parameters ....: $ColumnName - [A-Z] Uppercase Caracter\String, are not Supported line with more than 3 characters
;                  $iFlag      - Optional
;                  |$iFlag = 0 (Default) Column Number
;                  |$iFlag = 1 Column Number - 1 (for Array Index 0)
; Return values .: Success  - Return Column Number
;                  Failure - @Error
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: Limit is 18278 (A = 1 & AB = 27 & ZZZ = 18278)
; Related .......:
; Link ..........:
; Example .......: _XLSXSheetGetColumnNumber("ABC")
; Note ..........:
; ============================================================================================================================
Func _XLSXSheetGetColumnNumber($ColumnName, $iFlag = 0)
	If Not StringRegExp($ColumnName, '^[A-Z]{1,3}$') Or $iFlag < 0 Or $iFlag > 1 Then Return SetError(1, 0, 0)
	Local $ColumnNumber, $SheetDimension = StringLen($ColumnName) - 1
	If Not $SheetDimension Then
		$ColumnNumber = Asc($ColumnName) - 64 - $iFlag
	Else
		$ColumnName = StringToASCIIArray($ColumnName)
		$ColumnNumber = $ColumnName[$SheetDimension] - 64 - $iFlag
		$ColumnNumber += 26 * ($ColumnName[$SheetDimension - 1] - 64) ;(26 ^ 1) * ($ColumnName[1] - 64)
		If $SheetDimension > 1 Then $ColumnNumber += 676 * ($ColumnName[0] - 64) ;(26 ^ 2) * ($ColumnName[0] - 64)
	EndIf
	Return $ColumnNumber
EndFunc   ;==>_XLSXSheetGetColumnNumber


; #FUNCTION# =================================================================================================================
; Name...........: _SSNToDate
; Description ...: The _SSNToDate Fuction return Date from sequential serial number
; Syntax.........: _SSNToDate($iDay)
; Parameters ....: $iDay - sequential serial number (generated from DATE fuction on EXCEL, example 39637 = 7/8/2008)
; Return values .: Success  - Return DATE
;                  Failure - @Error
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: DATE String is Month/Day/Year, Year - is number is 1900 to 9999
; Related .......:
; Link ..........:
; Example .......: _SSNToDate(39637)
; Note ..........:
; ============================================================================================================================
Func _SSNToDate($iDay)
	If $iDay < 1 Or $iDay > 2958465 Then Return SetError(1, 0, "")
	$DateSSN[0] = Int($iDay / 365)
	$DateSSN[25] = $DateSSN[0] / 4
	$DateSSN[26] = IsFloat($DateSSN[25])
	$iDay = $iDay - ($DateSSN[0] * 365) - Int($DateSSN[25]) - $DateSSN[26]
	If $iDay < 1 Then
		$DateSSN[0] -= 1
		$DateSSN[25] = IsInt(($DateSSN[0] - 1) / 4)
		$iDay += 365 + $DateSSN[25]
		$DateSSN[26] = Int($DateSSN[25] = 0)
	EndIf
	$DateSSN[2] -= $DateSSN[26]
	For $iMonth = 1 To 11
		If $DateSSN[$iMonth] >= $iDay Then ExitLoop
		$iDay -= $DateSSN[$iMonth]
	Next
	$DateSSN[2] += $DateSSN[26]
	Return $iMonth & "/" & $iDay & "/" & (1900 + $DateSSN[0])
EndFunc   ;==>_SSNToDate


; #FUNCTION# =================================================================================================================
; Name...........: _DateToSSN
; Description ...: The _DateToSSN Fuction return sequential serial number that represent a particular Date
; Syntax.........: _DateToSSN($iYear, $iMonth, $iDay)
; Parameters ....: $iYear  - Year  - is number is 1900 to 9999
;                      Required. The value of the year argument can include one to four digits. Excel interprets the year argument
;                      according to the date system your computer is using. By default, Microsoft Excel for Windows uses the 1900 date system.
;                      We recommend using four digits for the year argument to prevent unwanted results. For example, "07" could mean "1907" or "2007." Four digit years prevent confusion.
;                      If year is between 0 (zero) and 1899 (inclusive), Excel adds that value to 1900 to calculate the year. For example, DATE(108,1,2) returns January 2, 2008 (1900+108).
;                      If year is between 1900 and 9999 (inclusive), Excel uses that value as the year. For example, _DateToSSN((2008,1,2) returns January 2, 2008.
;                      If year is less than 0 or is 10000 or greater, _DateToSSN returns the @Error
;                  $iMonth - is number is 1 to 12, If Month is less than 0 or is 13 or greater, _DateToSSN returns the @Error
;                  $iDay   - Required. A positive or negative integer representing the day of the month from 1 to 31.
;                      If day is greater than the number of days in the month specified, day adds that number of days to the first day in the month.
;                        For example, _DateToSSN(2008,1,35) returns the serial number representing February 4, 2008.
;                      If day is less than 1, day subtracts the magnitude that number of days, plus one, from the first day of the month specified.
;                        For example, _DateToSSN(2008,1,-15) returns the serial number representing December 16, 2007.
; Return values .: Success  - Return Sequential Serial Number
;                  Failure - @Error
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: Sequential Serial Number, _DateToSSN(2008, 7, 8) Return 39637, that represent 7/8/2008
;
;                    NOTE - Excel stores dates as sequential serial numbers so that they can be used in calculations. January 1, 1900 is serial number 1,
;                      and January 1, 2008 is serial number 39448 because it is 39,447 days after January 1, 1900.
;
;                    _DateToSSN NOT SUPPORT FOR NOW, THIS
;                      $iMonth Required. A positive or negative integer representing the month of the year from 1 to 12 (January to December).
;                        If month is greater than 12, month adds that number of months to the first month in the year specified. For example,
;                        DATE(2008,14,2) returns the serial number representing February 2, 2009.
;                      If month is less than 1, month subtracts the magnitude of that number of months, plus 1, from the first month in the
;                        year specified. For example, DATE(2008,-3,2) returns the serial number representing September 2, 2007.
; Related .......:
; Link ..........:
; Example .......: _DateToSSN(39637)
; Note ..........:
; ============================================================================================================================
Func _DateToSSN($iYear, $iMonth, $iDay)
	If $iYear < 1900 Or $iYear > 9999 Or $iMonth < 1 Or $iMonth > 12 Then Return SetError(1, 0, "")
	$iYear -= 1900
	$DateSSN[0] = $iYear / 4
	If IsFloat($DateSSN[0]) And $iMonth < 3 Then $iDay += 1
	Return ($iYear * 365) + Int($DateSSN[0]) + $DateSSN[$iMonth + 12] + $iDay
EndFunc   ;==>_DateToSSN


; #FUNCTION# =======================================================================================================================================================
; Name...........: _FileListToArrayEx
; Description ...: Lists files and\or folders in a specified path (Similar to using Dir with the /B Switch)
; Syntax.........: _FileListToArrayEx($sPath[, $sFilter = "*"[, $iFlag = 0]])
; Parameters ....: $sPath   - Path to generate filelist for.
;                  $sFilter - Optional the filter to use, default is *. (Multiple filter groups such as "All "*.png|*.jpg|*.bmp") Search the Autoit3 helpfile for the word "WildCards" For details.
;                  $iFlag   - Optional: specifies whether to return files folders or both Or Full Path (add the flags together for multiple operations):
;                  |$iFlag = 0 (Default) Return both files and folders
;                  |$iFlag = 1 Return files only
;                  |$iFlag = 2 Return Folders only
;                  |$iFlag = 4 Search SubDirectory
;                  |$iFlag = 8 Return Full Path
;                  |$iFlag = 16 $sFilter do Case-Sensitive matching (By Default $sFilter do Case-Insensitive matching)
;                  |$iFlag = 32 Disable the return the count in the first element - effectively makes the array 0-based (must use UBound() to get the size in this case).
;                    By Default the first element ($array[0]) contains the number of file found, the remaining elements ($array[1], $array[2], etc.)
;                  |$iFlag = 64 $sFilter is REGEXP Mod, See Pattern Parameters in StringRegExp (Can not be combined with flag 16)
;                  |$iFlag = 128 Return Backslash at the beginning of the file name, example Return "\Filename1.xxx" (Can not be combined with flag 8)
; Return values .: Failure - @Error
;                  |1 = Path not found or invalid
;                  |2 = Invalid $sFilter
;                  |3 = No File(s) Found
; Author ........: DXRW4E
; Modified.......:
; Remarks .......: The array returned is one-dimensional and is made up as follows:
;                                $array[0] = Number of Files\Folders returned
;                                $array[1] = 1st File\Folder
;                                $array[2] = 2nd File\Folder
;                                $array[3] = 3rd File\Folder
;                                $array[n] = nth File\Folder
; Related .......:
; Link ..........:
; Example .......: Yes
; Note ..........: Special Thanks to SolidSnake & Tlem
; ==================================================================================================================================================================
Func _FileListToArrayEx($sPath, $sFilter = "*", $iFlag = 0)
	$sPath = StringRegExpReplace($sPath & "\", "[\\/]+", "\\")
	If Not FileExists($sPath) Then Return SetError(1, 1, "")
	If StringRegExp($sFilter, StringReplace('^\s*$|\v|[\\/:><"]|^\||\|\||\|$', "[" & Chr(BitAND($iFlag, 64) + 28) & '\/:><"]|^\||\|\||\|$', "\\\\")) Then Return SetError(2, 2, "")
	Local $hSearch, $sFile, $sFileList, $sSubDir = BitAND($iFlag, 4), $sDelim = "|", $sDirFilter = StringReplace($sFilter, "*", "")
	$hSearch = FileFindFirstFile($sPath & "*")
	If @error Then Return SetError(3, 3, "")
	Local $hWSearch = $hSearch, $hWSTMP, $SearchWD, $Extended, $iFlags = StringReplace(BitAND($iFlag, 1) + BitAND($iFlag, 2), "3", "0")
	If BitAND($iFlag, 8) Then $sDelim &= $sPath
	If BitAND($iFlag, 128) Then $sDelim = "|\"
	If Not BitAND($iFlag, 64) Then $sFilter = StringRegExpReplace(BitAND($iFlag, 16) & "(?i)(", "16\(\?\i\)|\d+", "") & StringRegExpReplace(StringRegExpReplace(StringRegExpReplace(StringRegExpReplace($sFilter, "[^*?|]+", "\\Q$0\\E"), "\\E(?=\||$)", "$0\$"), "(?<=^|\|)\\Q", "^$0"), "\*+", ".*") & ")"
	While 1
		$sFile = FileFindNextFile($hWSearch)
		If @error Then
			If $hWSearch = $hSearch Then ExitLoop
			FileClose($hWSearch)
			$hWSearch -= 1
			$SearchWD = StringLeft($SearchWD, StringInStr(StringTrimRight($SearchWD, 1), "\", 1, -1))
		ElseIf $sSubDir Then
			$Extended = @extended
			If ($iFlags + $Extended <> 2) Then
				If $sDirFilter Then
					If StringRegExp($sFile, $sFilter) Then $sFileList &= $sDelim & $SearchWD & $sFile
				Else
					$sFileList &= $sDelim & $SearchWD & $sFile
				EndIf
			EndIf
			If Not $Extended Then ContinueLoop
			$hWSTMP = FileFindFirstFile($sPath & $SearchWD & $sFile & "\*")
			If $hWSTMP = -1 Then ContinueLoop
			$hWSearch = $hWSTMP
			$SearchWD &= $sFile & "\"
		Else
			If ($iFlags + @extended = 2) Or StringRegExp($sFile, $sFilter) = 0 Then ContinueLoop
			$sFileList &= $sDelim & $sFile
		EndIf
	WEnd
	FileClose($hSearch)
	If Not $sFileList Then Return SetError(3, 3, "")
	Return StringSplit(StringTrimLeft($sFileList, 1), "|", StringReplace(BitAND($iFlag, 32), "32", 2))
EndFunc   ;==>_FileListToArrayEx


Func _XLSXZip_COMErrorFunc()
	Return SetError(1, 0, "")
EndFunc   ;==>_XLSXZip_COMErrorFunc
#EndRegion XLSXReadToArray-UDF ; https://www.autoitscript.com/forum/topic/145160-_xlsxreadtoarray-using-only-autoit/

; ### Ende Funktionen: Dateien lesen ###




; ### Funktionen: Anzeige von Texten und Tabellen in GUIs ###

Func _ShowLines($sFullPath) ; Anzeige der Trefferzeilen in der MainGUI

	Local $iIndex = _ArraySearch($aSQLResultFiles, $sFullPath) ; Hier wird nach der Datei im Array $aSQLFiles gesucht..
	If @error Then
		_GUICtrlRichEdit_PauseRedraw($idLE_LinesMainGUI)
		_GUICtrlRichEdit_SetText($idLE_LinesMainGUI, "Keine Vorschau vorhanden. Die Datei wurde verschoben oder gelöscht!") ; Vorschau wird gefüllt.
		_GUICtrlRichEdit_SetSel($idLE_LinesMainGUI, 0, -1)
		_GUICtrlRichEdit_SetCharAttributes($idLE_LinesMainGUI, "+bo")
		_GUICtrlRichEdit_SetFont($idLE_LinesMainGUI, 12, "Segoe UI") ; Schriftgröße wird gesetzt.
		_GUICtrlRichEdit_SetSel($idLE_LinesMainGUI, 0, 0)
		_GUICtrlRichEdit_ResumeRedraw($idLE_LinesMainGUI)
		Return 0
	EndIf
	$aLineSplit = StringSplit($aSQLResultFiles[$iIndex][2], @LF) ; .. und der Inhalt in Linefeeds getrennt.

	Local $sPreview = ""
	Local $iMaxIndex = UBound($aSearchString) ; Jeder Absatz wird nun nach allen Begriffen aus dem Array $aSearchString durchsucht.
	For $i = 1 To $aLineSplit[0]
		For $ii = 0 To $iMaxIndex - 1
			If StringInStr($aLineSplit[$i], $aSearchString[$ii]) Then
				If Not StringInStr($sPreview, "Absatz " & $i) Then ; um doppelte Einträge bei mehreren Treffern in einer Zeile zu vermeiden.
					$sPreview &= "Absatz " & $i & " --> " & $aLineSplit[$i]
				EndIf
			EndIf
		Next
	Next
	_GUICtrlRichEdit_PauseRedraw($idLE_LinesMainGUI)
	_GUICtrlRichEdit_SetText($idLE_LinesMainGUI, $sPreview) ; Vorschau wird gefüllt.
	$sString = _GUICtrlRichEdit_GetText($idLE_LinesMainGUI)
	Local $iStringLen
	Local $sAllHits = ""
	For $i = 0 To $iMaxIndex - 1
		$iStringLen = StringLen($aSearchString[$i])
		For $ii = 1 To 10000 ; Die Suchtreffer werden markiert. Einfach mal blind 10000 mögliche Treffer gesetzt.
			$iPosition = StringInStr($sString, $aSearchString[$i], 0, $ii)
			If $iPosition <> 0 Then ; Treffer werden in der Vorschau markiert.
				$iPosition -= 1
				_GUICtrlRichEdit_SetSel($idLE_LinesMainGUI, $iPosition, $iPosition + $iStringLen)
;~ 			_GUICtrlRichEdit_SetCharColor ($idLE_LinesMainGUI, 255)
				_GUICtrlRichEdit_SetCharAttributes($idLE_LinesMainGUI, "+bo")
;~ 			_GUICtrlRichEdit_SetCharAttributes($idLE_LinesMainGUI, "+un")
				$sAllHits &= $iPosition & "|"
			Else
				ExitLoop ; Wenn kein Treffer mehr erzielt wird, endet die Schleife.
			EndIf
		Next
	Next
	_GUICtrlRichEdit_SetSel($idLE_LinesMainGUI, 0, -1)
	_GUICtrlRichEdit_SetFont($idLE_LinesMainGUI, 12, "Segoe UI") ; Schriftgröße wird gesetzt.
	_GUICtrlRichEdit_SetSel($idLE_LinesMainGUI, 0, 0)
	_GUICtrlRichEdit_ResumeRedraw($idLE_LinesMainGUI)
	GUICtrlSetState($idLV_MainGUI, $GUI_FOCUS)
EndFunc   ;==>_ShowLines

Func _Show_ArrayInGUI($aData)

	$iListposition = 1 ; Legt die Sprungposition der Buttons Zurück und Vor in den Anzeigefenstern auf die erste Position fest. (Wichtig falls vorher schon in einer Anzeige gesprungen wurde). Siehe dazu in der Funktion MainLoop die Buttons $idB_ListNext und $idB_ListPrev.
	$bExpanded = False ; Die Tabellenansicht startet mit Standardgröße für die Zellen. (Wichtig falls vorher die ausgeklappte Ansicht gewählt wurde).

	GUISetState(@SW_HIDE, $hDocGUI)

	_GUICtrlListView_BeginUpdate($idLV_ListArrays)

	_GUICtrlListView_DeleteAllItems($idLV_ListArrays) ; Listview wird geleert.

	Local $sAllHits = ""
	Local $iLvColumms = _GUICtrlListView_GetColumnCount($idLV_ListArrays) ; Spaltenanzahl wird ermittelt.

	For $i = $iLvColumms To 0 Step -1 ; die Spalten der bisherigen Listview löschen.
		_GUICtrlListView_DeleteColumn($idLV_ListArrays, $i)
	Next

	Local $iCols = UBound($aData, 2) ; Benötigte Spalten und Zeilen für die Listview.
	Local $iRows = UBound($aData)

	If $iCols = 0 Then ; Wenn die Excel UDF benutzt wird und ein Excel Sheet nur eine Spalte hat, wird nur ein eindimensionales Array zurückgegeben. Zum unfallfreien Füllen der Listview wird es zu einem zweidimensionalen Array gewandelt.
		_ArrayColInsert($aData, 1)
		$iCols += 1
	EndIf

	Local $aColumnsLetters = _ExcelColumnsLetters() ; In diesem Array sind die Buchstaben für die Spaltenüberschriften der ListGUI gespeichert (A, B, C, .., AA, ...).

	For $i = 0 To $iCols - 1 ; Die nun benötgten Spalten Spalten für die Listview erstellen.
		_GUICtrlListView_AddColumn($idLV_ListArrays, $aColumnsLetters[$i], 200)
	Next

	Local $iSearchMax = UBound($aSearchString), $iIndex = -1

	For $i = 0 To $iSearchMax - 1 ; In dieser Schleife werden Vorkommen der Suchbegriffe gesucht unf Treffer über $sAllHits in das Array $aAllHits aufgenommen.
		For $ii = 0 To UBound($aData) - 1
			$iIndex = _ArraySearch($aData, $aSearchString[$i], $iIndex + 1, 0, 0, 1, 1, -1)
			If $iIndex = -1 Then ExitLoop
			$sAllHits &= $iIndex & "|"
		Next
	Next

	$sAllHits = StringTrimRight($sAllHits, 1) ; Der String mit den Treffern (Index bzw. Zeilennummern) - letzter Trenner wird entfernt.
	$aAllHits = StringSplit($sAllHits, "|") ; Das Treffer-Array wird gebildet.

	For $i = 0 To UBound($aData) - 1 ; Listview wird in der Schleife gefüllt.
		If _ArraySearch($aAllHits, $i, 1) <> -1 Then ; Wenn in der Zeile ein Suchtreffer ist, wird die Zeile farblich markiert.
			GUICtrlCreateListViewItem($aData[$i][0], $idLV_ListArrays)
			GUICtrlSetBkColor(-1, 0xFFDC00)
		Else
			GUICtrlCreateListViewItem($aData[$i][0], $idLV_ListArrays)
		EndIf
		For $ii = 0 To $iCols - 1
			_GUICtrlListView_AddSubItem($idLV_ListArrays, $i, $aData[$i][$ii], $ii)
		Next
	Next

	_GUICtrlListView_EnsureVisible($idLV_ListArrays, Int($aAllHits[1] + 1)) ; Es wird zum ersten Treffer gesprungen.
	_GUICtrlListView_EndUpdate($idLV_ListArrays)

	GUICtrlSetData($idL_ListHits, $aAllHits[0] & " Treffer") ; Das Treffer-Label wird gefüllt.

	If (IniRead($hIni, "Position", "ListMax", "") == "1") Then ; Falls die letzte Ansicht maximiert war, soll es nach Programmneustart wieder maximiert starten.
		GUISetState(@SW_SHOWMAXIMIZED, $hListGUI)
		GUICtrlSetState($idLV_ListArrays, $GUI_SHOW) ; Damit sicher sichtbar. Manchmal sind Probleme mit WM_Size und dem darin vorgenommenen verstecken der Listview aufgetreten.
	Else
		GUISetState(@SW_SHOW, $hListGUI)
	EndIf

EndFunc   ;==>_Show_ArrayInGUI

Func _Show_StringInGUI($sString)
	GUISetState(@SW_HIDE, $hListGUI)

	$sString = StringReplace($sString, @CR & @CR, "") ; Bei Grafiken bleibt nur eine Sammlung von Wagenrückläufen übrig. Die sollen hier aus dem Text entfernt werden.
	_GUICtrlRichEdit_SetText($id_DocTxtField, $sString) ; Textfeld wird gefüllt.
	$sString = _GUICtrlRichEdit_GetText($id_DocTxtField)

	Local $iMaxIndex = UBound($aSearchString)
	Local $iStringLen
	Local $sAllHits = ""
	For $i = 0 To $iMaxIndex - 1 ; Für jedem Suchbegriff in $aSearchString..
		For $ii = 1 To 10000 ; Die Suchtreffer werden markiert. Einfach mal blind 10000 mögliche Treffer gesetzt.
			$iPosition = StringInStr($sString, $aSearchString[$i], 0, $ii)
			$iStringLen = StringLen($aSearchString[$i])
			If $iPosition <> 0 Then ; Treffer werden im Textfeld markiert.
				$iPosition -= 1
				_GUICtrlRichEdit_SetSel($id_DocTxtField, $iPosition, $iPosition + $iStringLen)
				_GUICtrlRichEdit_SetCharBkColor($id_DocTxtField, 0xFFE78F)
				$sAllHits &= $iPosition & "|" & $aSearchString[$i] & @LF
			Else
				ExitLoop ; Wenn kein Treffer mehr erzielt wird, endet die Schleife.
			EndIf
		Next
	Next
	$sAllHits = StringTrimRight($sAllHits, 1) ; Der String mit den Treffern - letzter Trenner wird entfernt.
	$aAllHits = StringSplit($sAllHits, @LF) ; Das Treffer-Array wird gebildet (Enhält die Zeichenposition im String).
;~ _ArrayDisplay($aAllHits)
	GUICtrlSetData($idL_DocHits, $aAllHits[0] & " Treffer") ; Das Treffer-Label wird gefüllt.

	_GUICtrlRichEdit_SetSel($id_DocTxtField, 0, _GUICtrlRichEdit_GetTextLength($id_DocTxtField))
	_GUICtrlRichEdit_SetFont($id_DocTxtField, $iFontsize, "Segoe UI") ; Schriftgröße wird gesetzt.
	_GUICtrlRichEdit_GotoCharPos($id_DocTxtField, $aAllHits[0] + 1) ; Setze den Curosr auf die erste Trefferposition.
	ControlSend($hDocGUI, "", $id_DocTxtField, "{LEFT}") ; Sende einen Tastaturbefehl an das Textfeld, damit es auch wirklich sichtbar wird.
	$iListposition = 1 ; Für die Sprungtasten wird die Position wieder auf 1 gesetzt. Siehe dazu in der Funktion MainLoop die Buttons $idB_DocNext und $idB_DocPrev.

	If (IniRead($hIni, "Position", "DocMax", "") == "1") Then ; Falls die letzte Ansicht maximiert war, soll es nach Programmneustart wieder maximiert starten.
		GUISetState(@SW_SHOWMAXIMIZED, $hDocGUI)
	Else
		GUISetState(@SW_SHOW, $hDocGUI)
	EndIf
EndFunc   ;==>_Show_StringInGUI

; ### Ende Funktionen: Anzeige von Texten und Tabellen in GUIs ###




; ### Funktionen: GUIRegisterMsg-Funktionen ### Hier sind die Funktionen, die für die Mindestgröße, Resizing und Mausklicks verantwortlich sind.

Func _WM_NOTIFY($hwnd, $iMsg, $wParam, $lParam) ; Reaktionen auf Klicks inkl. Funktionsaufrufe.

	#forceref $hwnd, $iMsg, $wParam
	Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo

	$hMainGUI = WinGetHandle($hMainGUI)
	If $hwnd <> $hMainGUI Then
		$hWndListView = $idLV_ListArrays
		If Not IsHWnd($idLV_ListArrays) Then $hWndListView = GUICtrlGetHandle($idLV_ListArrays)
	Else
		$hWndListView = $hLV_MainGUI
		If Not IsHWnd($idLV_MainGUI) Then $hWndListView = GUICtrlGetHandle($idLV_MainGUI)
	EndIf
	$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
	$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
	$iCode = DllStructGetData($tNMHDR, "Code")

	Switch $hWndFrom
		Case $hWndListView

			Switch $iCode
				Case $NM_CLICK ; Sent by a list-view control when the user clicks an item with the left mouse button

					$tInfo = DllStructCreate($tagNMITEMACTIVATE, $lParam)

					If $hWndListView = $hLV_MainGUI Then
						$sFullPath = $sStartFolder & "\" & _GUICtrlListView_GetItemText($hLV_MainGUI, DllStructGetData($tInfo, "Index")) ; Die ausgewählte Datei wird ermittelt.
						If $sFullPath <> $sStartFolder & "\" Then
							_ShowLines($sFullPath)
						EndIf
					Else

					EndIf
					; Aus der Hilfe.
					; Weitere Auswertungsbeispiele in der Hilfe zu _GUICtrlListView_HitTest oder _GUICtrlListView_SubItemHitTest.

				Case $NM_DBLCLK ; Sent by a list-view control when the user double-clicks an item with the left mouse button
					$tInfo = DllStructCreate($tagNMITEMACTIVATE, $lParam)
					If $hWndListView = $hLV_MainGUI Then
						$sFullPath = $sStartFolder & "\" & _GUICtrlListView_GetItemText($hLV_MainGUI, DllStructGetData($tInfo, "Index")) ; Die ausgewählte Datei wird ermittelt.
						If Not FileExists($sFullPath) Then Return MsgBox(0, "", "Die Datei kann nicht geöffnet werden. Sie wurde gelöscht oder verschoben.", 5)
						Local $aPathSplit = StringSplit($sFullPath, ".")
						WinSetTitle($hListGUI, "", $sFullPath)
						WinSetTitle($hDocGUI, "", $sFullPath)

						Select ; Je nach Datei-Endung wird die entsprechende Funktion ausgewählt. Hier mit Parameter 1 zum Anzeigen.
							Case $aPathSplit[$aPathSplit[0]] = "docx" Or $aPathSplit[$aPathSplit[0]] = "doc"
								_GetContent_DOC_DOCX($sFullPath, 1)
							Case $aPathSplit[$aPathSplit[0]] = "xls" Or $aPathSplit[$aPathSplit[0]] = "xlsx"
								_GetContent_XLS_XLSX($sFullPath, 1)
							Case _ArraySearch($aFileTypes, $aPathSplit[$aPathSplit[0]]) <> -1
								_GetContent_TXT($sFullPath, 1)
							Case $aPathSplit[$aPathSplit[0]] = "csv"
								_GetContent_CSV($sFullPath, 1)
							Case $aPathSplit[$aPathSplit[0]] = "pdf"
								_GetContent_PDF($sFullPath, 1)
						EndSelect
					Else
						ClipPut(_GUICtrlListView_GetItemText($idLV_ListArrays, DllStructGetData($tInfo, "Index"), DllStructGetData($tInfo, "SubItem")))
					EndIf
					; No return value
				Case $NM_RCLICK ; Sent by a list-view control when the user clicks an item with the right mouse button
					$tInfo = DllStructCreate($tagNMITEMACTIVATE, $lParam)
					If $hWndListView = $hLV_MainGUI Then
						$sFullPath = $sStartFolder & "\" & _GUICtrlListView_GetItemText($hLV_MainGUI, DllStructGetData($tInfo, "Index"))
						If Not FileExists($sFullPath) Then Return MsgBox(0, "", "Die Datei kann nicht geöffnet werden. Sie wurde gelöscht oder verschoben.", 5)
						ShellExecute($sFullPath)
					EndIf
					Return 0 ; allow the default processing
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_NOTIFY

Func _WM_SIZE($hwnd, $iMsg, $wParam, $lParam) ; Notwendig zum Vergrößern/Verkleinern der RichEdit-Controls und der StatusBar in der $hMainGUI (Leiste unten).

	If $hwnd = $hDocGUI Then ; Die Dokumentanzeige
		$iDocWidth = _WinAPI_LoWord($lParam)
		$iDocHeight = _WinAPI_HiWord($lParam)

		_WinAPI_MoveWindow($id_DocTxtField, 10, 10, $iDocWidth - 20, $iDocHeight - 80)
		GUICtrlSetPos($idL_DocHits, 300, $iDocHeight - 40, 135, 40)
		GUICtrlSetPos($idB_DocNext, 155, $iDocHeight - 50, 135, 40)
		GUICtrlSetPos($idB_DocPrev, 10, $iDocHeight - 50, 135, 40)
		GUICtrlSetPos($idB_DocZoomUp, $iDocWidth - 150, $iDocHeight - 50, 135, 40)
		GUICtrlSetPos($idB_DocZoomDown, $iDocWidth - 300, $iDocHeight - 50, 135, 40)
		Return 0
	ElseIf $hwnd = $hMainGUI Then ; Das Hauptfenster
		$iMainWidth = _WinAPI_LoWord($lParam)
		$iMainHeight = _WinAPI_HiWord($lParam)

		$hTimer = TimerInit() ; Bei Größenänderungen wird die Listview ausgeblendet, ein Timer gestartet und die Funktion _EndSize registriert.
		GUICtrlSetState($idLV_MainGUI, $GUI_HIDE)
		GUICtrlSetState($idLE_LinesMainGUI, $GUI_HIDE)
		If $bEndSize Then
			AdlibRegister("_EndSize", 30) ; In dieser Funktion wird geprüft, ob die Aktion Größenänderung beendet ist (Timer-Zeit muss erreicht werden).
			$bEndSize = False
		EndIf

		If $iMainWidth >= 980 Then ; Je nachdem, wie groß das Hauptfenster ist, werden die Controls angeordnet.
			GUICtrlSetPos($idCombo_SearchString, 500, 20)
			GUICtrlSetPos($idB_Search, 825, 20)
			GUICtrlSetPos($idL_Clickhint, 10, 85)
			GUICtrlSetPos($idL_Preview, 10, 105 + $iMainHeight * 0.4 + 5)
			GUICtrlSetPos($idLV_MainGUI, 10, 105, $iMainWidth - 20, $iMainHeight * 0.4)
			_WinAPI_MoveWindow($idLE_LinesMainGUI, 10, 105 + $iMainHeight * 0.4 + 30, $iMainWidth - 20, $iMainHeight - (110 + $iMainHeight * 0.4 + 50))
		Else
			GUICtrlSetPos($idCombo_SearchString, 10, 96)
			GUICtrlSetPos($idB_Search, 345, 95)
			GUICtrlSetPos($idL_Clickhint, 10, 135)
			GUICtrlSetPos($idL_Preview, 10, 105 + $iMainHeight * 0.4 + 5)
			GUICtrlSetPos($idLV_MainGUI, 10, 155, $iMainWidth - 20, $iMainHeight * 0.4 - 55)
			_WinAPI_MoveWindow($idLE_LinesMainGUI, 10, 155 + $iMainHeight * 0.4 + 30 - 55, $iMainWidth - 20, $iMainHeight - (110 + $iMainHeight * 0.4 + 45))
		EndIf
		_GUICtrlListView_SetColumnWidth($idLV_MainGUI, 0, $iMainWidth - 70)
		_GUICtrlListView_SetColumnWidth($idLE_LinesMainGUI, 0, $iMainWidth - 70)
		_GUICtrlStatusBar_Resize($hStatus)

		Local $aWinPos = WinGetPos($hMainGUI)
		$iMainXPos = $aWinPos[0]
		$iMainYPos = $aWinPos[1]
		WinMove($hProgressGUI, '', $iMainXPos + $iMainWidth / 2 - 200, $iMainYPos + $iMainHeight / 2 - 34)
	ElseIf $hwnd = $hListGUI Then ; Die Tabellenanzeige
		GUICtrlSetState($idLV_ListArrays, $GUI_HIDE)
		$hTimer = TimerInit() ; Bei Größenänderungen wird die Listview ausgeblendet, ein Timer gestartet und die Funktion _EndSize registriert.
		If $bEndSize Then
			AdlibRegister("_EndSize", 30) ; In dieser Funktion wird geprüft, ob die Aktion Größenänderung beendet ist (Timer-Zeit muss erreicht werden).
			$bEndSize = False
		EndIf
	EndIf
EndFunc   ;==>_WM_SIZE

Func _EndSize() ; Diese Funktion wird in _WM_SIZE aufgerufen, um das Flackern der Listview in der $hListGUI zu vermeiden.
	Local $fDiff = TimerDiff($hTimer) ; solange die Größe sich geändert, wird $hTimer = TimerInit() aufgerufen und $fDiff erreicht nicht 50.
	If $fDiff > 50 Then
		Local $iWinState = WinGetState($hMainGUI)
		$bEndSize = True
		AdlibUnRegister("_EndSize")
		If $iWinState = 15 Or $iWinState = 47 Then
			GUICtrlSetState($idLV_MainGUI, $GUI_SHOW)
			GUICtrlSetState($idLE_LinesMainGUI, $GUI_SHOW)
		Else
			GUICtrlSetState($idLV_ListArrays, $GUI_SHOW)
		EndIf
	EndIf
EndFunc   ;==>_EndSize

Func _WM_GETMINMAXINFO($hwnd, $Msg, $wParam, $lParam) ; Mindestgrößen der GUIs
	If $hwnd = $hDocGUI Then ; Die Dokumentenanzeige
		$tagMaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam)
		DllStructSetData($tagMaxinfo, 7, $hDocGUIminWid) ; min X
		DllStructSetData($tagMaxinfo, 8, $hDocGUIminHt) ; min Y
		Return 0
	ElseIf $hwnd = $hListGUI Then ; Die Tabellenanzeige
		$tagMaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam)
		DllStructSetData($tagMaxinfo, 7, $ListGUIminWid) ; min X
		DllStructSetData($tagMaxinfo, 8, $ListGUIminHt) ; min Y
		Return 0
	ElseIf $hwnd = $hMainGUI Then ; Das Hauptfenster
		$tagMaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam)
		DllStructSetData($tagMaxinfo, 7, $MainGUIminWid) ; min X
		DllStructSetData($tagMaxinfo, 8, $MainGUIminHt) ; min Y
		Return 0
	EndIf
EndFunc   ;==>_WM_GETMINMAXINFO

Func _WM_MOVE($hwnd, $Msg, $wParam, $lParam)

	Local $aWinPos = WinGetPos($hMainGUI)
	$iMainXPos = $aWinPos[0]
	$iMainYPos = $aWinPos[1]

	Switch $hwnd
		Case $hMainGUI
			WinMove($hProgressGUI, '', $iMainXPos + $iMainWidth / 2 - 200, $iMainYPos + $iMainHeight / 2 - 34)
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_MOVE


; ### Ende Funktionen: GUIRegisterMsg-Funktionen ###



; ### Hilfsfunktionen ###

Func _ErrFunc($oError) ; Bei Objekt-Fehlern in _XLSReadToArray wird diese Funktion aufgerufen. (Aus der Hilfe zu ObjEvent)
	ConsoleWrite("Skriptzeile: " & @ScriptLineNumber & " " & @ScriptName & " (" & $oError.scriptline & ") : ==> COM Error intercepted !" & @CRLF & _
			@TAB & "err.number is: " & @TAB & @TAB & "0x" & Hex($oError.number) & @CRLF & _
			@TAB & "err.windescription:" & @TAB & $oError.windescription & @CRLF & _
			@TAB & "err.description is: " & @TAB & $oError.description & @CRLF & _
			@TAB & "err.source is: " & @TAB & @TAB & $oError.source & @CRLF & _
			@TAB & "err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _
			@TAB & "err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _
			@TAB & "err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _
			@TAB & "err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _
			@TAB & "err.retcode is: " & @TAB & "0x" & Hex($oError.retcode) & @CRLF & @CRLF)

	$bObjectError = True ; Das Flag damit _XLSReadToArray nun abgebrochen wird und mit Excel weitergemacht wird, wenn möglich.
EndFunc   ;==>_ErrFunc

Func _ExcelColumnsLetters() ; In dieser Funktion wird ein Array mit Buchstaben für die Excel-Spalten in der ListGUI gebildet.
	Local $aCols[702] = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", _
			"L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", _
			"X", "Y", "Z"]
	Local $iColNumber = 26

	For $i = 0 To 25
		For $ii = 0 To 25
			$aCols[$iColNumber] = $aCols[$i] & $aCols[$ii]
			$iColNumber += 1
		Next
	Next

	Return $aCols
EndFunc   ;==>_ExcelColumnsLetters

Func _Exit() ; Die Funktion wird erwartungsgemäß beim Verlassen aufgerufen.
	If Not BitAND(WinGetState($hMainGUI), 16) Then
		$aGuiPos = WinGetPos($hMainGUI)
		If $aGuiPos[0] >= 0 Then
			If $aGuiPos[2] > @DesktopWidth Then $aGuiPos[2] = @DesktopWidth
			If $aGuiPos[3] > @DesktopHeight Then $aGuiPos[3] = @DesktopHeight
			IniWrite($hIni, "Position", "Mainx", $aGuiPos[0])
			IniWrite($hIni, "Position", "Mainy", $aGuiPos[1])
			IniWrite($hIni, "Position", "Mainwidth", $aGuiPos[2])
			IniWrite($hIni, "Position", "Mainheight", $aGuiPos[3])
		EndIf
	EndIf
	GUIDelete($hDocGUI)
	GUIDelete($hListGUI)
	_SQLite_Close()
	_SQLite_Shutdown()
	_Word_Quit($oWord)
	_Excel_Close($oExcel)
	Exit
EndFunc   ;==>_Exit

; ### Ende Hilfsfunktionen ###


; ### HintBox Funktionen ###

; Die folgenden hundert Zeilen sind nur dafür da, ein rotes Kästchen um die Inputbox für den Suchbegriff anzuzeigen,
; falls kein Suchbegriff bei Klick auf den Suchbutton im Control zu finden ist. :D
; Völlig übertrieben. Ich hatte die Funktionen aber gerade für ein anderes Projekt gemacht und hab es dann hier hineinkopiert..

Func _HintBoxes_By_Handle($hwnd, $vControls = "", $iStrength = 5, $iDuration = 2000, $vColor = 0xB10000)

	Local $aPos = WinGetPos($hwnd)

	; get height of window title and width of window frame - may be different when XP theme is ON/OFF
	Local $g_iHtit = _WinAPI_GetSystemMetrics($SM_CYCAPTION)
	Local $g_iFrame = _WinAPI_GetSystemMetrics($SM_CXDLGFRAME)

	Local $hGui = GUICreate("", $aPos[2] + $iStrength * 4, $aPos[3] + $iStrength * 4, $aPos[0] - $iStrength * 2, $aPos[1] - $iStrength * 2, -1, $WS_EX_TOPMOST + $WS_EX_TOOLWINDOW)

	__HintBoxes_HandlesArray($hGui)

	If IsArray($vControls) Then
		If Not IsArray($vColor) Then Return 0
		If UBound($vControls) <> UBound($vColor) Then Return 0
		Local $aControls[UBound($vControls)], $aColor[UBound($vColor)]
		For $i = 0 To UBound($vControls) - 1
			$aControls[$i] = $vControls[$i]
			$aColor[$i] = $vColor[$i]
		Next
		Local $ah_LabelIDs[UBound($vControls) * 4]
	Else
		Local $ah_LabelIDs[4]
		Local $aControls[1], $aColor[1]
		$aControls[0] = $vControls
		$aColor[0] = $vColor
		If $vControls = "" Then
			WinMove($hGui, "", $aPos[0] - $iStrength * 2, $aPos[1] - $iStrength * 2 - $g_iHtit - $g_iFrame)
			$aPos[0] = 0
			$aPos[1] = 0
			$aPos[3] = $aPos[3]
		EndIf
	EndIf

	Local $bMenu = False
	Local $hMenu = _GUICtrlMenu_GetMenu($hwnd)
	Local $hSub = _GUICtrlMenu_GetItemSubMenu($hMenu, 0)
	If Not @error And $hSub <> 0x00000000 Then $bMenu = True

	For $i = 0 To UBound($aControls) - 1
		If $vControls <> "" Then
			$aPos = ControlGetPos($hwnd, "", $aControls[$i])
			If $bMenu Then
				$aPos[0] += $g_iFrame * 2
				$aPos[1] += $g_iHtit + $g_iFrame * 1.5
			Else
				$aPos[0] += $g_iFrame
				$aPos[1] += $g_iFrame
			EndIf
		EndIf
		$ah_LabelIDs[$i * 4] = GUICtrlCreateLabel("", $aPos[0] + $iStrength, $aPos[1] + $iStrength, $iStrength, $aPos[3] + $iStrength) ; Left
		GUICtrlSetBkColor(-1, $aColor[$i])
		$ah_LabelIDs[$i * 4 + 1] = GUICtrlCreateLabel("", $aPos[0] + $iStrength, $aPos[1] + $iStrength, $aPos[2] + $iStrength, $iStrength) ; Top
		GUICtrlSetBkColor(-1, $aColor[$i])
		$ah_LabelIDs[$i * 4 + 2] = GUICtrlCreateLabel("", $aPos[0] + $aPos[2] + $iStrength, $aPos[1] + $iStrength, $iStrength, $aPos[3] + $iStrength) ; Right
		GUICtrlSetBkColor(-1, $aColor[$i])
		$ah_LabelIDs[$i * 4 + 3] = GUICtrlCreateLabel("", $aPos[0] + $iStrength, $aPos[1] + $aPos[3] + $iStrength, $aPos[2] + $iStrength, $iStrength) ; Bottom
		GUICtrlSetBkColor(-1, $aColor[$i])
	Next
	__HintBoxes_GuiHole($hGui, 0, 0, $aPos[2], $aPos[3], $ah_LabelIDs, $g_iHtit, $g_iFrame)
	WinActivate($hwnd)
	GUISetState(@SW_SHOWNA)

	If $iDuration = 0 Then Return $hGui

	Sleep($iDuration)
	_HintBoxes_Delete($hGui)
EndFunc   ;==>_HintBoxes_By_Handle

Func _HintBoxes_Delete($hGui = "")
	If $hGui = "" Then
		Local $aDeleteHandles = __HintBoxes_HandlesArray("", False)
	Else
		Local $aDeleteHandles = __HintBoxes_HandlesArray($hGui, False)
	EndIf
	If Not @error Then
		For $i = 0 To UBound($aDeleteHandles) - 1
			_WinAPI_AnimateWindow($aDeleteHandles[$i], BitOR($AW_BLEND, $AW_HIDE), 500)
		Next
	EndIf
EndFunc   ;==>_HintBoxes_Delete

Func __HintBoxes_GuiHole($hWin, $iX, $iY, $iSizeW, $iSizeH, $ah_LabelIDs, $g_iHtit = 0, $g_iFrame = 0)
	Local $hOuter_rgn, $hInner_rgn, $hCombined_rgn

	$hOuter_rgn = _WinAPI_CreateRectRgn(0, 0, $iSizeW, $iSizeH)
	$hInner_rgn = _WinAPI_CreateRectRgn($iX, $iY, $iX + $iSizeW, $iY + $iSizeH)
	$hCombined_rgn = _WinAPI_CreateRectRgn(0, 0, 0, 0)
	_WinAPI_CombineRgn($hCombined_rgn, $hOuter_rgn, $hInner_rgn, $RGN_DIFF)
	_WinAPI_DeleteObject($hOuter_rgn)
	_WinAPI_DeleteObject($hInner_rgn)
	For $i = 0 To UBound($ah_LabelIDs) - 1
		__HintBoxes_AddCtrlRegion($hCombined_rgn, $ah_LabelIDs[$i], $hWin, $g_iHtit, $g_iFrame)
	Next
	_WinAPI_SetWindowRgn($hWin, $hCombined_rgn)
EndFunc   ;==>__HintBoxes_GuiHole

Func __HintBoxes_AddCtrlRegion($hFull_rgn, $idCtrl, $hWin, $g_iHtit, $g_iFrame)
	Local $aCtrl_pos, $hCtrl_rgn

	$aCtrl_pos = ControlGetPos($hWin, "", $idCtrl)
	$hCtrl_rgn = _WinAPI_CreateRectRgn($aCtrl_pos[0] + $g_iFrame, $aCtrl_pos[1] + $g_iHtit + $g_iFrame, _
			$aCtrl_pos[0] + $aCtrl_pos[2] + $g_iFrame, $aCtrl_pos[1] + $aCtrl_pos[3] + $g_iHtit + $g_iFrame)
	_WinAPI_CombineRgn($hFull_rgn, $hFull_rgn, $hCtrl_rgn, $RGN_OR)
	_WinAPI_DeleteObject($hCtrl_rgn)
EndFunc   ;==>__HintBoxes_AddCtrlRegion

Func __HintBoxes_HandlesArray($hGui = "", $bAdd = True)
	Local Static $aHandles[0]
	If $bAdd Then
		_ArrayAdd($aHandles, $hGui)
	Else
		If $hGui = "" Then
			Local $aDeleteHandles = $aHandles
			ReDim $aHandles[0]
			Return $aDeleteHandles
		Else
			$iIndex = _ArraySearch($aHandles, $hGui)
			If Not @error Then
				Local $aDeleteHandles[1] = [$aHandles[$iIndex]]
				_ArrayDelete($aHandles, $iIndex)
				Return $aDeleteHandles
			Else
				Return SetError(1)
			EndIf
		EndIf
	EndIf
EndFunc   ;==>__HintBoxes_HandlesArray


; ### Ende HintBox Funktionen ###
