Light SQL in .NET met anorexia
Inclusief Data en File Cryptografie met 256 bits Rijndael algoritme
SQLite of "SQL Server CE" zonder (het gehannes met) automatisch gegenereerde Database, Connention, Datasets en Queries. Met voorbeeld in Visual Basic 2008 voor Windows & Mobile, eenvoudig om te zetten in C#. Met het 256 bits Rijndael algoritme EnCrypt/DeCrypt op een data-veld toepassen. Met detectie van x86, x64AMD, x64Intel processor
Inleiding:
Bij mijn
vorige project Googelde ik een enkele keer om een System.Data.SQL probleempje op te lossen. Ongelooflijk hoeveel vragen daar over zijn en hoe weinig goede/werkende/werkbare oplossingen er worden aangedragen. Zelf bij antwoorden van Microsoft-medewerkers blijf je vaak in het duister tasten. Uiteindelijk ben ik er met doorzoeken en uitproberen natuurlijk wel uitgekomen. Verder bleek mij dat de hoeveelheid informatie en juistheid er van op Forums voor C++ goed is, voor C# redelijk en voor VB zeer slecht. Een probleem is ook dat er in ADO.Net nogal wat paralleloplossingen zijn, verschillende mogelijkheden met het zelfde resultaat. Dus moet je er voor oppassen dat je niet van twee of meer walletjes tegelijk eet. Eerst begonnen met de halfautomatische VS oplossing, maar dat blijkt achteraf meer op het "met een kanon op een mug schieten". Ik wil mijn SQL database "oplossing" best met anderen delen, vandaar deze, laat ik het maar zo noemen, "Workshop". Daarnaast ook nog wat over het versleutelen van wachtwoord, data-velden en bestanden en een sterkwachtwoordgenerator. Nevenbij ook een oplossing voor de, veel geGoogelde, problemen met TextBox.Passwordchar en ComboBox in een DataGridView. Deze oplossing werkt, zonder aanpassingen, zowel bij Windows XP-SP2 t/m Win7 en Mobile 5 t/m 6.5 (dus niet Phone7). Enige kennis over/van SQL, queries, Database en programmeren in VB/C# is wel noodzakelijk, want dit is geen cursus en het "een en ander" kan vast wel beter.
Zomaar een, in de praktijk onbruikbare, database met SQLite-VB GUI als voorbeeld.
Een light SQL DB in Visual Studio 2005 - 2008 (of 2010 zonder Mobile):
In Visual Studio .NET lijkt het heel eenvoudig en makkelijk om een database te genereren en dan automatisch de Connection, Datasetsets, Adapters, BindingSources en de diverse querys te laten aanmaken door databinding in een Form.vb [Design] venster. En dat is het ook, behalve dan als je achteraf wijzigingen wilt aanbrengen in de tabellen, datatypen en queries want dan ben je "in de aap gelogeerd". Zo ook als je het progje distribueert, dan wijst de Connectionstring naar het oorspronkelijke path van jouw project. In tal van Forums staan oplossingen om dit laatste probleem, op meer of minder intelligente wijze, op te lossen. Maar ook dat blijft een heel gehannes want de oude Connection wordt steeds teruggezet of "Server Explorer" en MyDataSet.vb/xsd geven een error. Er is ook een andere, veel directere, oplossing met een heel flexibel resultaat en ook nog eens een veel kleinere EXE (bij mijn SaveMe!! 55%). Als je dan ook SQL Server CE inruilt voor SQLite (public domain) dan heb je ook nog eens minder DLLs en kan je progje ook zonder installatie overal draaien; Windows XP-SP2 t/m Win7, x86, x64AMD, x64Intel en Mobile 5-6.5 PRO.
Dit alles hebben we helemaal niet nodig en gaan we dan ook niet gebruiken
In plaats van het automatisch genereren van diverse bestanden met heel veel programmaregels kun je ook zelf een Class en/of Module schrijven. Dat vergt relatief weinig code, is zeer flexibel en onderhoudsvriendelijk en doet verder precies het zelfde. Een groot voordeel van zelf schrijven is ook dat je ook beter gaat begrijpen hoe het werkt. Op zich vind je dit ook gewoon in VS-HELP terug, daar staan namelijk diverse oplossingen voor het zelfde probleem beschreven. Het vervelende is echter dat dit nogal verspreid staat opgeslagen zodat je blijft bladeren en lezen in plaats van het programmeren.
Wat dit niet is en wat je reeds moet weten:
Dit is geen cursus programmeren, database en SQL statements ontwikkelen. Ik ga er vanuit dat de basiskennis aanwezig is. Zo nodig kun je met Googelen diverse gratis online cursussen vinden. Behoorlijk gedateerd maar heel duidelijk en nog steeds goed bruikbaar, ADO.NET: Developing Database Applications. Informatie over de opbouw van SQL-opdrachten kun je ook overal vinden, maar mijn voorkeur gaat uit naar: Uitgebreid (EN): SQL From Wikipedia, the free encyclopediaL Beperkt (NL): SQL (Structured Query Language)
SQL Server CE (gebruik ik niet meer):
Dat is bij Visual Studio .NET inbegrepen maar heeft als nadeel dat het uit vele DLLs bestaat, nogal veel bytes nodig heeft en dat je progje zonder installatie niet zal werken. SQL Sever CE, de laatste 2 tekens zeggen het al, is oorspronkelijk bedoeld voor Windows Smart Device, maar is ook bruikbaar voor Windows XP-SP2 t/m Win7 toepassingen. De informatie in Help-MSDN (t/m 2008) is verre van compleet maar bij microsoft.com kun je wel alles vinden: SQL Server Compact 3.5 Books Online en hier ADO.NET
SQLite & SQLite.NET (mijn voorkeur, open source):
SQLite en SQLite.NET code is practisch gelijk aan SQL Server CE en ADO.NET. SQLite kun je zo op het WWW vinden en is universeel inzetbaar. Het is echter niet zomaar even in VB/C#.NET te gebruiken, er is een zogenaamde "wrapper" nodig om er confortabel mee te kunnen werken. Bij http://sqlite.phxsoftware.com/ vindt je een perfecte wrapper (System.Data.SQLite) met er bij laatste SQLite versie:
System.Data.SQLite
An open source ADO.NET provider for the SQLite database engine
There are zero licensing restrictions for private or commercial use
Na installatie van deze wrapper werkt het in Visual Studio net zo als SQL Server CE alleen moet je op een enkele plaats de namespace SqlServerCe.<nnn> vervangen door SQLite.<nnn>. Met "alles" bedoel ik ook alles, dus ook het automatisch aanmaken en het "gehannes" van een database, Connection en Datasets (dat doen we hier dus niet). Het grote voordeel van SQLite is dat je progje slechts één SQL-DLL nodig heeft en je het zonder installatie kunt gebruiken. Bij Windows Mobile sluit je 2 DLLs bij. Helaas heeft men aparte DLLs voor 32 en 64 bits systemen gecompileerd, x86, x64AMD en x64Intel. Daardoor moet je bij distributie van je progje altijd 3 DLLs bijsluiten en er voor zorgen dat de juiste wordt gebruikt. Ook daar vindt je hier een programmatische oplossing voor zodat gebruikers hier geen hinder van ondervinden.
SQLite Administrator (database opzetten, freeware):
Dit is een zeer eenvoudig te gebruiken en redelijk goed hulpje om je tabellen te ontwerpen en te wijzigen. Je vindt het hier http://sqliteadmin.orbmu2k.de/ Hierin maak je je database met tabel(len) welke je dan in je toepassing gaat gebruiken. Achteraf aanpassen is simpel en je kunt eventueel ook data invoeren en bewerken. Het is nog Beta, maar ik kwam alleen maar een paar schoonheidfoutjes tegen.
Van VB naar C#:
Hier http://www.developerfusion.com/tools/convert/vb-to-csharp/ gaat dat perfect. Klik wel 2 x op copy to clipboard want soms.... Waarom in VB? Het WWW staat vol met C++ en C# oplossingen, voor VB is dat nogal beperkt. Conversie van VB naar C# gaat probleemloos en moet voor een beetje C Sharper een zachtgekookt eitje zijn.
Welke zaken zijn nodig om met je database te kunnen werken:
Eigenlijk net als bij het automatisch genereren: Connection, DataSet, Adapter, DataTable en als je Controls aan data wilt binden ook nog een BindingSource met Event. Een DataRow per tabel is extra, meer daarover volgt later. Het verschil is alleen dat je ze zelf declareert en ook zelf bepaald wat je ermee gaat doen. Dat bespaart je een enorme hoeveelheid, automatisch gegenereerde, onoverzichtelijke code.
Voorbeeld uit mijn SaveMe!! project
Merk op dat hier een Module is gebruikt, Module of Class, dat is afhankelijk van je toepassing
Deze attributen kun je zeer flexibel inzetten en gebruiken. DataBinding aan de diverse Form-controls kun je in het Form_Load-Event programmeren. Ook DataGridView-DataSource (en aanverwante eigenschappen) kun je gewoon in je code toepassen. In plaats van DataBinding kun je ook de BindingSource-Evens benutten om Controls, al dan niet aangepast, met DB-data te vullen. Beide methoden komen in een Form aan bod.
Dezelfde module voor Windows XP-Win7 en Mobile:
Mobile gebruikt een sterk beperkte commandoset en heeft soms een wat andere notatie en parameters nodig dan je normaal voor Windows zou coderen. Door hier rekening mee te houden kun je met één module voor beide toepassingen volstaan. Wel moet Mobile een eigen exemplaar hebben daar het anders een foutmelding geeft over de versie van System.Data in Compact Framework.
Wat gaan we maken:
Een heel eenvoudige, nogal rommelige, NAW database toepassing. Dat rommelige komt omdat het gebruik van de DB module voorop staat en de NAW-toepassing helemaal niets voorstelt cq op de voorbeeldfunctie na totaal nutteloos is. Ook geen tabelverknopingen/koppelingen/....., zoals voor een relationele -database, die kun je later zelf aanbrengen door het toevoegen van de daarvoor benodigde queries (gebruik de queries in de module als voorbeeld).De volgende Classes en Modules komen aan bod:
- Class NawDB
De database-Tabel-NAW procedures en functies.
Acties lokaal op DataSet en met SQL statements direct in DB. - Module PasswordDB
De database-Tabel-Password procedures en functies.
Ook een sub-Class om een BindingSource Event in een Class/Forms beschikbaar te maken.
Daar Password uit slechts één record bestaat welke en overal gelijk moet zijn kan dit in een module worden gestopt. - Module Diversen
Wat gemeenschappelijke variabelen, functies en subroutines. - Module Crypt
256 bits Rijndeal Encrypt en Decrypt van data en bestanden
Wachtwoordtest - Form frmInitDB
Test op 32/64bits Intel- of AMD-processor en klaarzetten van de juiste System.DataSQLite.DLL (1 uit 3 DLLs)
Test op database aanwezig.
Zet applicatie-Path, DB-filenaam en ConnectionString. - Form frmNAW
Demonstreren de werking van DB Module en Class.
Beveiligde wachtwoordbeveiliging vanuit database.
Listbox voor het snel voorzetten van een item in de TextBoxes en het DataGridView.
DataGridView met DataGridViewTextBoxColumn.PasswordChar (*) en DataGridViewComboBoxColumn.
Versleutelde (Encrypt) datavelden, via het wachtwoord, SubKey en Key.
Om het eenvoudig te houden wordt er "recht toe, recht aan", met duidelijke benamingen, gecodeerd. Aan het eindeloos voorzien van Remarks heb ik een hekel, ik vind dan de code onnodig uitgerekt waardoor het onoverzichtelijk wordt. Dus probeer ik de code "voor zichzelf" te laten spreken. Ik gebruik modules om variabelen en datavelden, in meerdere Forms/Classes/Modules tegelijk, met dezelfde waarden beschikbaar te hebben. In dit geval ook voor de Password-tabel.
De programmacode:
OOPs, ik ben ik niet eigenwijs, maar doe het wel op mijn eigen wijze! De Experts zullen wel de nodige bedenkingen hebben daar dit allemaal nu niet bepaald een OOP codering is. Ook zijn er Functions en Subs welke algemener bruikbaar zouden kunnen zijn. En daar hebben ze dan ook volkomen gelijk in. Maar dat OOP een must is, dat tijdperk, daar ben ik allang overheen. Soms is lekker ouderwets "recht toe, recht aan" programmeren ook een goede oplossing. Natuurlijk moet je de vroegere assembler en MS-Basic spaghetti's vergeten, maar zo kan het ook goed en onderhoudsvriendelijk zijn.
Maar... zo, op mijn eigen wijze dus, is het wat sneller, kleiner en toch overzichtelijk. Dus ook makkelijk aan te passen en vooral dat laatste, dat is hier belangrijk. En als Expert kun je er alsnog echte OOP van maken; toch...
Info: Over spaghetti gesproken, ik ben in 1976 met
Motorola 6800 machinetaal begonnen, daarna de "hogere talen" 68nn en 6502 assembler. Hoe men (we) toentertijd de code "verbeterde" en uitbreide, dat was op de duur totaal onleesbaar door het achteraf tussengevoegd heen en weer springen.
Het al dan niet delen van één database met Windows XP-Win7 en Mobile:
Het delen gaat eenvoudig zo: Al de volgende mappen en bestanden op één geheugenkaartje of USB-stick en het is universeel te gebruiken.
- Map NAW
Snelkoppeling naar Mobile\NAW.EXE (in PDA/Smartphone aanmaken)
Snelkoppeling naar Windows\NAW.EXE (in Windows aanmaken)- Map Database
NAW.s3db (het database-bestand) - Map Mobile
NAW.EXE (GUI aangepast aan PDA/Smartphone en zonder Form frmInitDB)
SQLite.Interop.dll
System.Data.SQLite.dll - Map Windows
NAW.EXE
System.Data.SQLite.AMD64.dll
System.Data.SQLite.IA64.dll
System.Data.SQLite.x86.dll
(Form InitDB kiest de juiste DLL en kopieert deze dan als System.Data.SQLite.dll)
- Map Database
Zonder Mobile sla je punt 2 over, zonder Windows sla je punt 3 over. In die gevallen zou je ook de database in de map bij de EXE kunnen plaatsen, dan moet je bij Form InitDB een aanpassing in de code maken bv DbPath = AppPath.
Als je het in een Windows-system-folder zet dan moet je voor de map Database en het bestand NAW.s3db de rechten voor schrijven aanpassen (of NAW.s3db in een documentenmap plaatsen en in het programma het path aanpassen).
LET OP de namen van de SQLite-DLLs!
SQLite.NET komt met diverse processor-Folders met daarin steeds een voor die processor specifieke System.Data.SQLite.dll.
Deze moet je zelf van de juiste namen voorzien (zie bij Map Windows hierboven).
Voor mobiele moet je SQLite.Interop.nnn.dll (nnn staat voor een getal bv. 066) wijzigen in SQLite.Interop.dll.
SQLite-foutmeldingen tijdens het opstarten zijn meestal aan een verkeerde DLL te wijten.
Na installatie van SQLite.NET vindt je hier de diverse DLLs.
Geen Demo-Download:
Gewoon "op je eigen wijze"gebruik maken van het voorbeeld en eventueel wat code kopiëren en plakken. dan weet je waar je mee bezig bent.
Database
De database:
Dat NWA (Naam, Adres, Woonplaats) database moet je niet serieus nemen, dit demo object moest toch een naam hebben.
Opslaan op een plaats naar keuze, ik kies voor Desktop, later plaatsen we twee kopieën in de VS .NET NAW Solution-Projecten. Open SQLite Administrator (Access of wat anders kan natuurlijk ook maar geeft waarschijnlijk ook meer bytes aan overhead) en maak de benodigde velden aan. In de 2e afb. staan al de velden met hun opties opgesomd (aangemaakt als in 1e afb.). Zoals je ziet is het in de praktijk niet echt bruikbaar maar voor deze demo ruim voldoende. Het veld Geheim, lengte 200 tekens, wordt voor het versleutelen gebruikt, blijft hier leeg en zit er nog even voor "spek en bonen" bij. Voor het gemak vul je gelijk wat records met je eigen data. Ik doe dat hier nogal fantasieloos maar wel makkelijk herkenbaar in de demo.
Het veld ID heeft hier maar een zeer beperkte functie maar is bij het verknopingen van tabellen onontbeerlijk (doen we hier niet aan). Maak nog een tabel aan met de naam Password met de velden Password en SubKey, elk met een lengte van 200 tekens (4e afb.). De waarden voor de velden Password en Subkey zijn in eenmalige programmacode aangemaakt:
' ''zo genereer je de eerste keer de waarden Password en SubKey ' ''voor in de Tabel Password Dim Password As String = "0000" Dim PasswordEncrypt As String = Encrypt(Password, Password) ' '' PasswordEncrypt: QZDIeuvQRZHlbi/Wl03y1w== ' '' ------------------------ Dim Subkey As String = "p|+I]{+IK3u%XqV+8|7h>%<e" Dim SubkeyEncrypt As String = Encrypt(Subkey, Password) ' ''SubkeyEncrypt: 0RMMpQhV0lr6rrDDIH9GdSnv2yGemF8hjygr0YVJ+yyGnfZSI1kAbPBPowjIdWv6zgYFteNca1U5B0pWDGCJBg== ' '' ----------------------------------------------------------------------------------------
Zoals je ziet is het wachtwoord met zichzelf versleuteld en de SubKey met het wachtwoord. De SubKey wordt samen met de Crypt-Key gebruikt om de datavelden "Geheim" te ver- en ontsleutelen. Als het wachtwoord wordt gewijzigd moet dus eerst de SubKey worden ontsleutelt om het dan met het nieuwe password opnieuw te versleutelen. Zie laatste afbeelding waar PasswordEncrypt en SubkeyEncrypt te plakken
Tabel en kolommen aanmaken...
ID = Prim.Key en auto-increment.
50 tekens per tekstveld is wel genoeg, Geheim 200 en Homepage 260.
De waarde van Relatiesoort komt later met ook tekst in een DataGridView Combobox.
Geheim blijft hier nog even geheim, in Textbox en DataGridView.columns wordt het met en zonder *-tjes weergegeven.
Er is een veld Password en SubKey nodig om de velden Geheim te ver- en ontsleutelen.
PasswordEncrypt (kopiëren en in veld Password plakken):
QZDIeuvQRZHlbi/Wl03y1w==
SubKeyEncrypt (kopiëren en in veld SubKey plakken):
0RMMpQhV0lr6rrDDIH9GdSnv2yGemF8hjygr0YVJ+yyGnfZSI1kAbPBPowjIdWv6zgYFteNca1U5B0pWDGCJBg==
Het versleutelde wachtwoord in de database is veilig. Als je het wachtwoord zomaar in de database of programmacode zet dan is het heel eenvoudig te achterhalen. Indien SubKey of, in Module Crypt, Key en/of IV worden gewijzigd dan is het wachtwoord onbruikbaar en geeft Decrypt een fout en blijven voortaan alle geheimen ook echt geheim. Dat laatste geld ook als het wachtwoord, na de eerste keer wijzigen, wordt vergeten. Tijdens DEBUGen kan het wachtwoord en de SubKey automatisch op boven vermelde waarden worden gereset met de procedure PasswordEnSubKeyReset() in Module PasswordDB.
TIP
Als je toch een database in je toepassing gebruikt kun je daar ook tabellen bij maken voor de opstartgegevens, talen,.
... en wat je nog meer kunt bedenken. Bij talen stopt je al je control-teksten, zoals van labels/knoppen/...., van één taal in één record. Via DataBinding of een BindinSourceEvent hang je de velden aan de juiste data-Column. Als van taal-record wordt gewisseld worden de schermteksten automatisch aangepast. Eventueel laat je de gebruiker zijn eigen schermteksten ingeven.
Project
Project:
Gelijk maar voor Windows en Mobile. Als je Mobile niet gebruikt kun je het Project NawMOB ook weglaten. Het kan zijn dat je in Visual Studio een Update moet doen naar Mobile 5, 6 en 6.5, het is bij Microsoft gratis te downloaden. Mobile (Smart Device Development) gebruikt haar eigen NawDB/PasswordDB/Crypt/Diversen, maar die zijn exact gelijk aan die voor Windows. De reden is dat er geen extra DLL ontstaat en omdat NawDB en PasswordDB de Compact Framework versie van System.Data nodig hebben. Daar de in Mobile te gebruiken opdrachten ook in de Windows-versie functioneren kun je de 4 bestanden simpelweg importeren.
Het Form frmDbInit is alleen voor de Windows-versie. De Forms frmNAW en frmNawMOB zijn aan code en controls voor ruim 90% gelijk. Het Mobile Form frmNawMOB laat ik aan je zelf over want 1 op 1 overzetten past niet op alle PDA/Smartphone-schermpjes. De gewenste Controls en prog.code kun bij Form frmNAW kopiëren en dan in frmNawMOB plakken, daarna wat aanpassingen maken. Welke aanpassingen: volg de lijst in het Errors venster (zijn er maar een paar en het is ook niet moeilijk) en de rest merk je wel bij het testen.
NAW is het Windows Project
NawMOB is het Smart Device Project
Met juiste Form starten en t/m het laatste Form open houden.
Nu nog even de Database erbij plaatsen...
...en de DLLs.
In de Debug en Release mappen van NawMOB zijn ze niet nodig
maar het is wel makkelijk als ze daar "kant & klaar" staan (zie hieronder).
Met deze Project instellingen en bestanden zou het, als de prog.code en controls er in zitten, moeten werken ;-)
Mobile Debugging:
Device Emulator en PDA/Smartphone
Na de eerste keer "Start Debugging (F5)" wordt map NAW aangemaakt en volg er een foutmelding.
1) Maak map Database en kopieer de DB er in.
2) Kopieer de 2 DLLs bij NAW.exe in de map.
"Start Debugging (F5)" zal nu NAW uitvoeren.
Na debugging kun je deze mapjes wissen en het, zoals eerder bij "Inleiding" omschreven, op een kaartje of stick zetten.
lsNawDB
clsNawDB:
Hier staat of valt je database-toepassing mee. Dit is, wat database betreft, een redelijk eenvoudige Class. Maar als je de werking ervan door hebt dan toets je zo een gecompliceerde module in elkaar, want het is in principe allemaal ongeveer het zelfde. Voorwaarde is dan wel dat je goede SQL queries kunt bouwen. Deze Class bevat de belangrijkste elementen voor de communicatie tussen DB-bestand en GUI. Er staan lokaal werkende acties in en directe, in de DB werkende, SQL acties in. Beide hebben het nadeel dat ze maar in één richting de gegevens bewerken; of alleen in de DB - of alleen in de GUI. In beide gevallen is het dus zaak om om de andere zijde te Updaten. Lokale acties zijn wat sneller maar ook minder zeker omdat, bij storing of verkeerd afsluiten, wijzigingen niet direct in de DB worden doorgevoerd en dan verloren gaan. Met SQL-acties is praktisch elke datamanipulatie mogelijk. gewoon een kwestie van de juiste query invoegen. Hier staan alleen wat simpele queries, maar met deze als voorbeeld kun je denk ik prima vooruit. Als je het begrijpt zijn ook relationele-databewerkingen eenvoudig toe te passen. Daar clsNawDB een Class is kun je het op diverse plaatsen declareren en met eigen DB-data gebruiken. Anders is dat bij de Module modPasswordDB. Deze heeft nagenoeg dezelfde opbouw als clsNawDB maar is, ongedeclareerd, overal met dezelfde DB-data beschikbaar. Eerder zagen we al dat Database, Connection, DataSet, Adapter, DataTable, BindingSource met Event noodzakelijk zijn. Extra een DataRow per tabel (zie ook modPasswordDB) welke steeds automatisch wordt gevuld vanuit het geselecteerde record en zo eenvoudig is uit te lezen. Gebruikt ze ook voor het kopiëren van ongewijzigde waarden in queries. Enkele van deze componenten zijn als Public en anderen als Private gedeclareerd. Je ziet dus gelijk welke je ook buiten deze module kunt benutten. Om het overzichtelijk te houden is de code in logische blokken opgedeeld:
#Region "<naam>" '' ' code blok #End Region ' <naam>
Code welke niet door deze demo NAW GUI wordt gebruikt hoeft niet gecompileerd te worden, dat staat dan in een conditieblok:
#Const Compile = False '#Const Compile = true #If Compile Then '' ' code #End If ' compile
Namen zijn zo gekozen dat ze, naar mijn mening, bijna voor zichzelf spreken.
Project NAW - clsNawDB.vb
Imports System.Data.SQLite Public Class NawDB ' '' NAW-record(s) moet(en) per Form individueel beschikbaar zijn ' '' dus staat deze in een Class #Region "NAW" Private _RowGetTblNAW As DataRow ' BindingSourceTblNAW.Current-Record voor uitlezen Public ReadOnly Property RowTblNAW() As DataRow Get Return _RowGetTblNAW End Get End Property Private Connection As New SQLiteConnection ' de connectie met het DB-bestand Private DataSetDbNAW As DataSet = New DataSet() ' de set DB-tabellen Private AdapterTblNAW As SQLiteDataAdapter ' de adapter werkt direct met DB Private DataTableTblNAW As DataTable ' de lokale tabel Public WithEvents BindingSourceTblNAW As New BindingSource() ' binding vanuit DataTable Public Event BindingSourceTblNAWChanged(ByVal Records As Integer) ' doorgeven van binding-Event Public Function InitDB() As Boolean Try Dim i As Integer Connection.ConnectionString = ConnectionString Connection.Open() AdapterTblNAW = New SQLiteDataAdapter("SELECT * FROM tblNAW", Connection) i = AdapterTblNAW.Fill(DataSetDbNAW, "tblNAW") DataTableTblNAW = DataSetDbNAW.Tables("tblNAW") BindingSourceTblNAW.DataSource = DataTableTblNAW Catch ex As Exception Return False End Try Return True End Function Public Sub CloseDB() Try Dim i As Integer i = AdapterTblNAWUpdate() Connection.Close() BindingSourceTblNAW.Dispose() DataTableTblNAW.Dispose() AdapterTblNAW.Dispose() DataSetDbNAW.Dispose() Connection.Dispose() Catch ex As Exception End Try End Sub Public Function AdapterTblNAWUpdate() As Integer Dim cmdBuilder As SQLiteCommandBuilder cmdBuilder = New SQLiteCommandBuilder(AdapterTblNAW) Return AdapterTblNAW.Update(DataSetDbNAW, "tblNAW") End Function Private Sub DBNullTest() ' '' Vervangt een eventueel DBNull.Value door een lege Sting If DBNull.Value.Equals(_RowGetTblNAW("Naam")) Then _RowGetTblNAW("Naam") = "" If DBNull.Value.Equals(_RowGetTblNAW("Adres")) Then _RowGetTblNAW("Adres") = "" If DBNull.Value.Equals(_RowGetTblNAW("Woonplaats")) Then _RowGetTblNAW("Woonplaats") = "" If DBNull.Value.Equals(_RowGetTblNAW("Geheim")) Then _RowGetTblNAW("Geheim") = "" If DBNull.Value.Equals(_RowGetTblNAW("Homepage")) Then _RowGetTblNAW("Homepage") = "" If DBNull.Value.Equals(_RowGetTblNAW("Relatiesoort")) Then _RowGetTblNAW("Relatiesoort") = 0 End Sub Private Sub BindingSourceTblNAW_CurrentChanged(ByVal sender As Object, ByVal e As EventArgs) _ Handles BindingSourceTblNAW.CurrentChanged ' '' Vult, na wijzigen van SelectedIndexChange, _RowGetTblNAW met het huidige record ' '' Roept BindingSourceTblPassword_CurrentChanged-Event aan bij gebruikers-Class If BindingSourceTblNAW.Count > 0 Then ' '' CType() tegen Late Binding Error in Mobile _RowGetTblNAW = CType(BindingSourceTblNAW.Current, DataRowView).Row DBNullTest() RaiseEvent BindingSourceTblNAWChanged(BindingSourceTblNAW.Count) End If End Sub #End Region ' NAW ' '' ______________________________________________________________________________ ' '' Acties via een DataSet: ' '' Deze zijn lokaal, dus sneller maar ook minder veilig ' '' Vergeet je een DataAdapter.Update of ongewone beëindigen van het programma ' '' dan gaan de wijzigen verloren ' '' DataBinding van Controls is ook lokaal, dus moet je wijzigingen middels prog.code ' '' in de database opslaan ' '' ' '' Acties via een SQL statement: ' '' Deze werken direct in de database, dat is veilig maar relatief traag ' '' Zonder DataAdapter.Fill komt het niet in je DataTable terecht ' '' ' '' Het Form frmNAW gebruikt slecht 1 van onderstaande acties daar BindingSource ook ' '' diverse mogelijkheden heeft ' '' Gebruik ze als model voor uitbreiding of andere ontwikkelingen #Const Compile = False '#Const Compile = true #Region "Acties via DataSet" #If Compile Then Private Function UpdateInsert(ByVal ID As Integer, ByVal Naam As String, _ ByVal Adres As String, ByVal Woonplaats As String, ByVal Geheim As String, _ ByVal Homepage As String, ByVal Relatiesoort As Integer) As Boolean ' '' ID: -1 Insert, >0 Update Dim i As Boolean = True Try Dim row As DataRow If ID = -1 Then row = DataTableTblNAW.NewRow() Else ' '' Dit werkt zo natuurlijk alleen met een uniek veld als ID ' '' In andere gevallen gebruik je een Row(Array) ' '' Select("<naam> = '<parameter>'") is een wat anders uitziende query row = DataTableTblNAW.Select("ID = '" & ID & "'")(0) End If row("Naam") = Naam row("Adres") = Adres row("Woonplaats") = Woonplaats row("Geheim") = Geheim row("Homepage") = Homepage row("Relatiesoort") = Relatiesoort Catch ex As Exception i = False End Try Return i End Function Public Function NAWUpdate(ByVal ID As Integer, ByVal Naam As String, ByVal Adres As String, _ ByVal Woonplaats As String, ByVal Geheim As String, ByVal Homepage As String, _ ByVal Relatiesoort As Integer) As Boolean Return UpdateInsert(ID, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort) End Function Public Function NAWInsert(ByVal Naam As String, ByVal Adres As String, _ ByVal Woonplaats As String, ByVal Geheim As String, ByVal Homepage As String, _ ByVal Relatiesoort As Integer) As Boolean Return UpdateInsert(-1, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort) End Function Public Function NAWDelete(ByVal ID As Integer) As Boolean Dim i As Boolean = True Try ' '' Dit werkt zo natuurlijk alleen met een uniek veld als ID ' '' In andere gevallen gebruik je een Row(Array) ' '' Select("<naam> = '<parameter>'") is een wat anders uitziende query Dim row As DataRow = DataTableTblNAW.Select("ID = '" & ID & "'")(0) row.Delete() Catch ex As Exception i = False End Try Return i End Function #End If ' compile #End Region ' Acties via DataSet #Region "Acties via SQL statements" Public Function NAWSelectSQL(ByVal Relatiesoort As Integer) As Integer ' '' Relatiesoort: -1 of 0 = alles, >0 selectief Dim Query0 As String = "SELECT * FROM tblNAW" Dim Query1 As String = " WHERE (Relatiesoort = @Relatiesoort)" Dim i As Integer = 0 Try If Relatiesoort = 0 OrElse Relatiesoort = -1 Then AdapterTblNAW.SelectCommand.CommandText = Query0 Else AdapterTblNAW.SelectCommand.Parameters.Add("@Relatiesoort", _ SqlDbType.Int).Value = Relatiesoort AdapterTblNAW.SelectCommand.CommandText = Query0 & Query1 End If DataTableTblNAW.Clear() i = AdapterTblNAW.Fill(DataTableTblNAW) Catch ex As Exception Return -1 End Try Return i End Function #If Compile Then Private Function NAWUpdateInsertSQL(ByVal ID As Integer, ByVal Naam As String, _ ByVal Adres As String, ByVal Woonplaats As String, ByVal Geheim As String, _ ByVal Homepage As String, ByVal Relatiesoort As Integer) As Boolean ' '' ID: -1 Insert, >0 Update Dim i As Integer = 0 Try Dim cmd As SQLiteCommand = Connection.CreateCommand() cmd.Connection.Open() Dim p As SQLiteParameter = Nothing cmd = Connection.CreateCommand() If ID = -1 Then cmd.CommandText = _ "INSERT " & _ "INTO NAW (ID, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort) " & _ "VALUES (@Naam, @Adres, @Woonplaats, @Geheim, @Homepage, @Relatiesoort)" Else cmd.CommandText = _ "UPDATE NAW " & _ "SET Naam = @Naam, Adres = @Adres, Woonplaats = @Woonplaats, Geheim = @Geheim, " & _ "Homepage = @Homepage, Relatiesoort = @Relatiesoort " & _ "WHERE (ID = @ID)" p = cmd.Parameters.Add("@ID", SqlDbType.Int) p.Value = ID p.SourceVersion = DataRowVersion.Original End If p = cmd.Parameters.Add("@Naam", SqlDbType.VarChar, 32) p.Value = Naam p.SourceVersion = DataRowVersion.Current p = cmd.Parameters.Add("@Adres", SqlDbType.VarChar, 32) p.Value = Adres p.SourceVersion = DataRowVersion.Current p = cmd.Parameters.Add("@Woonplaats", SqlDbType.VarChar, 32) p.Value = Woonplaats p.SourceVersion = DataRowVersion.Current p = cmd.Parameters.Add("@Geheim", SqlDbType.VarChar, 100) p.Value = Geheim p.SourceVersion = DataRowVersion.Current p = cmd.Parameters.Add("@Homepage", SqlDbType.VarChar, 260) p.Value = Homepage p.SourceVersion = DataRowVersion.Current p = cmd.Parameters.Add("@Relatiesoort", SqlDbType.Int) p.Value = Relatiesoort p.SourceVersion = DataRowVersion.Current i = cmd.ExecuteNonQuery() AdapterTblNAW.UpdateCommand = cmd cmd.Connection.Close() cmd.Dispose() If i = 0 Then Throw New ApplicationException() End If i = AdapterTblNAW.Fill(DataSetDbNAW, "tblNAW") Catch ex As Exception Return False End Try Return True End Function Public Function NAWUpdateSQL(ByVal ID As Integer, ByVal Naam As String, _ ByVal Adres As String, ByVal Woonplaats As String, ByVal Geheim As String, _ ByVal Homepage As String, ByVal Relatiesoort As Integer) As Boolean Return NAWUpdateInsertSQL(ID, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort) End Function Public Function NAWInsertSQL(ByVal Naam As String, ByVal Adres As String, _ ByVal Woonplaats As String, ByVal Geheim As String, ByVal Homepage As String, _ ByVal Relatiesoort As Integer) As Boolean Return NAWUpdateInsertSQL(-1, Naam, Adres, Woonplaats, Geheim, Homepage, Relatiesoort) End Function Public Function NAWDeleteSQL(ByVal ID As Integer) As Boolean Dim i As Integer = 0 Try Dim cmd As SQLiteCommand = Connection.CreateCommand() cmd.Connection.Open() Dim p As SQLiteParameter = Nothing cmd.CommandText = _ "DELETE " & _ "FROM NAW " & _ "WHERE (ID = @ID)" p = cmd.Parameters.Add("@ID", SqlDbType.Int, 4, "ID") p.Value = ID p.SourceVersion = DataRowVersion.Original i = cmd.ExecuteNonQuery() AdapterTblNAW.DeleteCommand = cmd cmd.Connection.Close() cmd.Dispose() If i = 0 Then Throw New ApplicationException() End If i = AdapterTblNAW.Fill(DataSetDbNAW, "tblNAW") Catch ex As Exception i = -1 End Try Return i End Function Public Function NAWDeleteAllSQL() As Integer ' '' Opgepast!!! alles weg en niet ongedaan te maken ' '' Return: -1 niet uitgevoerd, >=0 aantal Dim i As Integer = 0 Try ' ''Dit doen we met een query Dim cmd As SQLiteCommand = Connection.CreateCommand() cmd.Connection.Open() Dim p As SQLiteParameter = Nothing cmd.CommandText = _ "DELETE " & _ "FROM tblNAW" i = cmd.ExecuteNonQuery() AdapterTblNAW.DeleteCommand = cmd cmd.Connection.Close() cmd.Dispose() If i = 0 Then Throw New ApplicationException() End If i = AdapterTblNAW.Fill(DataSetDbNAW, "tblNAW") Catch ex As Exception i = -1 End Try Return i End Function #End If ' compile #End Region ' Acties via SQL statements End Class
modPasswordDB
modPasswordDB:
Dit is, wat database betreft, een heel erg simpele module. Eerder zagen we al dat Database, Connection, DataSet, Adapter, DataTable, BindingSource met Event noodzakelijk zijn. Ik geef geen uitleg over deze standaard componenten, dat weet je vast al wel en anders zoek het even op. Extra een DataRow per tabel welke steeds automatisch wordt gevuld vanuit het geselecteerde record en zo eenvoudig is uit te lezen. Gebruikt ze ook voor het kopiëren van ongewijzigde waarden in queries. Enkele van deze componenten zijn als Public en anderen als Private gedeclareerd. Je ziet dus gelijk welke je ook buiten deze module kunt benutten.
Bestand of velden versleutelen?
Een heel bestand versleutelen maakt het bestand maar iets groter. Losse velden versleutelen kost veel ruimte (kijk bij Password en SubKey). Dus waarom zou je voor het laatste kiezen? De data uit een versleuteld bestand komt onversleuteld in het geheugen te staan en is met een geheugendump leesbaar te maken. Daarentegen staan versleutelde velden ook versleuteld in het geheugen en ontsleutel je ze alleen op het moment dat het noodzakelijk is. Het is dus een kwestie van welk beveiligingsniveau gewenst is.
Heb je de Database met een wachtwoord beveiligd?
In dat geval moet je eerst het database-wachtwoord laten ingeven voor je de Function InitDb() aanroept. En in InitDb() de Connection.ConnectionString aanpassen:
Public myDbPassword as String ="; Password=" & Me.txtDbWachtwoord.Text ' of via InputBox Connection.ConnectionString = "Data Source=" & DbPath & DbFile & myDbPassword
Indien InitDB waarde False geeft dan is myDbPassword fout. Er zijn voor het beveiligen met wachtwoord meer parameters beschikbaar, maar de default-waarden zijn SQLite voldoende en kun je, naar mijn ervaring, wel vergeten. Kijk bij SQLite-Help hoe achteraf met wachtwoord te beveiligen, of de beveiliging te verwijderen, het is nogal simpel te doen.
Let op de spaties aan het einde in de diverse query deel-regels!
Project NAW - modPasswordDB.vb
Imports System.Data.SQLite Module PasswordDB ' '' Het Password-record telt slechts één record en is als Public Module overal beschikbaar ' '' Taal-records, prog.waarden, .... kun je zo ook in deze/een Module stoppen ' '' Via een Sub-Clas wordt het BindingSourceTblPassword-Event doorgegeven, ' '' dat wordt hier niet gebruikt maar is wel als voorbeeld aanwezig ' '' Werkt zonder declaratie, verder net als Class NawDB #Region "Password" Public RowTblPassword As DataRow ' BindingSourceTblPassword.CurrentRecord voor uitlezen Private Connection As New SQLiteConnection ' de connectie met het DB-bestand Private DataSetDbNAW As DataSet = New DataSet() ' de set DB-tabellen Private AdapterTblPassword As SQLiteDataAdapter ' de adapter werkt direct met DB Private DataTableTblPassword As DataTable ' de lokale tabel Public WithEvents BindingSourceTblPassword As New BindingSource() ' binding vanuit DataTable #If DEBUG Then ' '' Wachtwoord: 0000 (4 x NUL) Private Sub PasswordEnSubKeyReset() ' '' Zet tijdens DEBUGen password op 0000 en reset de SubKey, wordt aanroepen vannuit InitDB ' '' zo genereer/herstel je de waarden van Password en SubKey in de Tabel Password Dim Password As String = "0000" Dim PasswordEncrypt As String = Encrypt(Password, Password) Dim SubkeyEncrypt As String = Encrypt("p|+I]{+IK3u%XqV+8|7h>%<e", Password) If PasswordUpdate(RowTblPassword("ID"), PasswordEncrypt, SubkeyEncrypt) Then _ AdapterTblPasswordUpdate() ' gelijk in DB opslaan End Sub #End If Public Function InitDB() As Boolean Dim i As Integer Connection.ConnectionString = ConnectionString Connection.Open() AdapterTblPassword = New SQLiteDataAdapter("SELECT * FROM tblPassword", Connection) i = AdapterTblPassword.Fill(DataSetDbNAW, "tblPassword") DataTableTblPassword = DataSetDbNAW.Tables("tblPassword") BindingSourceTblPassword.DataSource = DataTableTblPassword If i <> 1 Then Return False ' geen, of meer dan één, tblPassword record #If DEBUG Then PasswordEnSubKeyReset() ' uitschakelen met ' (REM) #End If Return True End Function Public Sub CloseDB() Try Dim i As Integer i = AdapterTblPasswordUpdate() Connection.Close() BindingSourceTblPassword.Dispose() DataTableTblPassword.Dispose() AdapterTblPassword.Dispose() DataSetDbNAW.Dispose() Connection.Dispose() Catch ex As Exception End Try End Sub Public Function AdapterTblPasswordUpdate() As Integer Dim cmdBuilder As SQLiteCommandBuilder cmdBuilder = New SQLiteCommandBuilder(AdapterTblPassword) Return AdapterTblPassword.Update(DataSetDbNAW, "tblPassword") End Function Sub BindingSourcePassword_CurrentChanged(ByVal sender As Object, ByVal e As EventArgs) _ Handles BindingSourceTblPassword.CurrentChanged ' '' vult, na wijzigen van SelectedIndexChange, RowPassword met het huidige record ' '' roept sub-"Class BindingSourcesClass" op om een Event door te geven aan andere Classes (Forms) If BindingSourceTblPassword.Count > 0 Then ' '' CType() tegen Late Binding Error in Mobile RowTblPassword = CType(BindingSourceTblPassword.Current, DataRowView).Row End If ' ''####### voorbeeld MODULE-Event BindingSourcesEvents.BSPassword() 'Event doorgeven via sub-Class-Event End Sub #End Region ' Password ' '' Alleen Select * en Update nodig ' '' Zie clsNawDB voor info "Acties via DataSet" en "Acties via SQL statements" #Region "Acties via DataSet" Public Function PasswordUpdate(ByVal ID As Integer, ByVal Password As String, _ ByVal SubKey As String) As Boolean ' '' in dit geval het enigste record Updaten ' '' LET OP!!!! voordat je een nieuw versleuteld wachtwoord ingeeft: ' '' SubKey moet eerst met het OUDE wachtwoord worden ontsleuteld en ' '' met het NIEUWE wachtwoord versleutelen en dan pas het oude wachtwoord vervangen ' '' Natuurlijk kan dat hier ook maar ik geef er de voorkeur aan ' '' om het buiten deze module te houden Dim i As Boolean = True Try Dim row As DataRow = DataTableTblPassword.Select("ID = '" & ID & "'")(0) row("Password") = Password row("SubKey") = SubKey Catch ex As Exception i = False End Try Return i End Function #End Region ' Acties via DataSet #Region "Acties via SQL statements" Public Function PasswordSelectSQL() As Integer ' '' in dit geval het enigste record Selecteren ' '' return: -1 niet uitgevoerd, >=0 gelukt Dim Query As String = "SELECT * FROM tblPassword" Dim i As Integer = 0 Try AdapterTblPassword.SelectCommand.CommandText = Query DataTableTblPassword.Clear() i = AdapterTblPassword.Fill(DataTableTblPassword) Catch ex As Exception i = -1 End Try Return i End Function #End Region ' Acties via SQL statements #Region "RaiseEvent-BindingSourcesClass" ' ''####### voorbeeld MODULE-Event Public BindingSourcesEvents As New BindingSourcesClass Public Class BindingSourcesClass ' '' geeft Events door Public Shared Event BSPasswordCurrentChanged(ByVal count As Integer) Public Sub BSPassword() ' deze is eigenlijk niet nodig daar er maar één record is RaiseEvent BSPasswordCurrentChanged(BindingSourceTblPassword.Count) End Sub End Class #End Region ' RaiseEvent-BindingSourcesClass End Module
modDiversen
modDiversen:
Wat hulpmiddelen voor algemeen gebruik.
Project NAW - modDiversen.vb
Imports System.Reflection Imports System.IO Imports System.Data.SQLite Public Module Diversen Public AppPath As String = "" Public DbPath As String = "" Public DbFile As String = "" Public ConnectionString As String = "" Public w1 As String = "" ' om wachtwoord in te verstoppen Public w2 As String = GenerateStrongPW(32) ' om wachtwoord mee te verstoppen ' '' Voor GenerateStrongPW() en algemeen gebruik bij ingave-velden Public Const Lettertekens As String = _ "~!@#$%^&*()_+[]{}<>?-=\,./:""| " & _ "abcdefghijklmnopqrstuvwxyz" & _ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" & _ "1234567890" Public Function CompactDB() As Integer ' '' Compact/Compress/Vacuum 3 namen voor het zelfde doel: database opruimen ' '' Return: >=0 verschil in bytes, -1 = fout Try Dim Connection As New SQLiteConnection Connection.ConnectionString = ConnectionString Dim FileVoor, FileNa As Long Dim Dir As New DirectoryInfo(DbPath) Dim File As FileInfo() = Dir.GetFiles(DbFile) FileVoor = File(0).Length Dim cmd As SQLiteCommand = Connection.CreateCommand() cmd.Connection.Open() cmd.CommandText = "VACUUM" cmd.ExecuteNonQuery() cmd.Connection.Close() cmd.Dispose() File = Dir.GetFiles(DbFile) FileNa = File(0).Length Return FileVoor - FileNa Catch ex As Exception Return -1 End Try End Function Public Function GetAppPath() As String ' '' Applicatie Path ' '' Kan anders maar werkt zo ook voor Mobile Dim asm As [Assembly] = [Assembly].GetExecutingAssembly() Return System.IO.Path.GetDirectoryName(asm.GetName().CodeBase) End Function Public Function GenerateStrongPW(ByVal Lengte As Integer) As String ' '' Een sterk wachtwoord van 4-32 tekens aanmaken Select Case Lengte Case Is < 4 : Lengte = 4 Case Is > 32 : Lengte = 32 End Select Dim StrongPW As String = "" Dim symb1 As String = Lettertekens.Replace(" ", "").Replace(vbCrLf, "") For i As Integer = 1 To Lengte Dim rand As Random = New System.Random(Guid.NewGuid().GetHashCode()) Dim teken As Integer = rand.Next(0, symb1.Length - 1) StrongPW &= Lettertekens.Substring(teken, 1) Next Return StrongPW End Function Public Function w4(ByVal k As String) As String ' '' Wachtwoord en SubKey staan versleuteld in het geheugen ' '' Bewust nietszeggende namen w1, w2, w3, w4 en k Dim w3 As String = Decrypt(w1, w2) ' lees Wachtwoord Return Decrypt(k, w3) ' geef SubKey k End Function End Module
modCrypt
modCrypt:
Met deze module kun je eenvoudig en zeer veilig losse gegevens en/of bestanden versleutelen.
Encrypt = versleutelen
Decrypt = ontsleutelen
Doormiddel van een zelf te wijzigen SubKey of Wachtwoord wordt, vanuit een basis Key, een unieke 256 Bits Key samengesteld.
Project NAW - modCrypt.vb
Imports System.IO Imports System.Text Imports System.Security.Cryptography Public Module Crypt ' '' Encrypt/Decrypt byte-array, string en file met unieke 256 Bits Key ' '' Lossse data geeft bij een fout de string "Fout" terug ' '' Bij bestanden wordt een code geretouneerd Private algorithm As Rijndael = Rijndael.Create() Private Key As Byte() Private IV As Byte() = {38, 108, 24, 216, 222, 181, 118, 68, 177, 45, 239, 211, 175, 151, 38, 77} Const Fout As String = "(ERROR)" #Const Compile = False '#Const Compile = true Public Function PasswordOk(ByVal ToDecrypt As String, ByVal Password As String) As Boolean ' '' Test password ' '' ToDecrypt: versleutelde wachtwoord ' '' Password: door gebruiker ingegeven wachtwoord Return Decrypt(ToDecrypt, Password) <> Fout End Function Private Sub MakeKey(ByVal Sleutel As String) ' '' Maakt unieke Key van basis-Key en Sleutel (SubKey of Sleutel) If Sleutel.Length > 32 Then Sleutel = Sleutel.Substring(0, 31) Dim SleutelBytes As Byte() = Encoding.UTF8.GetBytes(Sleutel) Key = New Byte() {13, 28, 18, 114, 33, 100, 175, 128, 171, 216, 33, 62, 55, 189, 214, 104, _ 241, 53, 46, 15, 99, 112, 104, 10, 6, 153, 52, 172, 86, 218, 40, 100} Array.Copy(SleutelBytes, Key, SleutelBytes.Length) End Sub #If Compile Then Private Function Filetest(ByVal fileIn As String, ByVal fileOut As String) As Integer ' '' Return: 1 = no FileIn, 2 = user cancelled If Not File.Exists(fileIn) Then Return 1 If File.Exists(fileOut) AndAlso MsgBox("re-write " & fileOut, _ MsgBoxStyle.Information Or MsgBoxStyle.OkCancel) = MsgBoxResult.Cancel Then Return 2 End Function #End If #Region "Encrypt" Public Function Encrypt(ByVal ToEncryptData As Byte()) As Byte() Dim encryptedData As Byte() = Encoding.Unicode.GetBytes(Fout) Dim MemStream As New MemoryStream() Try algorithm.Key = Key algorithm.IV = IV Dim CryptStream As CryptoStream = New CryptoStream(MemStream, algorithm.CreateEncryptor(), _ CryptoStreamMode.Write) CryptStream.Write(ToEncryptData, 0, ToEncryptData.Length) CryptStream.Close() encryptedData = MemStream.ToArray() CryptStream.Dispose() Return encryptedData Catch ex As Exception Return encryptedData Finally MemStream.Close() MemStream.Dispose() End Try End Function Public Function Encrypt(ByVal ToEncryptText As String, ByVal Sleutel As String) As String MakeKey(Sleutel) Dim EncryptBytes As Byte() = Encoding.Unicode.GetBytes(ToEncryptText) Dim encryptedData As Byte() = Encrypt(EncryptBytes) Return Convert.ToBase64String(encryptedData) End Function #If Compile Then Public Function Encrypt(ByVal ToEncryptData As Byte(), ByVal Sleutel As String) As Byte() MakeKey(Sleutel) Return Encrypt(ToEncryptData) End Function Public Function Encrypt(ByVal fileIn As String, ByVal fileOut As String, _ ByVal Sleutel As String) As Integer ' '' Return: -1 = OK, 0 = read/write Error, 1 = no FileIn, 2 = user cancelled Dim i As Integer = Filetest(fileIn, fileOut) > 0 If i > 0 Then Return i MakeKey(Sleutel) Dim FileStreamIn As New FileStream(fileIn, FileMode.Open, FileAccess.Read) Dim FileStreamOut As New FileStream(fileOut, FileMode.OpenOrCreate, FileAccess.Write) Try algorithm.Key = Key algorithm.IV = IV Dim CryptStream As CryptoStream = New CryptoStream(FileStreamOut, _ algorithm.CreateEncryptor(), CryptoStreamMode.Write) Dim bufferLen As Integer = 4096 Dim buffer As Byte() = New Byte(bufferLen - 1) {} Dim bytesRead As Integer Do bytesRead = FileStreamIn.Read(buffer, 0, bufferLen) CryptStream.Write(buffer, 0, bytesRead) Loop While bytesRead <> 0 CryptStream.Close() CryptStream.Dispose() Return -1 Catch ex As Exception Return 0 Finally FileStreamOut.Close() FileStreamIn.Close() FileStreamOut.Dispose() FileStreamIn.Dispose() End Try End Function #End If #End Region ' Encrypt #Region "Decrypt" Public Function Decrypt(ByVal ToDecryptData As Byte()) Dim decryptedData As Byte() = Encoding.Unicode.GetBytes(Fout) Dim MemStream As New MemoryStream() algorithm.Key = Key algorithm.IV = IV Try Dim CryptStream As CryptoStream = New CryptoStream(MemStream, _ algorithm.CreateDecryptor(), CryptoStreamMode.Write) CryptStream.Write(ToDecryptData, 0, ToDecryptData.Length) CryptStream.Close() decryptedData = MemStream.ToArray() CryptStream.Dispose() Return decryptedData Catch ex As Exception Return decryptedData Finally MemStream.Close() MemStream.Dispose() End Try End Function Public Function Decrypt(ByVal ToDecryptText As String, ByVal Sleutel As String) As String Try MakeKey(Sleutel) Dim ToDecryptBytes As Byte() = Convert.FromBase64String(ToDecryptText) Dim decryptedData As Byte() = Decrypt(ToDecryptBytes) Return Encoding.Unicode.GetString(decryptedData, 0, decryptedData.Length) Catch ex As Exception Return Fout End Try End Function #If Compile Then Public Function Decrypt(ByVal ToDecryptData As Byte(), ByVal Sleutel As String) As Byte() MakeKey(Sleutel) Return Decrypt(ToDecryptData) End Function Public Function Decrypt(ByVal fileIn As String, ByVal fileOut As String, _ ByVal Password As String) As Integer ' '' Return: -1 = OK, 0 = read/write Error, 1 = no FileIn, 2 = user cancelled Dim i As Integer = Filetest(fileIn, fileOut) > 0 If i > 0 Then Return i MakeKey(Password) Dim FileStreamIn As New FileStream(fileIn, FileMode.Open, FileAccess.Read) Dim FileStreamOut As New FileStream(fileOut, FileMode.OpenOrCreate, FileAccess.Write) Try algorithm.Key = Key algorithm.IV = IV Dim CryptStream As New CryptoStream(FileStreamOut, algorithm.CreateDecryptor(), _ CryptoStreamMode.Write) Dim bufferLen As Integer = 4096 Dim buffer As Byte() = New Byte(bufferLen - 1) {} Dim bytesRead As Integer Do bytesRead = FileStreamIn.Read(buffer, 0, bufferLen) CryptStream.Write(buffer, 0, bytesRead) Loop While bytesRead <> 0 CryptStream.Close() CryptStream.Dispose() Return -1 Catch ex As Exception Return 0 Finally FileStreamOut.Close() FileStreamIn.Close() FileStreamOut.Dispose() FileStreamIn.Dispose() End Try End Function #End If #End Region ' Decrypt End Module
frmDbInit
frmDbInit:
Test of er al een NAW draait, of de database aanwezig is, welke DLL moet worden klaargezet.
De Function AppPath() staat in Module Diversen.
Een nogal eenvoudig window
- FormBorderStyle=None
- Startposition=CenterScreen
- Label1.Text="NAW: Init..."
- Button1.Visible=False
- Button1.Text="OK"
Project NAW - frmDbInit.vb
Imports System.Management Public Class frmDbInit Private Const cnstFile = "NAW.s3db" Private Const cnstPath = "\Database\" Private Sub frmDbInit_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Show() Dim apps As Process() = Process.GetProcessesByName("NAW") If apps.Length > 1 Then ' draait al? Me.Label1.Text = "NAW: Already activated" Me.Button1.Visible = True ElseIf Not FileDB() Then ' DB ok ? MsgBox(DbPath & DbFile & " ???", MsgBoxStyle.Critical, "ERROR") End Else ' DLL klaarzetten en Form NAW openen Dim dll As String = "System.Data.SQLite." & Choose(CPU, "x86", "AMD64", "IA64") & ".dll" If IO.File.Exists(AppPath & dll) Then IO.File.Copy(AppPath & dll, "System.Data.SQLite.dll", True) Else MsgBox(AppPath & dll & " ???", MsgBoxStyle.Critical, "ERROR") Close() End If frmNAW.Show() Me.Close() End If End Sub Private Function FileDB() As Boolean ' '' DB-path/file test AppPath = GetAppPath().ToLower.Replace("file:\", "") DbPath = AppPath.Substring(0, AppPath.LastIndexOf("\")) & cnstPath AppPath = AppPath & "\" DbFile = cnstFile If Not IO.File.Exists(DbPath & DbFile) Then Return False ' geen DB ConnectionString = "Data Source=" & DbPath & DbFile Return True End Function Private Function CPU() As Integer ' '' Return: 1=x86, 2=AMD64, 3=IA64 (Intel Itanium) ' '' 32 of 64 bits installatie Dim arch As String = System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") Dim archWOW As String = System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432") Dim installatie As String = "" Dim c As String = GetCpuArch() 'processor If archWOW IsNot Nothing AndAlso archWOW <> "" AndAlso archWOW.Contains("64") OrElse arch.Contains("64") Then installatie = "x64" If c = "x64" Then Return 2 ElseIf c = "Itanium" Then Return 3 End If End If Return 1 End Function Private Function GetCpuArch() As String Dim scope As New ManagementScope() Dim query As New ObjectQuery("SELECT Architecture FROM Win32_Processor") Dim search As New ManagementObjectSearcher(scope, query) Dim results As ManagementObjectCollection = search.[Get]() Dim e As ManagementObjectCollection.ManagementObjectEnumerator = results.GetEnumerator() e.MoveNext() Dim arch As UShort = CUShort(e.Current("Architecture")) Select Case arch Case 0 Return "x86" Case 1 Return "MIPS" Case 2 Return "Alpha" Case 3 Return "PowerPC" Case 6 Return "Itanium" Case 9 Return "x64" Case Else Return "Unknown Architecture (WMI ID " & arch.ToString() & ")" End Select End Function Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click ' '' afbreken Me.Close() End Sub End Class
frmNAW
frmNAW:
Een suggestie als voorbeeld met code om na te doen, maar misschien maak je er liever gelijk iets zinnigs van.
(afbeelding en tekst kan wat meer naar onder staan)
De Cotrol-namen zijn opgebouwd uit 3-letters voor het type control en de bijbehorende teksten/labels.
pnl, lsb, dvg, txb, lbl, btn, chb, rbn, nud
Let op bij rbn's; in Groep Relatie: rbnAllen, rbnFamilie,... in Groep Selecteer op Relatie: rbnSelectAllen, rbnSelectFamilie,.
..
In het rood wat voorbeelden, spaties en vraagteken worden niet meegenomen.
GroupBoxes en, op één na, alle Labels behouden de standaardbenaming.
Anchor gaat heel snel als je het op een selectie toepast, dat scheelt nogal wat klik of schrijfwerk.
Project NAW - frmNAW.vb
Imports System.Drawing Public Class frmNAW ' ''####### voorbeeld met Event uit MODULE 'Private WithEvents BindingSourcesEvents As New BindingSourcesClass 'Private Sub BindingSourceTblPassword_CurrentChanged(ByVal count As Integer) _ ' Handles BindingSourcesEvents.BSPasswordCurrentChanged ' ' ' Event-code hier 'End Sub ' ''###### Private WithEvents DB As NawDB = New NawDB ' BindingSourceTblPassword_CurrentChanged-Event Private RelatieVlag As Integer = 0 ' RadioButtons Selectie-Realtiesoort Private Sub frmBinding_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load Dim i As Integer Me.Size = New Size(660, 397) Me.MinimumSize = New Size(660, 397) Me.MaximumSize = New Size(855, 567) Me.pnlData.Visible = False Me.txbEncrypt.ReadOnly = True Me.txbRealatie.ReadOnly = True Me.txbGeheim.PasswordChar = "*" Me.rbnAllen.Tag = 0 Me.rbnSelectAllen.Tag = 0 Me.rbnFamilie.Tag = 1 Me.rbnSelectFamilie.Tag = 1 Me.rbnVrienden.Tag = 2 Me.rbnSelectVrienden.Tag = 2 Me.rbnZakelijk.Tag = 3 Me.rbnSelectZakelijk.Tag = 3 If Not InitDB() Then MsgBox("Geen tblPassword-record gevonden: EINDE") Me.Close() End If i = DB.InitDB() i = DB.NAWSelectSQL(-1) i = PasswordSelectSQL() Me.LinkLabel1.Text = "www.kendziorra.nl" ' '' Inplaats van onderstaande DataBindingen kun je er ook voor kiezen om de Contols te ' '' vullen/updaten via het BindingSourceTblNAW_CurrentChanged-Event Me.lsbLijst.DataSource = DB.BindingSourceTblNAW ' lijst om snel naar "Naam" zoeken Me.lsbLijst.DisplayMember = "Naam" 'herhaal eertste letter van "Naam" tot het gezocht voor staat Me.dgvGrid.DataSource = DB.BindingSourceTblNAW ' eerst datagridview binden, dan aanpassen ' '' Decrypt-TextBoxColomn voor ontsleutelde Geheim invoegen Dim dataGridViewColumn As New DataGridViewTextBoxColumn() dataGridViewColumn.HeaderText = "Decrypt" dataGridViewColumn.Name = "Decrypt" Me.dgvGrid.Columns.Insert(4, dataGridViewColumn) ' '' Relatie-ComboBoxColomn voor Relatiesoort in tekst Dim dataGridViewComboBoxColumn As New DataGridViewComboBoxColumn dataGridViewComboBoxColumn.HeaderText = "Relatie" dataGridViewComboBoxColumn.Name = "Relatie" dataGridViewComboBoxColumn.Items.AddRange("Allen", "Familie", "Vrienden", "Zakelijk") Me.dgvGrid.Columns.Insert(8, dataGridViewComboBoxColumn) ' '' ReadOnly = True: Edit kan hier via textboxes, anders voor het Updaten ' '' de kolommen "Decrypt"->"Geheim" en "Relatie"->"Relatiesoort" verwerken Me.dgvGrid.ReadOnly = True Me.dgvGrid.Columns(0).AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader Me.dgvGrid.Columns(7).AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader ' '' Textboxes binden Me.txbNaam.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _ "Naam", True)) Me.txbAdres.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _ "Adres", True)) Me.txbPlaats.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _ "Woonplaats", True)) Me.txbEncrypt.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _ "Geheim", True)) ' '' Me.txbGeheim.Text in BindingSourceTblNAW_CurrentChanged-Event Me.txbHomepage.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _ "Homepage", True)) Me.txbRealatie.DataBindings.Add(New Binding("Text", DB.BindingSourceTblNAW, _ "Relatiesoort", True)) ' '' Realatie-RadioButtons in BindingSourceTblNAW_CurrentChanged-Event End Sub Private Sub frmBinding_FormClosing(ByVal sender As Object, _ ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing OpslaanVervers(False) DB.CloseDB() CloseDB() End Sub Private Sub OpslaanVervers(ByVal Ververs As Boolean) Dim i As Integer ' '' Update tabel uit TextBoxes Dim Pos As Integer = DB.BindingSourceTblNAW.Position ' bewaar Position DB.BindingSourceTblNAW.MovePrevious() ' wijzig Position i = DB.AdapterTblNAWUpdate() ' Opslaan If Ververs Then i = DB.NAWSelectSQL(RelatieVlag) ' verversen DB.BindingSourceTblNAW.Position = Pos ' zet Position terug End Sub Public Sub BindingSourceTblNAW_CurrentChanged(ByVal Records) _ Handles DB.BindingSourceTblNAWChanged If Records > 0 Then Me.lblRecNr.Text = (DB.BindingSourceTblNAW.Position + 1) & "/" & Records Me.lblRecNr.Left = 193 - Me.lblRecNr.Width ' in r-bovenhoek van lijst houden Me.rbnAllen.Checked = False Me.rbnFamilie.Checked = False Me.rbnVrienden.Checked = False Me.rbnZakelijk.Checked = False Select Case DB.RowTblNAW("Relatiesoort") Case 0 : Me.rbnAllen.Checked = True Case 1 : Me.rbnFamilie.Checked = True Case 2 : Me.rbnVrienden.Checked = True Case 3 : Me.rbnZakelijk.Checked = True End Select If DB.RowTblNAW("Geheim").ToString.Length Then Me.txbGeheim.Text = Decrypt(DB.RowTblNAW("Geheim"), w4(RowTblPassword("Subkey"))) Else Me.txbGeheim.Text = "" End If End If End Sub Private Sub txbHomepage_DragEnter(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) Handles txbHomepage.DragEnter If (e.Data.GetDataPresent(DataFormats.FileDrop)) Then e.Effect = DragDropEffects.Link Else e.Effect = DragDropEffects.None End If End Sub Private Sub txbHomepage_DragDrop(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) Handles txbHomepage.DragDrop ' '' Zowel een applicatie als een url kan hier worden ingesleept ' '' URL of EXE is met dubbelklik te openen Me.txbHomepage.Text = e.Data.GetData(DataFormats.FileDrop)(0) End Sub Private Sub txbHomepage_DoubleClick(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles txbHomepage.DoubleClick Try Dim Link As String = Me.txbHomepage.Text If Link.IndexOf("/") <> -1 AndAlso Link.IndexOf("http://", 0) = -1 Then _ Link = "http://" & Link ' Is het een url? System.Diagnostics.Process.Start(Link) Catch ex As Exception End Try End Sub Private Sub textbox_KeyPress(ByVal sender As Object, _ ByVal e As System.Windows.Forms.KeyPressEventArgs) _ Handles txbWachtwoord.KeyPress, txbNaam.KeyPress, txbAdres.KeyPress, _ txbPlaats.KeyPress, txbGeheim.KeyPress, txbHomepage.KeyPress, _ txbNieuwWW.KeyPress, txbHerhaalWW.KeyPress ' '' Test op toegestane tekens Dim i As Boolean = (Lettertekens & Chr(8)).IndexOf(e.KeyChar) >= 0 If i Then Exit Sub e.KeyChar = Nothing Beep() End Sub Private Sub textbox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles txbWachtwoord.TextChanged, txbNaam.TextChanged, txbNieuwWW.TextChanged, _ txbHerhaalWW.TextChanged ' '' Minimale lengte = 4 ' '' CType() tegen Late Binding Error in Mobile If CType(sender, TextBox).Text.Length AndAlso CType(sender, TextBox).Text.Length < 4 Then CType(sender, TextBox).BackColor = Color.OrangeRed Else CType(sender, TextBox).BackColor = Color.White End If If CType(sender, TextBox).Name = "txbNieuwWW" Then Me.nudTekensWW.Value = _ Me.txbNieuwWW.Text.Length End Sub Private Sub btnWachtwoord_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnWachtwoord.Click If Me.btnWachtwoord.Text = "OK" Then If Me.txbWachtwoord.Text.Length < 4 Then Exit Sub w1 = Encrypt(Me.txbWachtwoord.Text, w2) ' bewaar wachtwoord verstopt If PasswordOk(RowTblPassword("Password"), Me.txbWachtwoord.Text) Then Me.pnlData.Visible = True Me.txbWachtwoord.Enabled = False Me.btnWachtwoord.Text = "Bescherm" End If Else Me.pnlData.Visible = False Me.txbWachtwoord.Enabled = True Me.btnWachtwoord.Text = "OK" End If Me.txbWachtwoord.Text = "" End Sub Private Sub btnGenereerWW_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Me.txbNieuwWW.Text = GenerateStrongPW(nudTekensWW.Value) Me.txbHerhaalWW.Text = Me.txbNieuwWW.Text() End Sub Private Sub btnNieuwRec_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnNieuwRec.Click DB.BindingSourceTblNAW.AddNew() End Sub Private Sub btnWisRec_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnWisRec.Click If MsgBox("Naam: " & DB.RowTblNAW("Naam"), MsgBoxStyle.Exclamation Or _ MsgBoxStyle.OkCancel, "RECORD WISSEN") = MsgBoxResult.Ok Then _ DB.BindingSourceTblNAW.Remove(DB.BindingSourceTblNAW.Current) End Sub Private Sub btnOpslaanVerversenRec_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnOpslaan.Click, btnVervers.Click If Me.txbGeheim.Text.Length Then Me.txbEncrypt.Text = Encrypt(Me.txbGeheim.Text, w4(RowTblPassword("Subkey"))) Else Me.txbGeheim.Text = "" Me.txbEncrypt.Text = "" End If OpslaanVervers(True) End Sub Private Sub btnCompactDB_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCompactDB.Click MsgBox("-" & CompactDB() & " KB", MsgBoxStyle.Information, "Compact DB") End Sub Private Sub rbnSelectRelatie_CheckedChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles rbnSelectAllen.CheckedChanged, _ rbnSelectFamilie.CheckedChanged, rbnSelectVrienden.CheckedChanged, _ rbnSelectZakelijk.CheckedChanged ' '' de RelatieVlag bepaald welke records er worden geselecteerd If Not Me.CanFocus Then Exit Sub ' eerst Form opmaken, daarna is DB pas beschikbaar ' '' CType() tegen Late Binding Error in Mobile RelatieVlag = CType(sender, RadioButton).Tag Dim i As Integer = DB.NAWSelectSQL(RelatieVlag) End Sub Private Sub rbnRelatie_CheckedChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles rbnAllen.CheckedChanged, _ rbnFamilie.CheckedChanged, rbnVrienden.CheckedChanged, rbnZakelijk.CheckedChanged ' '' CType() tegen Late Binding Error in Mobile ' '' Plaats de waarden 0 t/m 3 in het Tag-propertie van de betreffende RadioButtons Me.txbRealatie.Text = CType(sender, RadioButton).Tag End Sub Private Sub chbToonGeheim_CheckedChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles chbToonGeheim.CheckedChanged If Me.chbToonGeheim.Checked Then Me.txbGeheim.PasswordChar = "" Else Me.txbGeheim.PasswordChar = "*" End If dgvGrid.Refresh() End Sub Private Sub chbToonWW_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles chbToonWW.CheckedChanged If Me.chbToonWW.Checked Then Me.txbNieuwWW.PasswordChar = "" Else Me.txbNieuwWW.PasswordChar = "*" End If Me.txbHerhaalWW.PasswordChar = Me.txbNieuwWW.PasswordChar End Sub Private Sub btnOpslaanWW_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnOpslaanWW.Click ' '' Test nieuw wachtwoord ' '' Decrypt SubKey met oude WW en Encrypt het met nieuw WW ' '' Sla WW op If Me.txbNieuwWW.Text.Length < 4 Then Exit Sub If Me.txbNieuwWW.Text <> Me.txbHerhaalWW.Text Then MsgBox("Ongelijk", MsgBoxStyle.Information) Exit Sub End If MsgBox("Wachtwoord: " & Me.txbNieuwWW.Text & vbCrLf & _ "Noteer wachtwoord en berg het veilig op!", MsgBoxStyle.Exclamation) Dim SubKeyDecrypt As String = w4(RowTblPassword("Subkey")) ' ontsleutel SubKey Dim SubKeyEncrypt As String = Encrypt(SubKeyDecrypt, Me.txbNieuwWW.Text) ' versleutel SubKey Dim PasswordEncrypt As String = Encrypt(Me.txbNieuwWW.Text, Me.txbNieuwWW.Text) If PasswordUpdate(RowTblPassword("ID"), PasswordEncrypt, SubKeyEncrypt) Then AdapterTblPasswordUpdate() ' gelijk in DB opslaan w1 = Encrypt(Me.txbNieuwWW.Text, w2) ' bewaar wachtwoord als w1 versleuteld in geheugen Else MsgBox("Wachtwoor en SubKey opslaan is mislukt!", MsgBoxStyle.Critical) End If Me.txbNieuwWW.Text = "" Me.txbHerhaalWW.Text = "" Me.chbToonWW.Checked = False End Sub Private Sub btnGenereerWW_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnGenereerWW.Click Me.txbNieuwWW.Text = GenerateStrongPW(Me.nudTekensWW.Value) Me.txbHerhaalWW.Text = Me.txbNieuwWW.Text End Sub Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, _ ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) _ Handles LinkLabel1.LinkClicked System.Diagnostics.Process.Start("http://www.kendziorra.nl") End Sub Private Sub dgvGrid_CellFormatting(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) _ Handles dgvGrid.CellFormatting If e.Value Is Nothing Then Exit Sub Select Case e.ColumnIndex Case 5 If Me.dgvGrid("Geheim", e.RowIndex).Value.length Then Me.dgvGrid("Decrypt", e.RowIndex).Value = Decrypt(Me.dgvGrid("Geheim", _ e.RowIndex).Value, w4(RowTblPassword("Subkey"))) If Not Me.chbToonGeheim.Checked Then Me.dgvGrid("Decrypt", e.RowIndex).Value = _ New String("*"c, Me.dgvGrid("Decrypt", e.RowIndex).Value.Length) End If Case 8 Me.dgvGrid("Relatie", e.RowIndex).Value = _ Choose(e.Value + 1, "Allen", "Familie", "Vrienden", "Zakelijk") End Select End Sub End Class
NAW.exe
NAW.exe:
Nog even wat voorbeelden van de on/mogelijkheden van NAW. Onmogelijkheden om dat dit een totaal onzinnige toepassing is. Mogelijkheden omdat er tal van kleinigheidjes in verwerkt zijn welke in andere toepassingen misschien wel van pas kunnen komen. Bij afsluiten wordt eerst de DB bijgewerkt.
(afbeelding en tekst kan wat meer naar onder staan)
Klik in lijst en type het eerste teken van de gezochte naam, herhaald dit tot de gezochte naam is geselecteerd. Alle er bij behorende velden worden direct aan de selectie aangepast. Klik op knop Bescherm en het venster is weer in de begintoestand.
Met Nieuw rec. een leeg record toegevoegd, mijn gegevens, website, geheim en relatietype ingegeven en op Opslaan geklikt.
Zoeken doe je via de ListBox met een Klik en het (herhaald) ingeven van het eerste letterteken. Bewerken in TextBoxes en Realatie RadioButton, opslaan met de knop Opslaan. Zonder Opslaan wordt het geheim niet (opnieuw)versleuteld en alleen de oude inhoud van Encrypt in dataveld-Geheim opgeslagen. Opslaan werkt niet alleen lokaal maar update ook de DB. Bewerken zou ook in het DataViewGrid kunnen gebeuren, maar dan moet er extra code komen om het grid-veld Decrypt versleuteld in het dataveld-Geheim te plaatsen. Zo ook bij de Grid-ComboBoxes.
Ontsluierde geheimen.
SQL-Select op relatie past alles in één klik aan.
Dit is dan het einde, hopelijk heb je er wat aan!