SMTP Zugangsdaten im Programm speichern

  • VB.NET

Es gibt 76 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    Jup, so (ähnlich) würde ich es auch machen. Das Gleiche kannst Du auch mit dem Salt machen, allerdings musst Du dafür natürlich dessen Bytes bekommen.

    Ich hab mal irgendwo was für AES gefunden (leider keine Quelle mehr, aber der Code ist nicht auf meinem Mist gewachsen halt, hab's aus'm vb@rchiv) und ein wenig modifiziert. Das nutze ich bei mir:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Security.Cryptography
    2. Public Module TextCrypting
    3. Public Function CryptText(TextToCrypt As String, Password As String, Salt As String) As String
    4. If Not PrimaryCriteriasAreFulfilled(TextToCrypt, Password, Salt) Then Return Nothing
    5. Dim Aes = GetAesFrom(Password, Salt)
    6. Dim MemoryStream As New IO.MemoryStream
    7. Dim CryptoStream As New CryptoStream(MemoryStream, Aes.CreateEncryptor(), CryptoStreamMode.Write)
    8. Dim Data = Text.Encoding.UTF8.GetBytes(TextToCrypt)
    9. CryptoStream.Write(Data, 0, Data.Length)
    10. CryptoStream.FlushFinalBlock()
    11. Dim CryptedText = Convert.ToBase64String(MemoryStream.ToArray)
    12. CryptoStream.Dispose()
    13. MemoryStream.Dispose()
    14. Aes.Clear()
    15. Aes.Dispose()
    16. Return CryptedText
    17. End Function
    18. Private Function PrimaryCriteriasAreFulfilled(TargetText As String, Password As String, Salt As String) As Boolean
    19. Return Not String.IsNullOrEmpty(TargetText) AndAlso Not String.IsNullOrEmpty(Password) AndAlso Password.Length >= 8 AndAlso Not String.IsNullOrEmpty(Salt) AndAlso Salt.Length >= 8
    20. End Function
    21. Private Function GetAesFrom(Password As String, Salt As String) As AesManaged
    22. Dim GeneratedKey As New Rfc2898DeriveBytes(Password, Text.Encoding.UTF8.GetBytes(Salt))
    23. Dim Aes As New AesManaged With {.KeySize = 256, .BlockSize = 128, .Key = GeneratedKey.GetBytes(.KeySize \ 8), .IV = GeneratedKey.GetBytes(.BlockSize \ 8)}
    24. GeneratedKey.Dispose()
    25. Return Aes
    26. End Function
    27. Public Function DecryptText(CryptedText As String, Password As String, Salt As String) As String
    28. If Not PrimaryCriteriasAreFulfilled(CryptedText, Password, Salt) Then Return Nothing
    29. Dim Aes = GetAesFrom(Password, Salt)
    30. Using MemoryStream As New IO.MemoryStream
    31. Try
    32. Using CryptoStream As New CryptoStream(MemoryStream, Aes.CreateDecryptor(), CryptoStreamMode.Write)
    33. Dim Data = Convert.FromBase64String(CryptedText)
    34. CryptoStream.Write(Data, 0, Data.Length)
    35. CryptoStream.FlushFinalBlock()
    36. End Using
    37. Dim DecryptedText = Text.Encoding.UTF8.GetString(MemoryStream.ToArray)
    38. Aes.Clear()
    39. Return DecryptedText
    40. Catch CE As CryptographicException
    41. Return Nothing
    42. Catch FE As FormatException
    43. Return Nothing
    44. Finally
    45. Aes.Dispose()
    46. End Try
    47. End Using
    48. End Function
    49. End Module

    Ich sehe gerade: inkosequent, weil oben ohne doppeltes Using, unten mit. Der Codeanalyse meckert bei verschachteltem Using, weil der äußere Stream doppelt disposed werden kann. Naja, aber vom Prinzip zumindest ...

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    @DerShorty
    3-dimensionales String-Array umwandeln in "hier könnte Ihre Lösung stehen"?

    Sofern du dich ein bisschen mit AES, Salt und dergleichen beschäftigen willst, hier habe ich ein Beispiel gemacht für das Verkrypten einer Array. Es zeigt die Vorgehensweise und auf was man achten sollte. Natürlich kann man das auch problemlos mit einem Passwort machen.

    Für dein Vorhaben kann ich nur empfehlen (wie schon hier im Thread erwähnt wurde), eine Passworteingabe ganz am Anfang, das ruhig noch mit einem Salt oder weiteren Angaben, wie Username, HD-Nummer etc. in Kombination schlussendlich zusammengecryptet wird.

    Z.B. wenn man die HD-Nummer nimmt, ist die erstellte Datei nur noch für das entsprechende System verwendbar, das gleiche auch beim verwenden des Usernamen.

    Möchtest du ohne Passwortangabe am Anfang, empfiehlt es sich zuerst tiefgründig sich mit dieser Materie zu beschäftigen. Nicht das es am Schluss unerwartete Sachen gibt.

    Ein weiterer Tip, den ich empfehlen kann ist, Passwörter oder sensible Texte generell als byte() zu führen, oder in einer Securestring festzuhalten. Zweiteres bedeutet das es bevor es vercryptet wird noch aus dem SecureString extrahiert werden muss.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    So ihr lieben.
    Zu Beginn dieses Threads wurde mir geraten für mein Projekt keinen MDI Container zu verwenden, sondern meine Programmfunktionen in einem TabControl zu organisieren.
    Hier war ich sehr skeptisch und habe diesen Rat anfangs nur sehr, sehr, sehr, ... widerwillig befolgt.
    Nach nicht mal 4 Tagen an diesem Projekt bin ich absolut froh, dass ich "auf euch gehört habe".

    Also mach ichs jetzt genauso und befolge einfach euren Rat. Ich hau mir also eine PW Abfrage zum Programmstart rein.

    Um den (für das jetzige Problem unnötige) Code aus meinem Projekt hier rauszulassen, habe ich das Demoprojekt von @SpaceyX erweitert. Und zwar so, wie ich es dann in meinem Programm realisieren würde.

    Hierbei gehe ich davon aus, dass das Programm zum ersten mal gestartet wird, wenn die verschlüsselte xml Datei nicht gefunden wurde.
    Es folgt eine Eingabeaufforderung wo der User sein PW eingeben soll.
    Außerdem habe ich eine PW ändern Funktion eingebaut.
    Das ganze lade ich einfach mal hoch. Bitte sagt mir, ob das alles so ok ist. Bitte ignoriert Optik und Controlbenennung. Hier habe ich nur das allernötiste gemacht.
    Im Progamm würde ich natürlich später die Passwortchar Eigenschaft für Textboxen verwenden. Außerdem würde ich die Form MasterPasswort um eine Art Bildschirmtastatur erweitern, um die Bedienung auf Touch Geräten angenehmer zu machen. Aber wie ich das PW in TB bekomme, ist ja dem Code hier wurscht.
    Und ich denke ich werde das Passwort ändern Gedöns in eine eigene Form packen. Hier auch mit DialogResult.OK Button und Aufruf mittels Using.
    Dann hohle ich mir den Inhalt der drei Textboxen und mache mit dem gleichen Code wie gepostet weiter.

    An meinem Code stört mich ein wenig, dass ich im FormLoad Event nun Code enthalten habe, der in aller Regel, nur ein einziges mal im Leben des Programmes ausgeführt wird.
    Aber das geht ja denke ich nicht anders. und letzlich ist es bei der Ausführung des Programmes ja auch nur eine einzelne Zeile die ausgeführt wird (die If Abfrage, die prüft ob die xml Datei existiert). Daher denke ich, ist das vollkommen ok.

    Im Upload habe ich die Original xml von Spacey drin gelassen und von accounts.xm in accounts1.xml umbenannt. Das pw hierzu ist password123.
    Vielleicht braucht die ja noch jemand.

    Für diejenigen, die nicht runterladen möchten / oder müssen, kommt im Spoiler der Code und die notwendigen Erklärungen.
    Spoiler anzeigen
    Die Form MasterPasswort besteht aus einer TB und zwei Buttons. Die Buttons haben den DialogResult.OK und DialogResult.Cancel
    Die Form frmfirststart enthält 2 Textboxen (neues PW und neues PW erneut eingeben und einen OK Button (DialogResult.OK), sowie eine handvoll, für das Programm unwichtige Labels, mit Infos für den User.
    In der Form des Programms gibt es ein DaaGridView zum anzeigen der Daten aus dem DataSet, Button Save und Delete. Außerdem drei Textboxen zum ändern des Passworts.
    Und einen entsprechenden Button zum ändern des PW

    VB.NET-Quellcode

    1. Imports System.Security.Cryptography
    2. Imports System.IO
    3. Public Class Form1
    4. Private _masterPassword As String = String.Empty
    5. Private _dataPath As String = "accounts.xml"
    6. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    7. 'Ich gehe davon aus, dass das Programm zum ersten mal gestartet wird, wenn die xml Datei nicht existiert.
    8. 'solle die Datei aus einem anderen Grund fehlen, muss halt ein neues Pw vergeben werden
    9. If Not File.Exists(_dataPath) Then
    10. Using firststart As New frmfirststart()
    11. If firststart.ShowDialog() = DialogResult.OK Then
    12. If Not pwcheck(firststart.TBpw1.Text, firststart.TBpw2.Text) Then Close()
    13. 'hier wäre ein erneutes anzeigen der frmfirststart schöner als close()
    14. 'aber ich weiß nicht, wie ich das realisieren soll
    15. End If
    16. End Using
    17. 'wenn die Datei gefunden wurde, kommt die passwortabfrage
    18. Else
    19. Using mP As New MasterPassword()
    20. If mP.ShowDialog() = DialogResult.OK Then
    21. _masterPassword = mP.txtPassword.Text
    22. Else
    23. Close()
    24. End If
    25. End Using
    26. Try
    27. LoadData()
    28. Catch ex As Exception
    29. MessageBox.Show("Incorrect password")
    30. Close()
    31. End Try
    32. End If
    33. End Sub
    34. Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
    35. SaveData()
    36. End Sub
    37. Private Sub SaveData()
    38. If File.Exists(_dataPath) Then File.Delete(_dataPath)
    39. Using cS As CryptoStream = GetEncryptionStream()
    40. Me.AccountDetailsDataSet1.WriteXml(cS)
    41. End Using
    42. End Sub
    43. Private Sub LoadData()
    44. If File.Exists(_dataPath) Then
    45. Using cS As CryptoStream = GetDecryptionStream()
    46. Me.AccountDetailsDataSet1.ReadXml(cS)
    47. End Using
    48. End If
    49. End Sub
    50. Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
    51. If Not Me.AccountsBindingSource.Current Is Nothing Then
    52. Me.AccountsBindingSource.RemoveCurrent()
    53. End If
    54. SaveData()
    55. End Sub
    56. Private Sub BTNpwaendern_Click(sender As Object, e As EventArgs) Handles BTNpwaendern.Click
    57. 'erstmal prüfen ob altes pw korrekt.
    58. Dim pwalt As String = TBpwalt.Text
    59. If pwalt <> _masterPassword Then
    60. tbPWleeren()
    61. MessageBox.Show("falsches pw. nix geändert")
    62. Exit Sub
    63. End If
    64. If pwcheck(TBpw1.Text, TBpw2.Text) Then
    65. MessageBox.Show("pw erfolgreich geändert")
    66. Else
    67. tbPWleeren()
    68. End If
    69. End Sub
    70. Private Function pwcheck(pw1 As String, pw2 As String) As Boolean
    71. If pw1 <> "" AndAlso pw1 = pw2 Then
    72. _masterPassword = pw1
    73. 'Save Data ist wahrscheinlich beim aufruf über die Form Load unnötig.
    74. 'Aber erscheint mir sicherer
    75. SaveData()
    76. Return True
    77. Else
    78. MessageBox.Show("pw stimmen nicht überein")
    79. Return False
    80. End If
    81. End Function
    82. Private Sub tbPWleeren()
    83. TBpw1.Text = ""
    84. TBpw2.Text = ""
    85. TBpwalt.Text = ""
    86. End Sub
    87. Private Function GetEncryptionStream() As CryptoStream
    88. Dim key As New Rfc2898DeriveBytes(_masterPassword, New Byte() {10, 255, 255, 7, 14, 16, 23, 155})
    89. Dim x As New TripleDESCryptoServiceProvider()
    90. x.Key = key.GetBytes(x.KeySize \ 8)
    91. x.IV = key.GetBytes(x.BlockSize \ 8)
    92. Dim fS As FileStream = New FileStream(_dataPath, FileMode.Create, FileAccess.ReadWrite, FileShare.None)
    93. Return New CryptoStream(fS, x.CreateEncryptor(), CryptoStreamMode.Write)
    94. End Function
    95. Private Function GetDecryptionStream() As CryptoStream
    96. Dim key As New Rfc2898DeriveBytes(_masterPassword, New Byte() {10, 255, 255, 7, 14, 16, 23, 155})
    97. Dim x As New TripleDESCryptoServiceProvider()
    98. x.Key = key.GetBytes(x.KeySize \ 8)
    99. x.IV = key.GetBytes(x.BlockSize \ 8)
    100. Dim fS As FileStream = New FileStream(_dataPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
    101. Return New CryptoStream(fS, x.CreateDecryptor(), CryptoStreamMode.Read)
    102. End Function
    103. End Class

    Dateien
    • WindowsApp51.zip

      (952,43 kB, 44 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DerSmurf“ ()

    Joa, wenn's passt. Sieht auf den 1. Blick ganz passabel aus.
    Zwei Kleinigkeiten, die aber an sich problemirrelevant sind: Die Functions GetEncryptionStream() und GetDecryptionStream() sind bis auf ein Detail in 2 Zeilen identisch. Daher ließe sich da einiges zusammenfassen. Sollte man auch, v.a. wenn man mit Code zu tun hat, der ... schwieriger zu verstehen ist. Also sowas dann:

    VB.NET-Quellcode

    1. Private Function GetEncryptionStream() As CryptoStream
    2. Return GetCryptoStreamFor(FileMode.Create, CryptoStreamMode.Write)
    3. End Function
    4. Private Function GetDecryptionStream() As CryptoStream
    5. Return GetCryptoStreamFor(FileMode.Open, CryptoStreamMode.Read)
    6. End Function
    7. Private Function GetCryptoStreamFor(FileMode As IO.FileMode, CryptoStreamMode As CryptoStreamMode) As CryptoStream
    8. Dim key As New Rfc2898DeriveBytes(_masterPassword, New Byte() {10, 255, 255, 7, 14, 16, 23, 155})
    9. Dim x As New TripleDESCryptoServiceProvider()
    10. x.Key = key.GetBytes(x.KeySize \ 8)
    11. x.IV = key.GetBytes(x.BlockSize \ 8)
    12. Dim fS As FileStream = New FileStream(_dataPath, FileMode, FileAccess.ReadWrite, FileShare.None)
    13. Return New CryptoStream(fS, x.CreateEncryptor(), CryptoStreamMode)
    14. End Function

    und in tbPWleeren(): Es gibt auch die Möglichkeit mit TBpw1.Clear() zu arbeiten. Ist sauberer als TBpw1.Text = "". Denn dafür gibt es die Clear-Funktion.

    ##########

    btw: Wenn Du einen Projektordner hochlädst, bitte nicht nur den BIN- und OBJ-Ordner von unnötigem Ballast befreien, sondern auch den (versteckten) .vs-Ordner löschen. Der ist hier > 5 MB groß und komplett überflüssig (für uns, da er automatisch beim Projektmappenöffnen neu erstellt wird).
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „VaporiZed“ ()

    Zwischenfrage

    @ALL

    Eine kleine Zwischenfrage zu #41 von @VaporiZed . Soviel ich gelesen habe, arbeitest du schon mit VS 2019.

    Anscheinend hat man in VS2019 das CA2202 Using-Problem noch nicht gelöst und wird es wahrscheinlich weiterhin nicht
    mehr lösen wollen?
    docs.microsoft.com/de-de/visua…ltiple-times?view=vs-2015

    Gemäss oberer Link müsste man in dem Fall auf ein Try-Finally-Block ausweichen(? Aber Hallo), oder wie es jetzt vielfach
    gezeigt wird, einfach nicht weiter beachten und raus aus der Methode bzw. Scope ohne Dispose.
    Ich stell mal beide Varianten grundsätzlich in Frage.

    Was meint Ihr dazu? (Soll ich dazu ein neuer Thread eröffnen)

    Freundlicher Grüsse

    exc-jdbi
    @VaporiZed

    Aufpassen bei der Rückgabe. Hier muss entsprechend CreateDecryptor(), bzw. CreateEncryptor() als Parameter angegeben werden.

    VB.NET-Quellcode

    1. Private Function GetCryptoStreamFor(FileMode As IO.FileMode, CryptoStreamMode As CryptoStreamMode) As CryptoStream
    2. Dim key As New Rfc2898DeriveBytes(_masterPassword, New Byte() {10, 255, 255, 7, 14, 16, 23, 155})
    3. Dim x As New TripleDESCryptoServiceProvider()
    4. x.Key = key.GetBytes(x.KeySize \ 8)
    5. x.IV = key.GetBytes(x.BlockSize \ 8)
    6. Dim fS As FileStream = New FileStream(_dataPath, FileMode, FileAccess.ReadWrite, FileShare.None)
    7. If CryptoStreamMode = CryptoStreamMode.Read Then
    8. Return New CryptoStream(fS, x.CreateDecryptor(), CryptoStreamMode)
    9. Else
    10. Return New CryptoStream(fS, x.CreateEncryptor(), CryptoStreamMode)
    11. End If
    12. End Function
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    Hab ich sauber übersehen.
    Allerdings erübrigt sich (dann auch) meine Parameterübergabe und man kann gleich zu nem (von mir am liebsten gemiedenen) Boolean-Parameter übergehen:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Function GetEncryptionStream() As CryptoStream
    2. Return GetCryptoStream(True)
    3. End Function
    4. Private Function GetDecryptionStream() As CryptoStream
    5. Return GetCryptoStream(False)
    6. End Function
    7. Private Function GetCryptoStream(Encrypt As Boolean) As CryptoStream
    8. Dim key As New Rfc2898DeriveBytes(_masterPassword, New Byte() {10, 255, 255, 7, 14, 16, 23, 155})
    9. Dim x As New TripleDESCryptoServiceProvider()
    10. x.Key = key.GetBytes(x.KeySize \ 8)
    11. x.IV = key.GetBytes(x.BlockSize \ 8)
    12. Dim FileMode As IO.FileMode
    13. Dim CryptoStreamMode As CryptoStreamMode
    14. Dim Crypter As ICryptoTransform
    15. If Encrypt Then
    16. FileMode = IO.FileMode.Create
    17. CryptoStreamMode = CryptoStreamMode.Write
    18. Crypter = x.CreateEncryptor()
    19. Else
    20. FileMode = IO.FileMode.Open
    21. CryptoStreamMode = CryptoStreamMode.Read
    22. Crypter = x.CreateDecryptor()
    23. End If
    24. Dim fS As FileStream = New FileStream(_dataPath, FileMode, FileAccess.ReadWrite, FileShare.None)
    25. Return New CryptoStream(fS, Crypter, CryptoStreamMode)
    26. End Sub


    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    Ich mag halt die Using

    Hinweis: Für die Transformation des CryptoStreams darf der Filestream nicht geschlossen werden (darum ohne Using).
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub SaveData()
    2. If File.Exists(_dataPath) Then File.Delete(_dataPath)
    3. Using cS As CryptoStream = Me.GetCryptoStream(True)
    4. Me.AccountDetailsDataSet1.WriteXml(cS)
    5. End Using
    6. End Sub
    7. Private Sub LoadData()
    8. If File.Exists(_dataPath) Then
    9. 'Code für die Eingabe
    10. Using cS As CryptoStream = Me.GetCryptoStream(False)
    11. Me.AccountDetailsDataSet1.ReadXml(cS)
    12. End Using
    13. End If
    14. End Sub
    15. Private Function GetCryptoStream(_encrypt As Boolean) As CryptoStream
    16. Using key As New Rfc2898DeriveBytes(_masterPassword, New Byte() {10, 255, 255, 7, 14, 16, 23, 155})
    17. Using x As New TripleDESCryptoServiceProvider()
    18. x.Key = key.GetBytes(x.KeySize \ 8)
    19. x.IV = key.GetBytes(x.BlockSize \ 8)
    20. Dim _filemode = If(_encrypt, FileMode.Create, FileMode.Open)
    21. Dim _cryptostreammode = If(_encrypt, CryptoStreamMode.Write, CryptoStreamMode.Read)
    22. Dim _crypter = If(_encrypt, x.CreateEncryptor(), x.CreateDecryptor())
    23. Dim fS = New FileStream(_dataPath, _filemode, FileAccess.ReadWrite, FileShare.None)
    24. Return New CryptoStream(fS, _crypter, _cryptostreammode)
    25. End Using
    26. End Using
    27. End Function



    Lösen könnte man das irgendwie so. Es gibt so aber leider keine Übergabe mehr vom CryptoStream.
    Und die Datei 'accounts.xml' müsste zuerst kurz neu für diese Verkryptungsmethode geschrieben werden.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub SaveData()
    2. If File.Exists(_dataPath) Then File.Delete(_dataPath)
    3. GetSaveLoad(True)
    4. End Sub
    5. Private Sub LoadData()
    6. If File.Exists(_dataPath) Then
    7. GetSaveLoad(False)
    8. End If
    9. End Sub
    10. Private Sub GetSaveLoad(_encrypt As Boolean)
    11. Using key As New Rfc2898DeriveBytes(_masterPassword, New Byte() {10, 255, 255, 7, 14, 16, 23, 155})
    12. Using x As New TripleDESCryptoServiceProvider()
    13. x.Key = key.GetBytes(x.KeySize \ 8)
    14. x.IV = key.GetBytes(x.BlockSize \ 8)
    15. Dim _filemode = If(_encrypt, FileMode.Create, FileMode.Open)
    16. Dim _crypter = If(_encrypt, x.CreateEncryptor(), x.CreateDecryptor())
    17. Dim _cryptostreammode = If(_encrypt, CryptoStreamMode.Write, CryptoStreamMode.Read)
    18. Using fS = New FileStream(_dataPath, _filemode, FileAccess.ReadWrite, FileShare.None)
    19. Using cs = New CryptoStream(fS, _crypter, _cryptostreammode)
    20. 'Dim bf As New BinaryFormatter()
    21. If _encrypt Then
    22. Me.AccountDetailsDataSet1.WriteXml(cs)
    23. Return
    24. End If
    25. Me.AccountDetailsDataSet1.ReadXml(cs)
    26. End Using
    27. End Using
    28. End Using
    29. End Using
    30. End Sub


    FW 4.6.1.

    Die Codeanalyse spuckt hier für fS die Meldung "CA2202: Objekte nicht mehrmals verwerfen." aus.
    Da es sich um eine Datei handelt, die vom SW-Entwickler selber erstellt worden ist, stört mich das
    jetzt enorm. Würde es sich um eine Systemdatei handelt, wäre sie meiner Meinung nach berechtigt.

    FW 4.7.1.
    Der Code ist I.O.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „exc-jdbi“ ()

    Hallo ihr lieben
    Die Implermentierung in mein Programm klappt wunderbar.
    Drei Sachen habe ich aber noch.

    1. Wäre es ok den Benutzer aufzufordern ein beliebig langes Passwort, welches NUR AUS ZAHLEN besteht? Oder ist dies im Vergleich zu einem "normalen" Passwort zu unsicher?
    Hintergrund des ganzen ist, dass ich die PasswortForm etwas touchfreundicher gestalten möchte und die Passworteingabe mithilfe von Buttons realisieren will.
    Denn wenn ich mit einem Tablet unterwegs bin und erst die Bildschirmtastatur öffnen muss, um das Passwort einzugeben, laufe ich Amok!

    2. Ich möchte mein Programm maximiert starten. Dazu hatte ich WindowState auf maximized.
    Nun ist es aber so, dass das Programm im Hintergrund angezeigt wird, wenn die Passwortformen erscheinen.
    Also habe ich den WindowState im Designer auf normal gestellt und maximiere im Code nach Anzeige der Passwortboxen.
    Nun ist es aber so, dass ich das Programm nicht mehr über Close() verlassen kann, da hier immer der gesamte Code der Sub zuende gerödelt wird.
    Und dann kommt es zu einer Exception, bzw. die IDE meldet, dass sich das Programm im Haltemodus befindet (anstatt es zu beenden).
    Ich glaube dies liegt daran, dass die frmHauptform maxmiert werden soll, aber bereits entladen ist.
    Daher habe ich Close() durch Application.Exit ersetzt. Das läuft.
    Aber auch hier wird die Sub bis zum Ende durchlaufen. Es kommt daher zu einem Flackern, weil die Form maximiert und direkt wieder geschlossen wird.
    Gibt es hier irgendeine Abhilfe?

    Hier der Form Load Code
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub FrmMainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. 'DataSet laden
    3. If _DataFile.Exists Then DtsMain.ReadXml(_DataFile.FullName)
    4. 'verstecken der Reiter vom TabControl / vor Passwortangabe, damits nicht flackert
    5. TCMain.SuspendLayout()
    6. TCMain.SizeMode = TabSizeMode.Fixed
    7. TCMain.ItemSize = New Size(0, 1)
    8. TCMain.Appearance = TabAppearance.Buttons
    9. TCMain.ResumeLayout()
    10. 'Form Text Eigenschaft setzen
    11. Me.Text = "DasProgramm - version " & My.Application.Info.Version.ToString
    12. 'Prüfen ob die Settings Datei existiert, wenn nicht = erster Programstart
    13. If Not File.Exists(_SettingsFile) Then
    14. Using firststart As New frmFirstStart()
    15. 'Firststart Form zeigen und MasterPasswort abfragen
    16. If firststart.ShowDialog() = DialogResult.OK Then
    17. 'wenn pwcheck = False, stimmen Passörter nicht überein und Programmende
    18. 'sonst wird das _MasterPassword innerhalb der Function beschrieben
    19. If Not pwcheck(firststart.TBPassword1.Text, firststart.TBPassword2.Text) Then Close()
    20. Else
    21. 'wenn nicht Button OK gedrückt, Programm beenden
    22. Application.Exit()
    23. End If
    24. End Using
    25. Else
    26. 'wenn die Datei gefunden wurde, kommt die passwortabfrage
    27. Using PasswortEntry As New frmPasswordEntry()
    28. If PasswortEntry.ShowDialog() = DialogResult.OK Then
    29. _MasterPassword = PasswortEntry.TBPassword.Text
    30. Else
    31. 'wenn Button Cancel gedrückt, Programm beenden
    32. Application.Exit()
    33. End If
    34. End Using
    35. 'Wenn Button OK gedrückt, TryCatch zum laden der Settings Datei
    36. Try
    37. LoadSettings()
    38. Catch ex As Exception
    39. 'wenn laden fehlschlägt, wurde ein falsches Passwort eingegeben
    40. My.Settings.WrongPWCount = +1
    41. MessageBox.Show("Es wurde ein falsches Passwort eingegeben")
    42. 'TODO msgbox mit Ausrufezeichen
    43. Application.Exit()
    44. End Try
    45. End If
    46. 'wenn PW Count in den Settings größer 0, wurde das PW falsch eingegeben.
    47. If My.Settings.WrongPWCount > 0 Then
    48. MessageBox.Show("Das Passwort wurde " & My.Settings.WrongPWCount & " mal falsch eingegeben.")
    49. My.Settings.WrongPWCount = 0
    50. End If
    51. 'TODO Messagebox mit rotem Kreuz
    52. 'Programm maximieren / im Code, damit es währen Passworteingaben nicht sichtbar ist
    53. Me.WindowState = FormWindowState.Maximized
    54. End Sub
    Zu 1.
    Ich denke das ist eine Frage die du selber beantworten musst.

    Auch da gilt natürlich "Um so länger das Passwort, um so sicherer wird es".
    Traust du den dem Benutzer die Eingabe von z.b. 20 Zahlen ein?

    Länge 20 >>> 10^20 = 1 E20 Kombinationen

    Bei Buchstabe (End Gross oder Klein Buchstaben)
    Länge 8 >>> 26^8 = 2.088 E11 Kombinationen

    Bei Buchstaben und Zahlen (Gross Klein)
    Länge 8 >>> 62^8 = 2.134 E14 Kombinationen

    Ich könnte mir aber vorstellen, das es trotzdem mit Buchstaben und Zahlen geht. Ein Handy hat ja auch nur 10 Tasten für das Schreiben von SMS's.

    2.
    Mach aus Zeile 20-22

    VB.NET-Quellcode

    1. ​Else : Me.Close() : Return



    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „exc-jdbi“ ()

    Hallo Leute
    Ich komme deutlich besser voran als gedacht, aber an einer Stelle komme ich gerade nicht weiter.
    Ich poste das mal hier und nicht in einem neuen Thread, weil ich das hier angehängt Beispiel von @SpaceyX zum rumtesten verwende.
    Ich habe mir zwar noch mal die Youtube Videos vom @ErfinderDesRades angeschaut, aber zu diesem Problem nichts gefunden.
    Ich möchte in meinem Programm auf einer TabPage alle Bestellungen eines (auswählbaren) Lieferanten angezeigt bekommen und diese bearbeiten.
    Für die Auswahl dieses Lieferanten wollte ich mir eine eigene Form basteln. Da hier ja nachher alle Firmen aufgelistet werden (an die 60), wird es sonst in meiner Tab Page recht eng.

    Das Entschlüsselungspasswort des angehängten Beispiels ist immer noch password123
    Hier im Beispiel habe ich dazu das vorhandene DataSet um die Datatables (ich lerne die Benennung so allmählich :* ) Bestellung und Lieferant erweitert und entsprechend verknüpft.
    Dann habe ich ein Datagridview mit Binding zu DataSet - Lieferant/Bestellung generieren lassen.
    Wenn ich nun in der Hauptform ein weiteres Datagridview mit Binding an Dataset - Lieferant erstelle, werden mir ja nur Bestellungen zu diesem Lieferanten angezeigt.
    Das funktioniert also wunderbar.
    Nur will ich genau diese Auswahl auf einer separaten Form haben.
    Nach Aufruf dieser und Auswahl eines Lieferanten (Me.Close habe ich im Datagridview Double Klick untergebracht), ändert sich aber die Anzeige meiner Bestellungen Datagridview nicht.
    Es ist irgendwie so, als würde sich der BindingSource.Current nicht ändern.

    Was mache ich hier falsch? Funktioniert mein Vorhaben auf diese Weise überhaupt, oder komme ich nicht drumherum auf einer separaten Form den Lieferanten auszuwählen und dann meine BestellungBndingSource mittels .Filter zu filtern?
    Dateien
    • WindowsApp51.zip

      (50,24 kB, 28 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DerSmurf“ ()

    Na ist ja auch klar. Du rufst im Hauptform das Subform per .Show() auf. Und wenn man im Subform nen Doppelklick macht, wird das Subform geschlossen. Und mehr lässt Du ja nicht machen. Was soll da auch noch mehr passieren, Du veranlasst ja keine Änderungen. Nur weil im Subform was ausgewählt wird, ändert sich ja im Hauptform nix.
    Sinnvoller wäre das hier:

    VB.NET-Quellcode

    1. Using auswahl As New Form2()
    2. auswahl.AccountDetailsDataSet = Me.AccountDetailsDataSet1
    3. auswahl.LieferantBindingSource.DataSource = Me.AccountDetailsDataSet1
    4. auswahl.ShowDialog(Me)
    5. LieferantBindingSource.Position = auswahl.LieferantBindingSource.Position
    6. End Using

    Die Auswahl im Subform ändert jetzt das Lieferanten-Current im Hauptform. Ist zwar wegen Verwendung von Position nicht optimal, aber für den Anfang reicht es, um klarzumachen, worum es geht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hmm. Ich habe deinen Code jetzt noch nicht getestet, weil ich auf meinem Firmen PC unterwegs bin, aber er wird wohl schon laufen.
    Ich verstehe zwar was du meinst, aber nicht warum mein Code nicht funktioniert.

    VaporiZed schrieb:

    Was soll da auch noch mehr passieren, Du veranlasst ja keine Änderungen. Nur weil im Subform was ausgewählt wird, ändert sich ja im Hauptform nix.


    Ich übergebe doch das DataSet der Hauptform an die Subform:

    VB.NET-Quellcode

    1. auswahl.AccountDetailsDataSet = Me.AccountDetailsDataSet1
    2. auswahl.LieferantBindingSource.DataSource = Me.AccountDetailsDataSet1

    Dann verstehe ich nicht, warum es keine Änderung bewirkt, denn ich übergebe ja das DataSet.
    Wenn ich in der Subform einen Eintrag lösche zum Beispiel ist er ja im DataSet weg (also auch auf Form 1), warum trifft dies nicht auf eine geänderte .CUrrent Eigenschaft zu?
    Deine Hauptform-BindingSource (BS) und Subform-BS sind doch aber zwei (unabhängige) Instanzen. Du änderst doch nur in der Subform die Position der dortigen BS. Das ändert doch nix am tDS an sich. Das wäre so, als ob man 2 Objekte mit gleichem Namen hat, das eine ändert und sich plötzlich das andere auch ändert, obwohl es in einer anderen Klasse ist.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Huhu
    @VaporiZed, du hast mal gesagt, dass du de Helpers nicht nutzt. Daher folgende Frage:
    Wie stelle ich es (am einfachsten) an, den Wert einer Textbox in einer vorhandenen DataTableRow zu speichern.
    Also stell dir ein DataSet1, mit DataTable1 vor. DataTable1 hat nur eine Spalte "Name".
    Ich speichere nun zwei Werte 1. "Max" und 2. "Gustav"
    Ich möchte den ausgewählten Wert aus dem Datagridview in der Textbox angezeigt bekommen. Änderungen aus der Textbox, sollen aber erst nach Klick auf speichern übernommen werden. Ist kein Wert ausgewählt soll der erste Eintrag geändert werden.
    Also "Max" anklicken, in die Textbox "Sieglinde" schreiben, und erst nach Klick auf speichern, sollen die Werte im DataSet 1."Sieglinde" und 2."Gustav" lauten.

    Auf der Form platziere ich ein Datagridview mit Binding, eine Textbox (TBName) und einen speichern Button (speichern).
    Nun möchte ich den, im Datagridview ausgewählten, Namen in TBName angezeigt bekommen.
    Dafür setze ich auch ein entsprechendes Binding an die gleiche DataTable1BindingSource, wie mein Datagrdview.
    In den Eigenschaften der TBName --> DataBinding --> erweiterte Eigenschaften stelle ich den Datenquellen-Aktualisierungsmodus auf never.
    So erreiche ich das der Name den ich in im Datagridview anklicke in TBName angezeigt wird, eine Änderung in TBName hat aber keine Änderung des DataSet1 zur Folge. Dies soll erst nach einem Klick auf speichern passieren.
    Muss ich hier nun erstmal die aktuelle Bindingsource Position auslesen und dann den Wert schreiben, oder geht das einfacher?
    Wenn nämlich nicht nur der Name, sondern noch 15 andere Werte gespeichert werden, erscheint mir das recht umständlich:

    VB.NET-Quellcode

    1. 'Code habe ich frei Schnauze geschrieben, sorry für Fehler, die Intellisense verhindert hätte
    2. 'wenn kein Name ausgewählt, soll der erste Eintrrage geändert werden
    3. If DTDataTable1BindingSource.Current is nothing then DTDataTable1BindingSource.Position = 0
    4. Dim SelectedName = DirectCast(DirectCast(DTDataTable1BindingSource.Current, DataRowView).Row, DTDataSet1Row)
    5. SelectedName.Name = TBName.text
    6. 'wie schreibe ich den Wert jetzt wieder ins DataSet, an die korrekte Stelle?
    Das Vorgehen ist schon richtig, das Du da zusammengeschrieben hast. Zeile#3 ist m.E. irrelevant. Ich hab noch nicht bei mir erlebt, dass Current Nothing ist, während in der BindingSource.List mindestens ein Eintrag war. Aber hey, Stichwort UnitTests. Probier es aus.
    Wenn Du nicht nur 1 sondern 15 Werte ändern willst (gleichzeitig?), dann kommst Du an Deiner Vermutung bzgl. umständlich nicht vorbei. Ich würde es auch so machen. Oder ggf. gleich die komplette Row ersetzen? Oder vielleicht geht es auch, vor dem Großeingriff mit DataTable.AcceptChanges zu arbeiten, dann doch per DataBinding das Current zu verändern und wenn's einem doch nicht passt, was man da verzapft hat, mit DataTable.RejectChanges alles wieder auf Vorzustand versetzen. Müsste man ausprobieren. Aber ich begehe gerade eh einen anderen Weg, abseits von tDS und DataTables ...
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Wenn Du nicht nur 1 sondern 15 Werte ändern willst (gleichzeitig?)

    ja, gleichzeitig.
    Ich habe in meinem Programm zwei DataTable hierfür / Lieferant und Bestellungen
    Über die "Filter" Mehthode oben, zeige ich mir alle Bestellungen eines Lieferanten an.
    Die Spalten hier sind (bisher), Bestelldatum, Lieferdatum, Rechnungsdatum, Nettosumme19%, Netto7%, GesamtRe Summe, Rechnungsnummer, Notiz (sind nur 8 - hab schlecht geschätzt xD)
    Nun lege ich eine Bestellung an, indem ich die Bestelldatum Spalte mit Datum beschrifte.
    Alles andere änder ich dann gleichzeitg bei Rechnugserhalt.

    VaporiZed schrieb:

    mit DataTable.AcceptChanges zu arbeiten, dann doch per DataBinding das Current zu verändern und wenn's einem doch nicht passt, was man da verzapft hat, mit DataTable.RejectChanges

    DAs verstehe ich jetzt so, dass ich im Code den Datenquellen-Aktualisierungsmodus von Never wieder auf immer zurückstelle.
    Das werde ich mal testen, denn es würde mir ja einen haufen Coden (und ändern, falls ich mal eine neue Spalte im DataTable einfüge) sparen
    Hab's mit AcceptChanges und RejectChanges probiert. Klappt. Musst Du dann nur schauen, ob's irgendwelche Auswirkungen auf Deine Speichermethode hat. Wenn Du Dein tDS immer abspeicherst, dann isses wurscht. Wenn Du es abhängig von der Funktion DeinTds.HasChanges() machst, dann klappt das nicht mehr immer, weil: Wenn Du nur eine DataTable hättest und auf die wendest Du .AcceptChanges() an, dann meldet DeinTds.HasChanges(): False. Also obacht!
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Huhu
    Das erste Problem mit der Firmenauswahl habe ich nach deiner Anleitung gelöst - läuft wies soll.
    Beim zweiten bin ich mir nicht ganz sicher, ob mein Ansatz korrekt ist, denn was ich online zu AcceptChanges finde, hat mir nicht richtig geholfen.
    Ich speichere mein tDS immer beim schließen des Programmes.
    Wie folgt habe ich gecodet (diesmal in meinem eigentlichen Projekt darum sind die Namen anders).
    Dabei habe ich einfach mal mit Änderung in einer Spalte (Net7) angefangen und mir jegliche Überprüfung der eingegebenen Daten gespart.

    VB.NET-Quellcode

    1. Private Sub BTNSaveOrder_Click(sender As Object, e As EventArgs) Handles BTNSaveOrder.Click
    2. Dim SelectedOrder = DirectCast(DirectCast(DTOrdersBindingSource.Current, DataRowView).Row, DtsSettings.DTOrdersRow)
    3. SelectedOrder.Net7 = Double.Parse(Net7TextBox.Text)
    4. DtsSettings.AcceptChanges()
    5. End Sub

    Das funktioniert scheinbar - meinst du das so?

    Edit: Was ich mit DtsSettings.RejectChanges soll, versteh ich aber nicht.
    Ich habe einen zweiten Button eingefügt, der nur diesen Code enthält.
    Wenn ich im Datagridview mein tDS verändere, kann ich diese quasi wieder "rückgängig" machen.
    Trage ich die Daten aber mittels AcceptChanges ein, macht RejectChanges nix.
    Da ich eine Bearbeitung im Datagridview aussellen werde und die Textboxen zwar an die DataTale gebunden habe, jedoch den Datenquellen-Aktualisierungsmodus auf never gestellt habe, wird ja eh nichts in mein DataSet geschrieben, bis ich nicht auf speichern drücke.

    Also lasse ich RejectChanges einfach weg, oder hab ich was falsch verstanden?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DerSmurf“ ()