#include-once
#include <_EigeneFunktionen.au3>
#include <String.au3>
Opt("MustDeclareVars", 1)


; Funktionsaufruf im Script:
_DateitypZuordnen("Dateityp", "Programmnamen"[, "Registry-Einterag"[, "Erneut zuordnen"[, "Fehlermeldung"]]]
;DateitypZuordnen(".3g2", "MPC-HC", "mplayerc", True, True) ; Nur zum Testen.

; Fehlerauswertung über @error im Script!


#Region Anfang der _DateitypZuordnen() Funktion.
	; #FUNKTION# ==========================================================================================================================================
	; 	Funktions-Name	:	_DateitypZuordnen()
	; 	Beschreibung	:	Funktion zum Aufrufen des "Dateizuordnungen festlegen"-Dialogs (Standard-Apps nach Dateityp auswählen), damit man
	;							geschützte Dateizuordnungen einfacher ändern kann (bei Windows 10 sind die Dateizuordnungen geschützt
	;							und können nur "manuell" geändert werden).
	;
	; 	Syntax			:	_DateitypZuordnen($_sDateityp, $_sProgrammNamen[, $_sSuchString = $_sProgrammNamen[, $_bErneut = False[, $_bFehlermeldung = True]]])
	;
	;	Parameter		:	$_sDateityp: String = Der Dateityp, der gesucht und geändert werden soll
	;							(immer mit Punkt und als String, z.B. ".exe"), ($_sFileExtension).
	;						$_sProgrammName: String = Der Name des Standardprogramms, welches in Zukunft verwendet werden soll ($_sProgrammName).
	;						$_sSuchString [Optional]: $_sProgrammNamen (Standard): = Der Eintrag in der Registry der gesucht werden soll,
	;							wird dieser Parameter nicht angegeben, so wird der Programmnamen als Suchstring verwendet,
	;							Der Programmname wir nach den Regeln für reguläre Ausdrücke, nicht casesensitiv, erkannt, ($_sSearchString).
	;						$_bErneut [Optional]: False (Standard) = Der Dateityp soll zum ersten mal dem angegebenen Programm zugeordnet werden,
	;							True = der Dateityp muss dem Programm nochmals zugeordnet werden, obwohl er schon als diesem Programm
	;							zugeordnet in dem Dialog angezeigt wird, ($_bRenewed).
	;						$_bFehlermeldung [Optional]: True (Standard) = Fehlermeldung ausgeben, False = keine Fehlermeldung ausgeben, ($_bMessage).
	;
	;	Rückgabewerte	:	Erfolg: Der Dialog zum Ändern des Dateityp und danach Return-Code 1.
	;						Fehler: Fehlermeldung und/oder Return mit dem Return-Code 0 und setzt @error auf:
	;									1 = Falsches Betriebssystem, nur Windows 10 ab 1803 (Build: 1733) wird unterstützt
	;									2 = Der übergebene Dateityp beginnt nicht mit einem Punkt
	;									3 = Der Dateityp existiert nicht
	;									4 = Der Dateityp ist schon dem gewünschten Programm zugeordnet
	;									5 = Das Fenster "Standard-Apps/Standard-Apps nach Dateityp auswählen" existiert nicht
	;									6 = Das Auswählen des Standardprogramms wurde abgebrochen (es wurde nicht ausgewählt)
	;
	;	Includes		:	<String.au3> (wird für die Funktion _StringRepeat() gebraucht), die Funktion _GUI_Meldungen() wird von
	;							dieser Funktion zur Ausgabe der Meldungen benötigt.
	;	AutoIt Version	:	3.3.14.5
	;	Funktions-Autor	:	BigRox
	;	Anmerkung(en)	:	Der Dateityp muss immer MIT dem Trennzeichen - dem Punkt - angegeben werden (Beispiel: ".bmp")!
	;							Wird als Variable für den Dateityp kein String übergeben, so wird die Funktion immer abgebrochen!
	;							Der angegebene Programmnamen stimmt meistens nicht mit dem in Registry eingetragenen Programmnamen
	;							(SuchString) überein! Z.B. Word (Desktop) = Applications\winword.exe, Editor = Applications\Notepad.exe,
	;							WordPad = Applications\WordPad.exe, Text editor (PSPad) = xmlfile.
	;							Die GUI mit dem Hinweis auf das Ändern des Standardprogramms, kann mit der Maus verschoben werden,
	;							falls die GUI etwas verdecken sollte.
	;							Die Funktion funktioniert auch in der Windows-Sandbox (der Fenstertext wird in der Sandbox angepasst!)
	;
	;						! ! ! Die Funktion funktioniert nur bei Windows 10 1803+ (ab Build 17133)-Versionen ! ! !
	; =====================================================================================================================================================
	Func _DateitypZuordnen($_sFileExtension, $_sProgramName, $_sSearchString = $_sProgramName, $_bRenewed = False, $_bMessage = True)
		Local $_sActualKey, $_hGUI_Handle, $_iLV, $_iMemoryCursor, $_iMemoryInput, $_sMessageText, $_sWindowTitle

		; Testen, ob ein erforderliches Betriebssystem installiert ist (sonst stimmen die Fensteraufrufe nicht).
		If @OSVersion <> "WIN_10" Or @OSBuild < 17133 Then
			$_sMessageText = @CRLF & "Es ist kein erforderliches Betriebssystem installiert!" & @CRLF & @CRLF & _
					"Diese Funktion unterstützt nur die Versionen von Windows 10 ab 1803 (Build: 17133)!" & @CRLF & @CRLF & _
					"Die Funktion wird daher abgebrochen!"
			; GUI-Titel, GUI-Farbe:Gelb, Label-Text, Label-Farbe:Rot, Icon:Fehler, Button:"OK", kein Autoclose, Schrift:16, 500, Tahoma, Weiß, X-Zentriert, Y-Zentriert, Vordergrund.
			_GUI_Meldungen("! ! !  F E H L E R  (<_DateitypZuordnen()>)  ! ! !", 0xD9DE10, $_sMessageText, 0xFF0000, _
					@SystemDir & "\comres.dll, 10", 1)
			Return SetError(1, 0, 0)
		EndIf

		; Testen, ob die übergebene Variable mit einem Punkt beginnt (oder kein String ist), wenn "Ja", die Funktion abbrechen.
		If Not StringRegExp($_sFileExtension, "^\.") Then
			$_sMessageText = @CRLF & "Die übergebene Variable:" & @CRLF & _StringRepeat(" ", 6) & '"' & $_sFileExtension & '"' & @CRLF & _
					@CRLF & "beginnt nicht mit einem Punkt oder sie ist kein String!" & @CRLF & @CRLF & _
					"Die Funktion wird daher abgebrochen!"
			; GUI-Titel, GUI-Farbe:Gelb, Label-Text, Label-Farbe:Rot, Icon:Fehler, Button:"OK", kein Autoclose, Schrift:16, 500, Tahoma, Weiß, X-Zentriert, Y-Zentriert, Vordergrund.
			_GUI_Meldungen("! ! !  F E H L E R  (<_DateitypZuordnen()>)  ! ! !", 0xD9DE10, $_sMessageText, 0xFF0000, _
					@SystemDir & "\comres.dll, 10", 1)
			Return SetError(2, 0, 0)
		EndIf

		; Eine Schleife zum Auswerten des Registry-Schlüssels (enthält alle im System registrierten Dateitypen) starten.
		For $_iLV = 1 To 500
			$_sActualKey = RegEnumKey("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts", $_iLV)
			If @error = 0 Then ; @error wird <> 0, wenn alle Schlüssel eingelesen wurden, dann wird die Schleife abgebrochen.
				If StringRegExp($_sActualKey, "(?i)(" & $_sFileExtension & ")") Then
					ExitLoop
				EndIf
			Else
				If $_bMessage Then
					$_sMessageText = @CRLF & "Der Dateityp:" & @CRLF & _StringRepeat(" ", 6) & '"' & $_sFileExtension & '"' & @CRLF & _
							@CRLF & "existiert nicht!" & @CRLF & @CRLF & "Die Funktion wird daher abgebrochen!"
					; GUI-Titel, GUI-Farbe:Gelb, Label-Text, Label-Farbe:Rot, Icon:Fehler, Button:"OK", kein Autoclose, Schrift:16, 500, Tahoma, Weiß, X-Zentriert, Y-Zentriert, Vordergrund.
					_GUI_Meldungen("! ! !  F E H L E R  (<_DateitypZuordnen()>)  ! ! !", 0xD9DE10, $_sMessageText, 0xFF0000, _
							@SystemDir & "\comres.dll, 10", 1)
				EndIf
				Return SetError(3, 0, 0)
			EndIf
		Next

		If Not $_bRenewed Then
			If StringRegExp(RegRead("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" & $_sFileExtension & "\UserChoice", _
					"ProgId"), "(?i)\Q" & $_sSearchString & "\E") Then
				If $_bMessage Then
					$_sMessageText = @CRLF & "Der Dateityp:" & @CRLF & _StringRepeat(" ", 6) & '"' & $_sFileExtension & '"' & @CRLF & @CRLF & _
							"ist schon dem Programm:" & @CRLF & _StringRepeat(" ", 6) & '"' & $_sProgramName & '"' & @CRLF & @CRLF & _
							"zugeordnet!" & @CRLF & @CRLF & "Die Funktion wird daher abgebrochen!"
					; GUI-Titel, GUI-Farbe:Gelb, Label-Text, Label-Farbe:Rot, Icon:Fehler, Button:"OK", kein Autoclose, Schrift:16, 500, Tahoma, Weiß, X-Zentriert, Y-Zentriert, Vordergrund.
					_GUI_Meldungen("! ! !  F E H L E R  (<_DateitypZuordnen()>)  ! ! !", 0xD9DE10, $_sMessageText, 0xFF0000, _
							@SystemDir & "\comres.dll, 10", 1)
				EndIf
				Return SetError(4, 0, 0)
			EndIf
		EndIf

		; Schleife bis der Dateityp dem richtigen Programm zugeordnet wurde ausführen.
		While - 1
			; Die Einstellungsseite zur Auswahl des Standardprogramms aufrufen.
			Run(@ComSpec & " /c " & "control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram", "", @SW_MAXIMIZE)

			; Sleep(), zur Sicherheit
			Sleep(1000)

			; Das Fenster zum Einstellen des Standardprograms aktivieren und warten bis es aktiviert ist.
			WinActivate("[CLASS:ApplicationFrameWindow; TITLE:Einstellungen]", "Einstellungen")
			WinWaitActive("[CLASS:ApplicationFrameWindow; TITLE:Einstellungen]", "Einstellungen")

			If $_bRenewed Then
				; Die GUI mit dem Hinweis zum Zuordnen des Dateityps anzeigen.
				$_sMessageText = "(Dieses Hinweisfenster kann mit der Maus verschoben werden.)" & @CRLF & @CRLF & "Der Dateityp:" & @CRLF & _
						_StringRepeat(" ", 6) & '"' & $_sFileExtension & '"' & @CRLF & @CRLF & _
						"wird eventuell schon als dem Programm:" & @CRLF & _StringRepeat(" ", 6) & '"' & $_sProgramName & '"' & @CRLF & @CRLF & _
						"zugeordnet angezeigt, aber er muss unter:" & @CRLF & _StringRepeat(" ", 6) & _
						'"Standard-Apps nach Dateityp auswählen"' & @CRLF & @CRLF & "nochmals manuell diesem Programm zugeordnet werden!"
			Else
				; Die GUI mit dem Hinweis zum Zuordnen des Dateityps anzeigen.
				$_sMessageText = "(Dieses Hinweisfenster kann mit der Maus verschoben werden.)" & @CRLF & @CRLF & "Der Dateityp:" & @CRLF & _
						_StringRepeat(" ", 6) & '"' & $_sFileExtension & '"' & @CRLF & @CRLF & _
						"kann  - aus Sicherheitsgründen - nicht automatisch einem anderen" & @CRLF & "Programm zugeordnet werden!" & @CRLF & _
						@CRLF & "Er muss daher unter:" & @CRLF & _StringRepeat(" ", 6) & '"Standard-Apps nach Dateityp auswählen"' & @CRLF & _
						@CRLF & "Dem Programm:" & @CRLF & _StringRepeat(" ", 6) & '"' & $_sProgramName & '"' & @CRLF & @CRLF & _
						"manuell zugeordnet werden!"
			EndIf
			;	GUI-Titel, GUI-Farbe:Blau, Label-Text, Label-Farbe:HellGrün, Icon:Information, Button: Keine, kein Autoclose, Schrift:12, 500, Tahoma, Schwarz, X-Pos, Y-Pos, Vordergrund.
			$_hGUI_Handle = _GUI_Meldungen("! ! !  H I N W E I S  (<_DateitypZuordnen()>)  ! ! !", 0x3F4DFC, $_sMessageText, _
					0x68E84D, @SystemDir & "\audiodev.dll, 2", 0, 0, "12, 500, Tahoma, 0x000000", Int(@DesktopWidth * 0.45), _
					Int(@DesktopHeight * 0.2))

			; Testen, ob die Funktion in der Windows-Sandbox ausgeführt wird.
			If WinExists("Program Manager") And FileExists(@HomeDrive & "\Users\ContainerUser") Then
				$_sWindowTitle = "windows.immersivecontrolpanel" ; Der Titel gilt für die folgenden Befehle innerhalb der Windows-Sandbox.
			Else
				$_sWindowTitle = "[CLASS:ApplicationFrameWindow; TITLE:Einstellungen]" ; Der Titel gilt für die folgenden Befehle außerhalb der Windows-Sandbox.
			EndIf

			; Die Funktion zum Warten auf das erste Fenster aufrufen.
			_StartVerzoegerung($_sWindowTitle, "", "(<_DateitypZuordnen()>)", 10, False, "", "", False)
			If @error Then
				If $_bMessage Then
					GUIDelete($_hGUI_Handle)
					$_sMessageText = @CRLF & "Das Fenster:" & @CRLF & _StringRepeat(" ", 6) & '"' & $_sWindowTitle & '"' & @CRLF & @CRLF & _
							"existiert nicht!"
					; GUI-Titel, GUI-Farbe:Gelb, Label-Text, Label-Farbe:Rot, Icon:Fehler, Button:"OK", kein Autoclose, Schrift:16, 500, Tahoma, Weiß, X-Zentriert, Y-Zentriert, Vordergrund.
					_GUI_Meldungen("! ! !  F E H L E R  (<_DateitypZuordnen()>)  ! ! !", 0xD9DE10, $_sMessageText, 0xFF0000, _
							@SystemDir & "\comres.dll, 10", 1)
				EndIf
				Return SetError(5, 0, 0)
			EndIf

			; Die Bedienung freigeben, damit der Dateityp ausgewählt werden kann.
			$_iMemoryInput = BlockInput(0)
			$_iMemoryCursor = _CursorAnzeigen(True)

			; Eine Warteschleife bis der Dateityp zugeordnet ist, ausführen die GUI löschen und die Bedienung wieder sperren.
			Do
				; Sleep, um das System nicht voll auszulasten.
				Sleep(1000)
			Until Not WinExists($_sWindowTitle)
			GUIDelete($_hGUI_Handle)
			_Bedienung(False, $_iMemoryInput, $_iMemoryCursor)

			; Testen, ob der Dateityp auch wirklich dem richtigen Programm zugeordnet ist, ansonsten die Schleife fortsetzen oder das Auswählen abbrechen.
			If StringRegExp(RegRead("HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\" & $_sFileExtension & "\UserChoice", _
					"ProgId"), "(?i)\Q" & $_sSearchString & "\E") Then

				ExitLoop
			Else
				; Fehlermeldung, falls der Dateityp nicht dem richtigen Programm zugeordnet wurde.
				$_sMessageText = @CRLF & "Der Dateityp" & @CRLF & _StringRepeat(" ", 6) & '"' & $_sFileExtension & '"' & @CRLF & @CRLF & _
						"konnte dem gewünschten Programm" & @CRLF & "nicht zugeordnet werden." & @CRLF & _
						@CRLF & "(OK = Auswahl wiederholen, Abbrechen = Auswahl abbrechen)."
				; GUI-Titel, GUI-Farbe:Gelb, Label-Text, Label-Farbe:Rot, Icon:Fehler, Button:"OK", kein Autoclose, Schrift:16, 500, Tahoma, Weiß, X-Zentriert, Y-Zentriert, Vordergrund.
				If _GUI_Meldungen("! ! !  F E H L E R  (<_DateitypZuordnen()>)  ! ! !", 0xD9DE10, $_sMessageText, 0xFF0000, _
						@SystemDir & "\comres.dll, 10", 2) = 2 Then ; 2 = Abbrechen
					Return SetError(6, 0, 0)
				EndIf
			EndIf
		WEnd

		Return (1)
	EndFunc ; _DateitypZuordnen()
#EndRegion Ende der _DateitypZuordnen() Funktion.
