2.10.4.0 - Refactor: remove license mgmt, add password crypto class

Replaced all license management classes (ClassLicense, ClassLicenses, ClassLicenseManager) with a new ClassPasswordCrypto for password encryption/decryption using Rijndael (AES). Updated all usages to call EncodePassword/DecodePassword instead of license key methods. Removed obsolete license-related code and files from the project. Incremented assembly version to 2.10.4.0. Cleaned up imports and updated the project file to reflect these changes. No license logic remains; only password crypto is handled.
This commit is contained in:
OlgunR
2026-05-07 13:21:06 +02:00
parent de30e3198b
commit 2a4de5ddf8
9 changed files with 34 additions and 414 deletions

View File

@@ -1,7 +1,7 @@
Imports System.DirectoryServices Imports System.DirectoryServices
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
Public Class ClassActiveDirectory Public Class ClassActiveDirectory
Public Shared licenseManager As ClassLicenseManager = Nothing Public Shared passwordCrypto As ClassPasswordCrypto = Nothing
Public Shared ErgebnisAD As String() Public Shared ErgebnisAD As String()
Private Shared _Logger As DigitalData.Modules.Logging.Logger Private Shared _Logger As DigitalData.Modules.Logging.Logger
Public Shared Function Test_Connect(SEARCH_Filter As String, Property2Load As String, Domain As String, User As String, PW As String) Public Shared Function Test_Connect(SEARCH_Filter As String, Property2Load As String, Domain As String, User As String, PW As String)
@@ -95,8 +95,8 @@ Public Class ClassActiveDirectory
End If End If
licenseManager = New ClassLicenseManager("#DigitalData9731258!#") passwordCrypto = New ClassPasswordCrypto("#DigitalData9731258!#")
Dim PWDecode As String = licenseManager.DecodeLicenseKey(PW) Dim PWDecode As String = passwordCrypto.DecodePassword(PW)
Dim objDirectoryEntry As DirectoryEntry = New DirectoryEntry(Domain) Dim objDirectoryEntry As DirectoryEntry = New DirectoryEntry(Domain)
If PW <> String.Empty And User <> String.Empty Then If PW <> String.Empty And User <> String.Empty Then
objDirectoryEntry.Username = User objDirectoryEntry.Username = User

View File

@@ -1,104 +0,0 @@
Public Class ClassLicense
Private _modulename As String
Private _expires As Date
Private _Typ As String
Private _anzProf As String
' ++++++++++++++++++++++++++++++++++++++++++++++ Methoden ++++++++++++++++++++++++++++++++++++++++++++++
''' <summary>
''' Konstruktor der Lizenz
''' </summary>
''' <param name="modulename">Name des Moduls</param>
''' <param name="expires">Gültigkeitsdatum der Lizenz</param>
''' <remarks></remarks>
Sub New(ByVal modulename As String, ByVal expires As Date, ByVal _type As String, ByVal _anzprofile As String)
Me._modulename = modulename
Me._expires = expires
Me._Typ = _type
Me._anzProf = _anzprofile
End Sub
' ++++++++++++++++++++++++++++++++++++++++++++++ Properties ++++++++++++++++++++++++++++++++++++++++++++++
''' <summary>
''' Liefert oder setzt den Namen des Moduls für diese Lizenz
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Modulename() As String
Get
Return Me._modulename
End Get
Set(ByVal value As String)
Me._modulename = value
End Set
End Property
''' <summary>
''' Liefert oder setzt das Gültigkeitsdatum der Lizenz für das Modul
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Expires() As Date
Get
Return Me._expires
End Get
Set(ByVal value As Date)
Me._expires = value
End Set
End Property
''' <summary>
''' Liefert ob die Lizenz schon abgelaufen ist
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property IsExpired()
Get
If Date.Today > Me._expires Then
Return True
Else
Return False
End If
End Get
End Property
''' <summary>
''' Liefert den Typend er Lizenz
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Type() As String
Get
Return Me._Typ
End Get
Set(ByVal value As String)
Me._Typ = value
End Set
End Property
''' <summary>
''' Liefert die Anzahl der Profile
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Anz_Profile() As String
Get
Return Me._anzProf
End Get
Set(ByVal value As String)
Me._anzProf = value
End Set
End Property
End Class

View File

@@ -1,149 +0,0 @@
Public Class ClassLicenses
Private _licenses() As ClassLicense
Private _machine As String
Private _company As String
Private _WDLizenz As String
' ++++++++++++++++++++++++++++++++++++++++++++++ Methoden ++++++++++++++++++++++++++++++++++++++++++++++
''' <summary>
''' Konstruktor für die Lizenzen-Sammlung
''' </summary>
''' <param name="licenseStringArray">In Array übertragene Lizenzinformationen</param>
''' <remarks></remarks>
Sub New(ByVal licenseStringArray(,) As String)
Try
If licenseStringArray IsNot Nothing Then
Dim license1() As String = licenseStringArray(0, 1).Split("#")
If license1.Length > 1 Then
Me._machine = license1(1)
Else
Me._machine = "all"
End If
Me._company = license1(0) 'licenseStringArray(0, 1)
frmStart._company = Me._company
Dim i As Integer
For i = 1 To licenseStringArray.GetLength(0) - 2 ' minus 2, weil GetLength nicht null-basiert ist und das erste Element Firma ist
Dim _date As Date
Dim anzprof As String = licenseStringArray(i, 3)
If anzprof.ToLower = "unlimited" Then
anzprof = 99
End If
Try
_date = CDate(licenseStringArray(i, 1))
Catch ex As Exception
If licenseStringArray(i, 1).ToString.EndsWith("2099") Then
_date = "2099-12-31"
Else
MsgBox(ex.Message & vbNewLine & Environment.OSVersion.ToString, MsgBoxStyle.Critical)
End If
End Try
Me.Add(licenseStringArray(i, 0), _date, licenseStringArray(i, 2), anzprof)
Next
End If
Catch ex As Exception
MsgBox("Fehler bei Auslesen der Licenses: " & vbNewLine & ex.Message, MsgBoxStyle.Critical)
End Try
End Sub
''' <summary>
''' Fügt der Lizenz-Sammlung eine Lizenz hinzu
''' </summary>
''' <param name="modulename">Name des Moduls, für das eine Lizenz angelegt werden soll</param>
''' <param name="expires">Datum der Gültigkeit der Lizenz</param>
''' <remarks></remarks>
Public Sub Add(ByVal modulename As String, ByVal expires As Date, ByVal type As String, ByVal anzprof As String)
If Me._licenses IsNot Nothing Then
ReDim Preserve Me._licenses(Me._licenses.Length)
Else
ReDim Preserve Me._licenses(0)
End If
Me._licenses(Me._licenses.Length - 1) = New ClassLicense(modulename, expires, type, anzprof)
End Sub
''' <summary>
''' Liefert eine Lizenz an Hand des Modulnamens
''' </summary>
''' <param name="modulename">Name des zu suchenden Moduls</param>
''' <returns>liefert ein Lizenzobjekt</returns>
''' <remarks></remarks>
Public Function GetLicense(ByVal modulename As String) As ClassLicense
If Me._licenses IsNot Nothing Then
For Each license As ClassLicense In Me._licenses
If license.Modulename = modulename Then
Return license
End If
Next
End If
Return Nothing
End Function
' ++++++++++++++++++++++++++++++++++++++++++++++ Properties ++++++++++++++++++++++++++++++++++++++++++++++
''' <summary>
''' liefert eine Sammlung von Lizenzobjekten
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property Licenses() As ClassLicense()
Get
Return Me._licenses
End Get
End Property
''' <summary>
''' liefert eine Lizenz an Hand des Modulnamens
''' </summary>
''' <param name="modulename">Name des zu suchenden Moduls</param>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property License(ByVal modulename As String) As ClassLicense
Get
Return Me.GetLicense(modulename)
End Get
End Property
''' <summary>
''' Liefert oder setzt den Firmennamen des Lizenzeigentümers
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Company() As String
Get
Return Me._company
End Get
Set(ByVal value As String)
Me._company = value
End Set
End Property
Public Property machine() As String
Get
Return Me._machine
End Get
Set(ByVal value As String)
Me._machine = value
End Set
End Property
End Class

View File

@@ -1,34 +1,26 @@
Imports System.Text Imports System.Security.Cryptography
Imports System.Security.Cryptography Imports System.Text
Imports System.Collections.ObjectModel
Public Class ClassLicenseManager Public Class ClassPasswordCrypto
Private _password As String Private _password As String
Private _key As String
Public Shared _licenses As ClassLicenses
Public licenseString As String ' ++++++++++++++++++++++++++++++++++++++++++++++ Properties ++++++++++++++++++++++++++++++++++++++++++++++
Public licenseStringArray(,) As String
''' <summary>
''' Liefert das Passwort zum Entschlüsseln des Lizenzschlüssels
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property Password() As String
Get
Return Me._password
End Get
End Property
' ++++++++++++++++++++++++++++++++++++++++++++++ Methoden ++++++++++++++++++++++++++++++++++++++++++++++ ' ++++++++++++++++++++++++++++++++++++++++++++++ Methoden ++++++++++++++++++++++++++++++++++++++++++++++
''' <summary>
''' Konstruktor für den Lizenz-Manager
''' </summary>
''' <param name="password">Passwort zum Entschlüsseln des Lizenzkeys</param>
''' <param name="key">verschlüsselter Lizenzkey</param>
''' <remarks></remarks>
Sub New(ByVal password As String, ByVal key As String)
Me._password = password
Me._key = key
Me.licenseString = Me.DecodeLicenseKey(Me._key)
Me.licenseStringArray = Me.SplitLicenseString(Me.licenseString)
Me.LoadLicenses()
End Sub
''' <summary> ''' <summary>
''' Konstruktor für den Lizenz-Manager ohne License load ''' Konstruktor für den Lizenz-Manager ohne License load
''' </summary> ''' </summary>
@@ -37,14 +29,6 @@ Public Class ClassLicenseManager
Sub New(ByVal password As String) Sub New(ByVal password As String)
Me._password = password Me._password = password
End Sub End Sub
''' <summary>
''' Lädt alle Lizenzen aus dem Lizenz-Array
''' </summary>
''' <remarks></remarks>
Public Sub LoadLicenses()
ClassLicenseManager._licenses = New ClassLicenses(Me.licenseStringArray)
End Sub
''' <summary> ''' <summary>
''' Codiert eine Zeichenkette ''' Codiert eine Zeichenkette
@@ -53,7 +37,7 @@ Public Class ClassLicenseManager
''' <param name="password">das zur Verschlüsselung verwendete Passwort</param> ''' <param name="password">das zur Verschlüsselung verwendete Passwort</param>
''' <returns>liefert eine verschlüsselte Zeichenkette</returns> ''' <returns>liefert eine verschlüsselte Zeichenkette</returns>
''' <remarks></remarks> ''' <remarks></remarks>
Public Function EncodeLicenseKey(ByVal str As String, ByVal password As String) Public Function EncodePassword(ByVal str As String, ByVal password As String)
Dim rd As New RijndaelManaged Dim rd As New RijndaelManaged
Dim md5 As New MD5CryptoServiceProvider Dim md5 As New MD5CryptoServiceProvider
@@ -69,7 +53,7 @@ Public Class ClassLicenseManager
ms.Write(iv, 0, iv.Length) ms.Write(iv, 0, iv.Length)
Dim cs As New CryptoStream(ms, rd.CreateEncryptor, CryptoStreamMode.Write) Dim cs As New CryptoStream(ms, rd.CreateEncryptor, CryptoStreamMode.Write)
Dim data() As Byte = System.Text.Encoding.UTF8.GetBytes(Str) Dim data() As Byte = System.Text.Encoding.UTF8.GetBytes(str)
cs.Write(data, 0, data.Length) cs.Write(data, 0, data.Length)
cs.FlushFinalBlock() cs.FlushFinalBlock()
@@ -82,14 +66,13 @@ Public Class ClassLicenseManager
Return result Return result
End Function End Function
''' <summary> ''' <summary>
''' Decodiert den verschlüsselten Lizenzkey ''' Decodiert den verschlüsselten Lizenzkey
''' </summary> ''' </summary>
''' <param name="licenseCodeStr">verschlüsselter Lizenzkey</param> ''' <param name="licenseCodeStr">verschlüsselter Lizenzkey</param>
''' <returns></returns> ''' <returns></returns>
''' <remarks></remarks> ''' <remarks></remarks>
Public Function DecodeLicenseKey(ByVal licenseCodeStr As String) Public Function DecodePassword(ByVal licenseCodeStr As String)
Try Try
Dim rd As New RijndaelManaged Dim rd As New RijndaelManaged
Dim rijndaelIvLength As Integer = 16 Dim rijndaelIvLength As Integer = 16
@@ -121,7 +104,6 @@ Public Class ClassLicenseManager
Dim i As Integer = 0 Dim i As Integer = 0
Try Try
i = cs.Read(data, 0, data.Length) i = cs.Read(data, 0, data.Length)
@@ -143,95 +125,4 @@ Public Class ClassLicenseManager
Return Nothing Return Nothing
End Function End Function
''' <summary>
''' Zerlegt den entschlüsselten Lizenzkey
''' </summary>
''' <param name="licenseStr">entschlüsselter Lizenzkey</param>
''' <returns></returns>
''' <remarks></remarks>
Public Function SplitLicenseString(ByVal licenseStr As String) As String(,)
Try
If licenseStr IsNot Nothing Then
Dim licenseTemp() As String = licenseStr.Split(";")
Dim licenses(licenseTemp.Length, 3) As String
Dim i As Integer = 0
If licenseTemp IsNot Nothing Then
For Each lizenz As String In licenseTemp
Dim temp() = lizenz.Split(":")
licenses(i, 0) = temp(0)
licenses(i, 1) = temp(1)
If temp.Length > 2 Then
licenses(i, 2) = temp(2)
licenses(i, 3) = temp(3)
Dim expires As Date
Date.TryParse(licenses(i, 1), expires)
End If
i += 1
Next
Return licenses
End If
End If
Catch ex As Exception
MsgBox("Fehler in SplitLicenseString: " & vbNewLine & ex.Message, MsgBoxStyle.Critical)
End Try
Return Nothing
End Function
' ++++++++++++++++++++++++++++++++++++++++++++++ Properties ++++++++++++++++++++++++++++++++++++++++++++++
''' <summary>
''' Liefert das Passwort zum Entschlüsseln des Lizenzschlüssels
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property Password() As String
Get
Return Me._password
End Get
End Property
''' <summary>
''' Liefert eine Sammlung von Lizenzobjekten
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property Licenses() As ClassLicenses
Get
Return ClassLicenseManager._licenses
End Get
End Property
''' <summary>
''' Liefert oder setzt den Lizenzschlüssel
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Key() As String
Get
Return Me._key
End Get
Set(ByVal value As String)
Me._key = value
End Set
End Property
End Class End Class

View File

@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben: ' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")> ' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("2.10.3.0")> <Assembly: AssemblyVersion("2.10.4.0")>
<Assembly: AssemblyFileVersion("2.9.9.0")> <Assembly: AssemblyFileVersion("2.9.9.0")>

View File

@@ -191,9 +191,7 @@
<Compile Include="ClassDIRegel.vb" /> <Compile Include="ClassDIRegel.vb" />
<Compile Include="ClassDIRegeln.vb" /> <Compile Include="ClassDIRegeln.vb" />
<Compile Include="ClassLDAP.vb" /> <Compile Include="ClassLDAP.vb" />
<Compile Include="ClassLicense.vb" /> <Compile Include="ClassPasswordCrypto.vb" />
<Compile Include="ClassLicenseManager.vb" />
<Compile Include="ClassLicenses.vb" />
<Compile Include="ClassLoggerDI.vb" /> <Compile Include="ClassLoggerDI.vb" />
<Compile Include="ClassLoggerService.vb" /> <Compile Include="ClassLoggerService.vb" />
<Compile Include="ClassMI_Profile.vb" /> <Compile Include="ClassMI_Profile.vb" />

View File

@@ -15,7 +15,7 @@ Public Class frmNIProfileigenschaften
' verhindert (wenn True) das _selectedProfile auf Nothing gesetzt wird, wenn das Panel auf visible = True gesetzt wird ' verhindert (wenn True) das _selectedProfile auf Nothing gesetzt wird, wenn das Panel auf visible = True gesetzt wird
Private _flagIgnoreVisibilityChanged As Boolean = False Private _flagIgnoreVisibilityChanged As Boolean = False
Private Shared _Instance As frmNIProfileigenschaften = Nothing Private Shared _Instance As frmNIProfileigenschaften = Nothing
Private licenseManager As ClassLicenseManager = Nothing Private passwordCrypto As ClassPasswordCrypto = Nothing
Private INDEX_LIST As New List(Of String) Private INDEX_LIST As New List(Of String)
Private selectedProfile As ClassNIProfil Private selectedProfile As ClassNIProfil
Public Shared Function Instance() As frmNIProfileigenschaften Public Shared Function Instance() As frmNIProfileigenschaften
@@ -435,8 +435,8 @@ Public Class frmNIProfileigenschaften
If _selectedProfile.Password <> "" And _selectedProfile.UserId <> "" Then If _selectedProfile.Password <> "" And _selectedProfile.UserId <> "" Then
Me.chkbxUserIdent.Checked = False Me.chkbxUserIdent.Checked = False
Me.txtLDAP_User.Text = _selectedProfile.UserId Me.txtLDAP_User.Text = _selectedProfile.UserId
licenseManager = New ClassLicenseManager("#DigitalData9731258!#") passwordCrypto = New ClassPasswordCrypto("#DigitalData9731258!#")
Dim PWDecode As String = licenseManager.DecodeLicenseKey(_selectedProfile.Password) Dim PWDecode As String = passwordCrypto.DecodePassword(_selectedProfile.Password)
Me.txtLDAP_PW.Text = PWDecode Me.txtLDAP_PW.Text = PWDecode
Else Else
Me.chkbxUserIdent.Checked = True Me.chkbxUserIdent.Checked = True
@@ -1158,8 +1158,8 @@ Public Class frmNIProfileigenschaften
Private Sub txtLDAP_PW_TextChanged(sender As Object, e As EventArgs) Handles txtLDAP_PW.TextChanged Private Sub txtLDAP_PW_TextChanged(sender As Object, e As EventArgs) Handles txtLDAP_PW.TextChanged
If Me._selectedProfile IsNot Nothing Then If Me._selectedProfile IsNot Nothing Then
licenseManager = New ClassLicenseManager("#DigitalData9731258!#") passwordCrypto = New ClassPasswordCrypto("#DigitalData9731258!#")
Dim encodePW As String = licenseManager.EncodeLicenseKey(txtLDAP_PW.Text, "#DigitalData9731258!#") Dim encodePW As String = passwordCrypto.EncodePassword(txtLDAP_PW.Text, "#DigitalData9731258!#")
Me._selectedProfile.Password = encodePW Me._selectedProfile.Password = encodePW
If Not Me._selectedProfile.Password = Me._selectedProfile.OriginalPassword Then If Not Me._selectedProfile.Password = Me._selectedProfile.OriginalPassword Then
Me.btnSpeichern.Enabled = True Me.btnSpeichern.Enabled = True

View File

@@ -4,7 +4,7 @@ Public Class frmNIProfilhinzufuegen
Private _oDokumentTypen As WINDREAMLib.WMObjects Private _oDokumentTypen As WINDREAMLib.WMObjects
Public Shared _windream As ClassWindream_allgemein Public Shared _windream As ClassWindream_allgemein
Private Shared _Instance As frmNIProfilhinzufuegen = Nothing Private Shared _Instance As frmNIProfilhinzufuegen = Nothing
Private licenseManager As ClassLicenseManager = Nothing Private passwordCrypto As ClassPasswordCrypto = Nothing
Public Shared Function Instance() As frmNIProfilhinzufuegen Public Shared Function Instance() As frmNIProfilhinzufuegen
@@ -138,8 +138,8 @@ Public Class frmNIProfilhinzufuegen
' Nachindexierung über AD ' Nachindexierung über AD
If Me.txtProfilname.Text <> "" And Me.cmbObjektTypen.SelectedIndex <> -1 And Me.txtWindreamSuche.Text <> "" Then If Me.txtProfilname.Text <> "" And Me.cmbObjektTypen.SelectedIndex <> -1 And Me.txtWindreamSuche.Text <> "" Then
If chkbxUserIdent.Checked = False And txtLDAP_Domaene.Text <> "" And txtLDAP_PW.Text <> "" And txtLDAP_User.Text <> "" Then If chkbxUserIdent.Checked = False And txtLDAP_Domaene.Text <> "" And txtLDAP_PW.Text <> "" And txtLDAP_User.Text <> "" Then
Me.licenseManager = New ClassLicenseManager("#DigitalData9731258!#") Me.passwordCrypto = New ClassPasswordCrypto("#DigitalData9731258!#")
Dim key As String = licenseManager.EncodeLicenseKey(txtLDAP_PW.Text, "#DigitalData9731258!#") Dim key As String = passwordCrypto.EncodePassword(txtLDAP_PW.Text, "#DigitalData9731258!#")
' das Profil hinzufügen - AD MIT AUTH ' das Profil hinzufügen - AD MIT AUTH
ClassNIProfile.Add(Me.txtProfilname.Text, Me.cmbObjektTypen.SelectedItem, Me.txtWindreamSuche.Text, "activedirectory", "", "", txtLDAP_Domaene.Text, txtLDAP_User.Text, key, "", Me.cmbIndexValidierung.Text, "", 0, Me.chkbxGetOrdnerRechte.Checked, Me.cmbOrdnertyp.Text) ClassNIProfile.Add(Me.txtProfilname.Text, Me.cmbObjektTypen.SelectedItem, Me.txtWindreamSuche.Text, "activedirectory", "", "", txtLDAP_Domaene.Text, txtLDAP_User.Text, key, "", Me.cmbIndexValidierung.Text, "", 0, Me.chkbxGetOrdnerRechte.Checked, Me.cmbOrdnertyp.Text)
' und das Formular schließen ' und das Formular schließen

View File

@@ -1,27 +1,11 @@
Imports System.Collections.ObjectModel Imports System.IO
Imports System.Reflection
Imports System.Globalization
Imports DigitalData.Modules.Logging
Imports System.IO
Imports DigitalData.Modules.Database
Imports System.Text.RegularExpressions Imports System.Text.RegularExpressions
Imports System.ComponentModel Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Public Class frmStart Public Class frmStart
Private _MyLogger As LogConfig Private _MyLogger As LogConfig
Private Shared _Logger As DigitalData.Modules.Logging.Logger Private Shared _Logger As DigitalData.Modules.Logging.Logger
Public _company As String
' Dim timediff As Integer = 0
'Private Sub timUhrzeit_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timUhrzeit.Tick
' ' der Statusuhr die aktuelle Systemzeit zuweisen
' Me.Status_Clock.Text = CType(My.Computer.Clock.LocalTime, String)
' timediff += 1000
' If timediff >= 86400000 Then
' 'LogDateien-löschen
' Delete_LogFiles()
' End If
'End Sub
' CREATE INSTANCE ' CREATE INSTANCE
Private Shared _Instance As frmStart = Nothing Private Shared _Instance As frmStart = Nothing