Option Explicit On Imports System.IO Imports System.Runtime.InteropServices Imports DevExpress.XtraSplashScreen Imports DigitalData.GUIs.ClipboardWatcher Imports DigitalData.GUIs.ZooFlow.ClassConstants Imports DigitalData.GUIs.ZooFlow.ClipboardWatcher Imports DigitalData.Modules Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Language.Utils Imports DigitalData.Modules.Windows Imports DigitalData.Modules.ZooFlow Imports DigitalData.GUIs.Common.Base Imports DigitalData.GUIs.Common Imports DigitalData.Modules.Language Imports DevExpress.LookAndFeel Imports System.Threading.Tasks Imports System.Threading Imports DigitalData.Controls.MessageBoxEx Public Class frmFlowForm #Region "Sidebar DllImport" Private Shared Function SHAppBarMessage(ByVal dwMessage As Integer, ByRef BarrData As AppDeskBar) As Integer End Function Public Shared Function RegisterWindowMessage(ByVal msg As String) As Integer End Function #End Region #Region "Sidebar Variablen" Private AppDeskData As AppDeskBar Private fBarRegistered As Boolean = False Private Property uCallBack As Integer Private Structure RECT Public left As Integer Public top As Integer Public right As Integer Public bottom As Integer End Structure Private Structure AppDeskBar Public cbSize As Integer Public hWnd As IntPtr Public uCallbackMessage As Integer Public uEdge As Integer Public rc As RECT Public lParam As IntPtr End Structure Private Enum ABMsg ABM_NEW = 0 ABM_REMOVE = 1 ABM_QUERYPOS = 2 ABM_SETPOS = 3 ABM_GETSTATE = 4 ABM_GETTASKBARPOS = 5 ABM_ACTIVATE = 6 ABM_GETAUTOHIDEBAR = 7 ABM_SETAUTOHIDEBAR = 8 ABM_WINDOWPOSCHANGED = 9 ABM_SETSTATE = 10 End Enum Public Enum ABEdge ABE_LEFT = 0 ABE_TOP ABE_RIGHT ABE_BOTTOM End Enum Private Enum ABNotify ABN_STATECHANGE = 0 ABN_POSCHANGED ABN_FULLSCREENAPP ABN_WINDOWARRANGE End Enum #End Region #Region "Sidebar Enum Properties Register" Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) Try If m.Msg = uCallBack Then Select Case m.WParam.ToInt32() Case CInt(ABNotify.ABN_POSCHANGED) ABSetPos(ABEdge.ABE_RIGHT) End Select End If MyBase.WndProc(m) Catch ex As Exception End Try End Sub Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams Get Dim cp As CreateParams = MyBase.CreateParams cp.Style = cp.Style And Not &HC00000 ' WS_CAPTION cp.Style = cp.Style And Not &H800000 ' WS_BORDER cp.ExStyle = &H80 Or &H8 ' WS_EX_TOOLWINDOW | WS_EX_TOPMOST Return cp End Get End Property Private Sub ABSetPos(ByVal dockEdge As ABEdge) Dim abd As New AppDeskBar() abd.cbSize = Marshal.SizeOf(abd) abd.hWnd = Me.Handle abd.uEdge = CInt(dockEdge) If abd.uEdge = CInt(ABEdge.ABE_LEFT) Or abd.uEdge = CInt(ABEdge.ABE_RIGHT) Then abd.rc.top = 0 abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height If abd.uEdge = CInt(ABEdge.ABE_LEFT) Then abd.rc.left = 0 abd.rc.right = Size.Width Else abd.rc.right = SystemInformation.PrimaryMonitorSize.Width abd.rc.left = abd.rc.right - Size.Width End If Else abd.rc.left = 0 abd.rc.right = SystemInformation.PrimaryMonitorSize.Width If abd.uEdge = CInt(ABEdge.ABE_TOP) Then abd.rc.top = 0 abd.rc.bottom = Size.Height Else abd.rc.bottom = SystemInformation.PrimaryMonitorSize.Height abd.rc.top = abd.rc.bottom - Size.Height End If End If ' Query the system for an approved size and position. SHAppBarMessage(CInt(ABMsg.ABM_QUERYPOS), abd) ' Adjust the rectangle, depending on the edge to which the ' appbar is anchored. Select Case abd.uEdge Case CInt(ABEdge.ABE_LEFT) abd.rc.right = abd.rc.left + Size.Width Case CInt(ABEdge.ABE_RIGHT) abd.rc.left = abd.rc.right - Size.Width Case CInt(ABEdge.ABE_TOP) abd.rc.bottom = abd.rc.top + Size.Height Case CInt(ABEdge.ABE_BOTTOM) abd.rc.top = abd.rc.bottom - Size.Height End Select ' Pass the final bounding rectangle to the system. SHAppBarMessage(CInt(ABMsg.ABM_SETPOS), abd) ' Move and size the appbar so that it conforms to the ' bounding rectangle passed to the system. Me.Location = New Point(abd.rc.left, abd.rc.top) Dim PSBH = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height Dim TaskBarHeight = PSBH - System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height Me.Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height - TaskBarHeight End Sub #End Region #Region "Form Variables" ' Constants Private Const OPACITY_INITIAL = 0 Private Const OPACITY_FINAL = 1 Private Const OPACITY_HIDDEN = 0.65 Private Const OPACITY_SHOWN = 0.85 Private DTIDB_SEARCHES As DataTable ' Common Helpers Classes Private Logger As Logger Private Init As ClassInit Private FileEx As Filesystem.File Private ErrorHandler As BaseErrorHandler Private Modules As ClassModules Private Search As SearchRunner ' Globix Helper Classes Private FileDropNew As FileDrop Private FileHandle As ClassFilehandle Private FolderWatch As ClassFolderwatcher ' ClipboardWatcher Helper Classes Private ClassWindow As Window Private ProfileFilter As ProfileFilter Private ProfileLoader As ClassProfileLoader Private Property Environment As Environment ' Runtime Flags Private ApplicationLoading As Boolean = True Private IDBSearchActive As Boolean = False ' Runtime Variables Private ESCHitCount As Integer = 0 Private IndexForm As frmGlobix_Index Private AdminForm As frmAdmin_Start Private InitialOverlayHandle As IOverlaySplashScreenHandle Private RunningTask As Task Private RunningTaskTokenSource As New CancellationTokenSource Private RunningTaskToken = RunningTaskTokenSource.Token ' Events Public Event ClipboardChanged As EventHandler(Of IDataObject) Private WithEvents HotkeyClass As Hotkey Private WithEvents Watcher As Watcher = Watcher.Singleton #End Region Private Sub frmFlowForm_Load(sender As Object, e As EventArgs) Handles Me.Load ' === Set Form === OverlayWindowOptions.Default.DisableInput = False ' === Show Splash Screen === SplashScreenManager.ShowForm(Me, GetType(frmSplash), False, False) ' === Initialization === Init = New ClassInit(My.LogConfig, Me) AddHandler Init.Completed, Async Sub() Await Init_Completed(sender, e) Init.InitializeApplication() ' === Register Sidebar === RegisterBar(ABEdge.ABE_RIGHT) ' Disable Form until init has completed Enabled = False End Sub Private Sub frmFlowForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing UnregisterBar() End Sub Private Async Function Init_Completed(sender As Object, e As EventArgs) As Threading.Tasks.Task Try ' === Initialization Complete === ApplicationLoading = False SplashScreenManager.CloseForm(False) ' === Initialize Environment === Logger = My.LogConfig.GetLogger() Environment = My.Application.GetEnvironment() ErrorHandler = New BaseErrorHandler(My.LogConfig, Logger, Me) Modules = New ClassModules(My.LogConfig, My.SystemConfig) FileEx = New Filesystem.File(My.LogConfig) Search = New SearchRunner(My.LogConfig, Environment, "FlowSearch") With { .BaseSearchSQL = SQL_FLOW_SEARCH_BASE } ' === Initialize Theming === If My.Application.Palette = "" Then UserLookAndFeel.Default.SetSkinStyle(My.Application.Skin) Else UserLookAndFeel.Default.SetSkinStyle(My.Application.Skin, My.Application.Palette) End If ' === Setup Timers === ' No timers right now ' === Setup Event Handlers === AddHandler KeyDown, AddressOf frmFlowForm_KeyDown AddHandler KeyUp, AddressOf frmFlowForm_KeyDown AddHandler Watcher.ClipboardChanged, AddressOf Watcher_ClipboardChanged AddHandler Search.Closed, AddressOf SearchRunner_Closed PictureBoxSearch.Visible = False For Each oRow As DataRow In My.Tables.DTIDB_COMMON_SQL.Rows If oRow.Item("TITLE") = SQLCMD_FLOW_SEARCH_BASE Then IDBSearchActive = True PictureBoxSearch.Visible = True End If Next Await Load_Recent_Files() If My.Application.ModulesActive.Contains(MODULE_CLIPBOARDWATCHER) Then Try ClassWindow = New Window(My.LogConfig) HotkeyClass = New Hotkey(Me) 'Add Toggle Hotkey HotkeyClass.AddHotKey(Keys.T, Hotkey.ModfierKey.MOD_CONTROL, HOTKEY_TOGGLE_WATCHER) ' Add Trigger Hotkey 'TODO: Configure Hotkey Dim oSearchKey As String = "D" Dim oFunctionKey As String = "CTRL" Dim oConverter As New KeysConverter Dim oObject As Object = oConverter.ConvertFromString(oSearchKey) Dim oKeyCode As Keys = oObject Select Case oFunctionKey Case "CTRL" HotkeyClass.AddHotKey(oKeyCode, Hotkey.ModfierKey.MOD_CONTROL, HOTKEY_TRIGGER_WATCHER) Case "SHIFT" HotkeyClass.AddHotKey(oKeyCode, Hotkey.ModfierKey.MOD_SHIFT, HOTKEY_TRIGGER_WATCHER) Case "ALT" HotkeyClass.AddHotKey(oKeyCode, Hotkey.ModfierKey.MOD_ALT, HOTKEY_TRIGGER_WATCHER) Case "WIN" HotkeyClass.AddHotKey(oKeyCode, Hotkey.ModfierKey.MOD_WIN, HOTKEY_TRIGGER_WATCHER) End Select AddHandler HotkeyClass.HotKeyPressed, AddressOf HotkeyClass_HotKeyPressed ProfileLoader = New ClassProfileLoader(My.LogConfig, My.Database) ProfileLoader.LoadProfiles() Catch ex As Exception ErrorHandler.ShowErrorMessage(ex, "Init Search FLOW") End Try Else My.Application.ClipboardWatcher.MonitoringActive = False Logger.Info("Clipboard Watcher Module is not active. Hotkey Monitoring will be disabled!") End If If My.Application.ModulesActive.Contains(MODULE_GLOBAL_INDEXER) Then FileDropNew = New FileDrop(My.LogConfig, "ZooFlow") FileHandle = New ClassFilehandle(My.LogConfig) FolderWatch = New ClassFolderwatcher(My.LogConfig) Dim oFileExclusions As New ClassExclusions() If oFileExclusions.Load() = False Then Dim oMsg As String If My.Application.User.Language = "de-DE" Then oMsg = "Die Ausschlusskriterien für Dateien in Folderwatch konnten nicht angelegt werden!" Else oMsg = "File-Exclusions in Folderwatch could not be created!" End If Dim oMsgBox As New frmDialog(oMsg, "Error", True) oMsgBox.ShowDialog() End If Init_Folderwatch() Folderwatch_CheckFiles() btnGlobixConfig.Visibility = DevExpress.XtraBars.BarItemVisibility.Always Else btnGlobixConfig.Visibility = DevExpress.XtraBars.BarItemVisibility.Never End If Dim oProcessManagerPath = Modules.GetProductPath(Base.ECM.Product.ProcessManager) If oProcessManagerPath IsNot Nothing Then My.SystemConfig.ProductPaths.ProcessManagerPath = oProcessManagerPath My.SystemConfigManager.Save() End If ' TODO: This needs an update of the function FNZF_GET_MODULE_INFO If My.Application.ModulesActive.Contains(MODULE_PROCESS_MANAGER) Then TimerDisplay.Enabled = True PictureBoxPM.Visible = True DISPLAY_TASKS() End If If IsNothing(My.Tables.DTIDB_CATALOG_USER) Then Exit Function End If Await ConfigureQuicksearch1(False) Catch ex As Exception Logger.Error(ex) Finally Enabled = True End Try End Function Private Async Sub SearchRunner_Closed(sender As Object, e As Integer) Await Load_Recent_Files() End Sub Private Async Function Load_Recent_Files() As Task Try Dim AccessedFilesTable = Await My.Database.GetDatatableIDBAsync(SQL_RECENT_FILES_USER) GridControlRecentFiles.DataSource = AccessedFilesTable colPrimary.FieldName = AccessedFilesTable.Columns(1).ColumnName ' "DisplayFileName" colSecondary.FieldName = AccessedFilesTable.Columns(2).ColumnName '"Changed when" Catch ex As Exception ShowErrorMessage(ex) End Try End Function Async Function ConfigureQuicksearch1(Reload As Boolean) As Threading.Tasks.Task If Reload Then Dim oSQL = $"SELECT * FROM TBIDB_CATALOG_USER WHERE USR_ID = {My.Application.User.UserId}" My.Tables.DTIDB_CATALOG_USER = Await My.Database.GetDatatableIDBAsync(oSQL) End If For Each oRow As DataRow In My.Tables.DTIDB_CATALOG_USER.Rows If oRow.Item("CAT_TITLE") = "QUICKSEARCH1_TITLE" Then pnlQuicksearch1.Visible = True lblQuicksearch1.Text = oRow.Item("CAT_STRING") ElseIf oRow.Item("CAT_TITLE") = "QUICKSEARCH1_POS" Then 'If oRow.Item("CAT_STRING") = "Top" Then ' pnlQuicksearch1.Dock = DockStyle.Top 'ElseIf oRow.Item("CAT_STRING") = "Bottom" Then ' pnlQuicksearch1.Dock = DockStyle.Bottom 'End If End If Next End Function Public Sub RegisterBar(ByVal dockEdge As ABEdge) AppDeskData = New AppDeskBar() AppDeskData.cbSize = Marshal.SizeOf(AppDeskData) AppDeskData.hWnd = Me.Handle If Not fBarRegistered Then uCallBack = RegisterWindowMessage("AppBarMessage") AppDeskData.uCallbackMessage = uCallBack SHAppBarMessage(CInt(ABMsg.ABM_NEW), AppDeskData) 'ToDo: Unsigned Integers not supported fBarRegistered = True ABSetPos(ABEdge.ABE_RIGHT) Else SHAppBarMessage(CInt(ABMsg.ABM_REMOVE), AppDeskData) fBarRegistered = False End If End Sub Public Sub UnregisterBar() If fBarRegistered Then fBarRegistered = False SHAppBarMessage(ABMsg.ABM_REMOVE, AppDeskData) End If End Sub Public Sub Init_Folderwatch() Try Dim oSql As String = "SELECT FOLDER_PATH FROM TBGI_FOLDERWATCH_USER WHERE FOLDER_TYPE = 'DEFAULT' AND USER_ID = " & My.Application.User.UserId Dim oDT = My.Database.GetDatatable("TBGI_FOLDERWATCH_USER", oSql, EDMI.API.Constants.DatabaseType.ECM, $"FOLDER_TYPE = 'DEFAULT' AND USER_ID = {My.Application.User.UserId}") If oDT.Rows.Count = 0 Then 'Throw New ApplicationException("No Default Path configured for User!") Logger.Warn("No Default Path configured for User. Skipping.") Exit Sub End If Dim oFolderWatchPath = oDT.Rows.Item(0).Item("FOLDER_PATH") oFolderWatchPath = NotNull(oFolderWatchPath, String.Empty).ToString If oFolderWatchPath = String.Empty Then Logger.Info("Init_Folderwatch: folderwatchPath is empty") My.Application.Globix.Folderwatchstarted = False My.UIConfig.Globix.FolderWatchStarted = False My.UIConfigManager.Save() Else If Not IO.Directory.Exists(oFolderWatchPath) Then Logger.Info("Init_Folderwatch: folderwatchPath does not exists or is invalid path") My.Application.Globix.Folderwatchstarted = False My.UIConfig.Globix.FolderWatchStarted = False My.UIConfigManager.Save() Else My.Application.Globix.CurrentFolderWatchPath = oFolderWatchPath FolderWatch.StartStop_FolderWatch() End If End If Catch ex As Exception ShowErrorMessage(ex) End Try Try Dim oSql As String = "SELECT FOLDER_PATH FROM TBGI_FOLDERWATCH_USER WHERE FOLDER_TYPE = 'SCAN' AND USER_ID = " & My.Application.User.UserId Dim oFolderwatchScanPath = My.Database.GetScalarValueECM(oSql) oFolderwatchScanPath = IIf(IsDBNull(oFolderwatchScanPath), "", oFolderwatchScanPath) If oFolderwatchScanPath = String.Empty Then Logger.Info("Init_Folderwatch: folderwatchPath is empty") My.Application.Globix.ScanFolderwatchstarted = False My.UIConfig.Globix.FolderWatchScanStarted = False My.UIConfigManager.Save() Else If Not IO.Directory.Exists(oFolderwatchScanPath) Then Logger.Info("Init_Folderwatch: folderwatchPath does not exists or is invalid path") My.Application.Globix.ScanFolderwatchstarted = False My.UIConfig.Globix.FolderWatchScanStarted = False My.UIConfigManager.Save() Else My.Application.Globix.CURRENT_SCAN_FOLDERWATCH = oFolderwatchScanPath FolderWatch.StartStop_FolderWatchSCAN() End If End If Catch ex As Exception ShowErrorMessage(ex) End Try End Sub Private Sub TimerRefreshData_Tick(sender As Object, e As EventArgs) 'TODO: Refresh Data End Sub Private Sub frmFlowForm_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) If e.KeyCode = Keys.Escape Then If RunningTask IsNot Nothing Then RunningTaskTokenSource.Cancel() Else If ESCHitCount > 0 Then ExitZooflow() Else ESCHitCount += 1 End If End If End If End Sub Sub ExitZooflow() Dim omessage = "Wollen sie ZooFlow wirklich beenden?" If My.Application.User.Language <> "de-DE" Then omessage = "Are you sure you want to close ZooFlow?" End If Dim oTitle = "Zooflow beenden" If My.Application.User.Language <> "de-DE" Then oTitle = "Exit Zooflow" End If Dim oMsgBox As New frmDialog(omessage, oTitle, False) oMsgBox.ShowDialog() If oMsgBox.DialogResult = DialogResult.OK Then Close() Else ESCHitCount = 0 End If End Sub Sub Open_FlowSearch() Cursor = Cursors.WaitCursor If TheFormIsAlreadyLoaded("frmFlowSearch1") Then Cursor = Cursors.Default Exit Sub End If Dim oForm As New frmFlowSearch2() oForm.Show() oForm.BringToFront() Cursor = Cursors.Default End Sub Private Sub PictureBoxSearch1_Click(sender As Object, e As EventArgs) Handles PictureBoxSearch.Click Open_FlowSearch() End Sub Private Sub ZooFlowBeendenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ZooFlowBeendenToolStripMenuItem.Click ExitZooflow() End Sub Private Sub VerwaltungToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles VerwaltungToolStripMenuItem.Click Cursor = Cursors.WaitCursor AdminForm = New frmAdmin_Start() AdminForm.Show() Cursor = Cursors.Default End Sub Private Sub frmFlowForm_DragEnter(sender As Object, e As DragEventArgs) Handles MyBase.DragEnter If My.Application.GlobixDropAreaStyle = "PROGRESSIVE" Then 'PictureBoxDragDrop.Image = My.Resources._1_LOGO_ZOO_FLOW_DROP3 PictureEdit2.Image = My.Resources.ZOOFLOW_DRAG_PROGRESSIVE Else 'PictureBoxDragDrop.Image = My.Resources._1_LOGO_ZOO_FLOW_DROP2 PictureEdit2.Image = My.Resources.ZOOFLOW_DRAG_NORMAL End If e.Effect = DragDropEffects.Copy Drag_Enter(sender, e) End Sub Private Async Sub frmFlowForm_DragDrop(sender As Object, e As DragEventArgs) Handles MyBase.DragDrop Await DragDropForm(e) End Sub Private Sub frmFlowForm_DragLeave(sender As Object, e As EventArgs) Handles Me.DragLeave 'PictureBoxDragDrop.Image = My.Resources._1_LOGO_ZOO_FLOW1 PictureEdit2.Image = My.Resources.ZOOFLOW_DEFAULT End Sub Private Function TheFormIsAlreadyLoaded(ByVal pFormName As String) As Boolean TheFormIsAlreadyLoaded = False For Each frm As Form In Application.OpenForms If frm.Name.Equals(pFormName) Then TheFormIsAlreadyLoaded = True Exit Function End If Next End Function Private Sub NotifyIcon_DoubleClick(sender As Object, e As EventArgs) Handles NotifyIcon.DoubleClick If Visible = False Then Visible = True Else Visible = False End If End Sub Sub Drag_Enter(sender As Object, e As DragEventArgs) If e.Data.GetDataPresent(DataFormats.FileDrop) Then e.Effect = DragDropEffects.All ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then 'handle a message dragged from Outlook e.Effect = DragDropEffects.Copy ElseIf e.Data.GetDataPresent("aryFileGroupDescriptor") AndAlso (e.Data.GetDataPresent("FileContents")) Then e.Effect = DragDropEffects.Copy Else 'otherwise, do not handle e.Effect = DragDropEffects.None End If End Sub Async Function DragDropForm(e As DragEventArgs) As Threading.Tasks.Task If Not My.Application.ModulesActive.Contains(ClassConstants.MODULE_GLOBAL_INDEXER) Then Exit Function End If If TheFormIsAlreadyLoaded("frmIndexFileList") Then Cursor = Cursors.Default Dim oMsgBox As New frmDialog("Please index the active file first!", "Drag 'n Drop not allowed!", True) oMsgBox.ShowDialog() Exit Function End If PictureEdit2.Image = My.Resources.ZOOFLOW_DEFAULT 'Erstmal alles löschen My.Database.ExecuteNonQueryECM("DELETE FROM TBGI_FILES_USER WHERE USER@WORK = '" & My.Application.User.UserName & "'") Dim oDroppedFiles = FileDropNew.GetFiles(e) If oDroppedFiles.Count > 0 Then Await Globix_CheckDroppedFiles(oDroppedFiles) End If Await Load_Recent_Files() End Function Private Async Function Globix_CheckDroppedFiles(pDroppedFiles As List(Of FileDrop.DroppedFile)) As Task Try Await My.Database.ExecuteNonQueryECMAsync($"DELETE FROM TBGI_FILES_USER WHERE WORKED = 1 AND USER@WORK = '{My.Application.User.UserName}'") For Each oDroppedFile In pDroppedFiles Logger.Info("Checking Dropped File: [{0}]", oDroppedFile.FilePath) Dim oDropType = oDroppedFile.DropType Dim oFileName = oDroppedFile.FilePath If FileHandle.CheckDuplicateFiles(oFileName, "Manuelle Ablage") Then FileHandle.Decide_FileHandle(oFileName, oDropType) End If Next Dim sql As String = "SELECT * FROM TBGI_FILES_USER WHERE WORKED = 0 AND USER@WORK = '" & My.Application.User.UserName & "'" My.Application.Globix.DTACTUAL_FILES = Nothing My.Application.Globix.DTACTUAL_FILES = Await My.Database.GetDatatableECMAsync(sql) My.Application.Globix.ABORT_INDEXING = False Dim oOnlyFilesFromFilesystem = True For Each oRow As DataRow In My.Application.Globix.DTACTUAL_FILES.Rows If oRow.Item("HANDLE_TYPE").ToString <> "|DROPFROMFSYSTEM|" Then oOnlyFilesFromFilesystem = False Exit For End If Next If My.Application.Globix.DTACTUAL_FILES.Rows.Count > 1 And oOnlyFilesFromFilesystem = False Then frmGlobix_IndexFileList.ShowDialog() My.Application.Globix.DTACTUAL_FILES = Nothing My.Application.Globix.DTACTUAL_FILES = My.Database.GetDatatableECM(sql) End If For Each oRow As DataRow In My.Application.Globix.DTACTUAL_FILES.Rows Dim oFilePath As String = oRow.Item("FILENAME2WORK").ToString Dim oFileId As Integer = oRow.Item("GUID") My.Application.Globix.CurrentWorkfile = New Globix.Models.WorkFile(oFileId) With { .FilePath = oFilePath } Logger.Info(" CURRENT_WORKFILE: {0}", My.Application.Globix.CurrentWorkfile) If IO.File.Exists(My.Application.Globix.CurrentWorkfile.FilePath) = True And My.Application.Globix.DTACTUAL_FILES.Rows.Count > 0 Then Globix_Open_IndexDialog() End If Next Catch ex As Exception ShowErrorMessage(ex) Finally CleanTempFiles() Show() End Try End Function Private Sub CleanTempFiles() Dim oTempFiles = My.Application.Globix.TEMP_FILES For Each oFile In oTempFiles Try IO.File.Delete(oFile) Logger.Debug("Temp file [{0}] was deleted.", oFile) Catch ex As Exception Logger.Warn("Temp file [{0}] could not be deleted", oFile) Logger.Error(ex) End Try Next My.Application.Globix.TEMP_FILES.Clear() FileHandle.ClearTempFiles() FileDropNew.RemoveTempDirectory() End Sub Sub Globix_Open_IndexDialog() Try IndexForm = New frmGlobix_Index(My.LogConfig) NotifyIconReset() AddHandler IndexForm.FormClosed, AddressOf GlobixClosed IndexForm.ShowDialog() If IndexForm.oSuccess = True Then Dim oMessage As String = "Datei erfolgreich importiert!" If My.Application.User.Language <> "de-DE" Then oMessage = "File successfully imported!" End If NotifyIcon.ShowBalloonTip(15000, "FileFlow", oMessage, ToolTipIcon.Info) End If Cursor = Cursors.Default Catch ex As Exception ShowErrorMessage(ex) End Try End Sub Sub NotifyIconReset() NI_TYPE = "INFO" NI_MESSAGE = String.Empty End Sub Sub GlobixClosed() Try If NI_MESSAGE = String.Empty Then Exit Sub End If Dim oNIType = 1 Select Case NI_TYPE Case "INFO" oNIType = 1 Case "ERROR" oNIType = 3 End Select NotifyIcon.ShowBalloonTip(30000, NI_TITLE, NI_MESSAGE, oNIType) Catch ex As Exception ShowErrorMessage(ex) End Try End Sub Sub Folderwatch_CheckFiles() If My.Application.Globix.CurrentFolderWatchPath = String.Empty Then My.Application.Globix.Folderwatchstarted = False End If If My.Application.Globix.CURRENT_SCAN_FOLDERWATCH = String.Empty Then My.UIConfigManager.Config.Globix.FolderWatchScanStarted = False My.UIConfigManager.Save() End If If My.Application.Globix.CurrentFolderWatchPath <> "" Or My.Application.Globix.CURRENT_SCAN_FOLDERWATCH <> "" Then Try If My.UIConfigManager.Config.Globix.FolderWatchScanStarted = True Then Logger.Info("FWSCAN started - Checking file:" & My.Application.Globix.CURRENT_SCAN_FOLDERWATCH) Dim fileEntries As String() = Directory.GetFiles(My.Application.Globix.CURRENT_SCAN_FOLDERWATCH) ' Process the list of files found in the directory. Dim fileName As String For Each fileName In fileEntries Logger.Info("Scanfolder after startup: Checking file:" & fileName) For Each row As DataRow In My.Application.Globix.DTEXCLUDE_FILES.Rows Dim content As String = row.Item(0).ToString.ToLower If fileName.ToLower.Contains(content) Then Exit Sub End If Next Dim handleType As String If fileName.ToLower.EndsWith(".msg") Then handleType = "|FW_OUTLOOK_MESSAGE|" Else handleType = "|FW_SIMPLEINDEXER|" End If 'Die Datei übergeben Logger.Info(" Adding file from Scanfolder after startup:" & fileName) If FileHandle.CheckDuplicateFiles(fileName, "FolderWatch/Scan") Then FileHandle.Decide_FileHandle(fileName, handleType) Else IO.File.Delete(fileName) Logger.Info("Scanfolder Startup: File already exists:" & fileName) End If Next fileName Else Logger.Info("FWSCAN not started") End If Catch ex As Exception ShowErrorMessage(ex) End Try Try If My.Application.Globix.Folderwatchstarted = True Then Logger.Info("Folderwatchstarted - Checking file:" & My.Application.Globix.CurrentFolderWatchPath) Dim fileEntries As String() = Directory.GetFiles(My.Application.Globix.CurrentFolderWatchPath) ' Process the list of files found in the directory. Dim fileName As String For Each fileName In fileEntries Logger.Info("Folderwach after startup: Checking file:" & fileName) For Each row As DataRow In My.Application.Globix.DTEXCLUDE_FILES.Rows Dim content As String = row.Item(0).ToString.ToLower If fileName.ToLower.Contains(content) Then Exit Sub End If Next Dim handleType As String If fileName.ToLower.EndsWith(".msg") Then handleType = "|FW_OUTLOOK_MESSAGE|" Else handleType = "|FW_SIMPLEINDEXER|" End If 'Die Datei übergeben Logger.Info("Adding file from Folderwatch after startup:" & fileName) If FileHandle.CheckDuplicateFiles(fileName, "FolderWatch/Scan") Then FileHandle.Decide_FileHandle(fileName, handleType) Else Logger.Info("Folderwatch Startup: File already exists:" & fileName) IO.File.Delete(fileName) End If Next fileName Else Logger.Info("Folderwatch not started") End If Catch ex As Exception ShowErrorMessage(ex) End Try If TimerCheckFolderWatchTable.Enabled = False Then TimerCheckFolderWatchTable.Start() End If End If End Sub Private Sub frmFlowForm_ResizeEnd(sender As Object, e As EventArgs) Handles Me.ResizeEnd My.UIConfig.FlowForm.Location = Location My.UIConfigManager.Save() End Sub Private Sub TimerFolderwatch_Tick(sender As Object, e As EventArgs) Handles TimerCheckFolderWatchTable.Tick Try ' JenneJ, 11.02.2019: ' Keine Folderwatch Dateien verarbeiten, wenn gerade Indexiert wird, ' dadurch würden die Globalen Variablen überschrieben ' und in Folge die falschen Dateien Indexiert! If My.Application.Globix.INDEXING_ACTIVE Or My.Application.Globix.MULTIINDEXING_ACTIVE Then Exit Sub End If If My.Application.Globix.Folderwatchstarted = True Or My.UIConfig.Globix.FolderWatchScanStarted = True Then 'Prüfen ob alle Files abgearbeitet wurden Dim sql = "SELECT * FROM TBGI_FILES_USER WHERE WORKED = 0 AND HANDLE_TYPE like '%|FW%' AND USER@WORK = '" & My.Application.User.UserName & "'" My.Application.Globix.DTACTUAL_FILES = My.Database.GetDatatableECM(sql) If My.Application.Globix.DTACTUAL_FILES.Rows.Count > 0 Then My.Application.Globix.ABORT_INDEXING = False TimerCheckFolderWatchTable.Enabled = False For Each row As DataRow In My.Application.Globix.DTACTUAL_FILES.Rows Dim FILEGUID = row.Item("GUID") Dim oDel = String.Format("DELETE FROM TBGI_FILES_USER WHERE GUID = {0}", FILEGUID) If My.Application.Globix.ABORT_INDEXING = True Then Exit For End If Dim FileForWork As String = row.Item(1).ToString Logger.Info(" In Timer Folderwatch - File: " & FileForWork) Dim fileInUse As Boolean = FileEx.TestFileIsLocked(FileForWork) 'Dim fileInUse As Boolean = FileHandle.IsFileInUse(FileForWork) Dim fileexists As Boolean = System.IO.File.Exists(FileForWork) If fileInUse = False Then If fileexists = True Then Dim handleType As String If FileForWork.ToLower.EndsWith(".msg") Then handleType = "|FW_OUTLOOK_MESSAGE|" Else handleType = "|FW_SIMPLEINDEXER|" End If If FileHandle.CheckDuplicateFiles(FileForWork, "FolderWatch") Then My.Application.Globix.CurrentWorkfile = New Globix.Models.WorkFile(row.Item("GUID")) With { .FilePath = FileForWork, .HotfolderFile = True } Globix_Open_IndexDialog() Else My.Database.ExecuteNonQueryECM(oDel) IO.File.Delete(FileForWork) Logger.Info("Folderwatch: File has been deleted:" & FileForWork) End If Else Logger.Info(" File not existing - Row will be deleted!") My.Database.ExecuteNonQueryECM(oDel) End If Else Logger.Info(" file '" & row.Item(1).ToString & "' could not be opened exclusively - fileInUse!") End If Next If TimerCheckFolderWatchTable.Enabled = False Then TimerCheckFolderWatchTable.Start() End If End If 'tslblFW.Visible = True Else 'tslblFW.Visible = False End If Catch ex As Exception If ex.Message.Contains("Sammlung wurde geändert") Or ex.Message.Contains("Enumeration") Then Else Dim oMsgBox As New frmDialog("Error in Work FolderWatch-File:" & vbNewLine & ex.Message, "Drag 'n Drop not allowed!", True) oMsgBox.ShowDialog() End If End Try End Sub Private Sub Watcher_ClipboardChanged(sender As Object, e As IDataObject) Dim ClipboardContents As String = Clipboard.GetText().Trim() Dim oState = My.Application.ClipboardWatcher oState.CurrentClipboardContents = ClipboardContents If oState.MonitoringActive = False Then Dim oMessage As String = "Clipboard Watcher is not active!" Logger.Warn(oMessage) End If If oState.UserProfiles Is Nothing Then Dim oMessage As String = "User Profiles are empty!" Logger.Warn(oMessage) End If If oState.ProfileProcesses Is Nothing OrElse oState.ProfileProcesses.Rows.Count = 0 Then Dim oMessage As String = "Profile Processes are empty!" Logger.Warn(oMessage) End If If oState.ProfileWindows Is Nothing OrElse oState.ProfileWindows.Rows.Count = 0 Then Dim oMessage As String = "Profile Windows are empty!" Logger.Warn(oMessage) End If If oState.ProfileControls Is Nothing OrElse oState.ProfileControls.Rows.Count = 0 Then Dim oMessage As String = "Profile Processes are empty!" Logger.Warn(oMessage) End If Dim oWindowInfo = ClassWindow.GetWindowInfo() Try ' Tree View zurücksetzen oState.MatchTreeView.Nodes.Clear() ProfileFilter = New ProfileFilter(My.LogConfig, oState.UserProfiles, oState.ProfileProcesses, oState.ProfileWindows, oState.ProfileControls, oState.MatchTreeView) Catch ex As Exception Logger.Error(ex) End Try Try Dim oProfiles = ProfileFilter.Profiles Dim oEnvironment = My.Application.GetEnvironment() ' Filter by Clipboard Contents oProfiles = ProfileFilter.FilterProfilesByClipboardRegex(oProfiles, ClipboardContents) oProfiles = ProfileFilter.LogRemainingProfiles(oProfiles, "FilterProfilesByClipboardRegex") ' Filter by Process Name oProfiles = ProfileFilter.FilterProfilesByProcess(oProfiles, oWindowInfo.ProcessName) oProfiles = ProfileFilter.LogRemainingProfiles(oProfiles, "FilterProfilesByProcess") ' Filter by Window Title oProfiles = ProfileFilter.FilterWindowsByWindowTitleRegex(oProfiles, oWindowInfo.WindowTitle) oProfiles = ProfileFilter.LogRemainingProfiles(oProfiles, "FilterWindowsByWindowTitleRegex") ' Filter by Focused Control oProfiles = ProfileFilter.FilterProfilesByFocusedControl(oProfiles, ClipboardContents, Handle) oProfiles = ProfileFilter.LogRemainingProfiles(oProfiles, "FilterProfilesByFocusedControl") oState.CurrentMatchingProfiles = oProfiles.ToList() ' Filter by Search Results oProfiles = ProfileFilter.FilterProfilesBySearchResults(oProfiles, oEnvironment.Database, oEnvironment.User, ClipboardContents) oProfiles = ProfileFilter.LogRemainingProfiles(oProfiles, "FilterProfilesBySearchResults") ' Clean up Profiles oProfiles = ProfileFilter.ClearNotMatchedProfiles(oProfiles) oProfiles = ProfileFilter.ClearDuplicateProfiles(oProfiles) oProfiles = ProfileFilter.LogRemainingProfiles(oProfiles, "CleanUp") oState.CurrentProfilesWithResults = oProfiles.ToList() Catch ex As Exception Logger.Error(ex) End Try End Sub Private Async Sub HotkeyClass_HotKeyPressed(HotKeyID As String) Dim oState = My.Application.ClipboardWatcher Select Case HotKeyID Case HOTKEY_TRIGGER_WATCHER If oState.CurrentClipboardContents = String.Empty Then Logger.Info("Current Clipboard Contents is empty. Exiting.") Exit Sub End If If oState.MonitoringActive = False Then Logger.Info("Monitoring is inactive. Exiting.") Exit Sub End If If oState.UserProfiles.Rows.Count = 0 Then NotifyIcon.ShowBalloonTip(NOTIFICATION_DELAY, "ClipboardWatcher", "Es wurden keine Profile für Sie gefunden.", ToolTipIcon.Warning) ElseIf oState.CurrentMatchingProfiles.Count = 0 Then NotifyIcon.ShowBalloonTip(NOTIFICATION_DELAY, "ClipboardWatcher", "Es wurden keine passenden Profile gefunden.", ToolTipIcon.Warning) ElseIf oState.CurrentProfilesWithResults.Count = 0 Then NotifyIcon.ShowBalloonTip(NOTIFICATION_DELAY, "ClipboardWatcher", "Es wurden weder Dokumente noch Daten gefunden!", ToolTipIcon.Warning) ElseIf oState.CurrentProfilesWithResults.Count = 1 Then Dim oProfile = oState.CurrentProfilesWithResults.First() Dim oProfileSearches As New ProfileSearches(My.LogConfig, My.Application.GetEnvironment(), oState.CurrentClipboardContents) Dim oFormTitle = GetResultWindowString(oState.CurrentClipboardContents) ' For now we assume these are document results instead of data results Dim oForm = Await oProfileSearches.GetDocResultForm(oProfile, oFormTitle, DigitalData.Modules.ZooFlow.Constants.OperationMode.ZooFlow) AddHandler oForm.NeedsRefresh, AddressOf ProfileResultForm_NeedsRefresh oForm.Show() Else Dim oProfiles = oState.CurrentProfilesWithResults Dim oEnvironment = My.Application.GetEnvironment() Dim oParams As New ClipboardWatcherParams With { .ClipboardContents = oState.CurrentClipboardContents, .MatchingProfiles = oProfiles, .MatchTreeView = oState.MatchTreeView, .OperationModeOverride = DigitalData.Modules.ZooFlow.Constants.OperationMode.ZooFlow } Dim oForm As New frmMatch(My.LogConfig, oEnvironment, oParams) oForm.Show() End If Case HOTKEY_TOGGLE_WATCHER If oState.MonitoringActive = True Then NotifyIcon.ShowBalloonTip(NOTIFICATION_DELAY, "ClipboardWatcher", "Clipboard-Watcher wurde deaktiviert!", ToolTipIcon.Info) Else NotifyIcon.ShowBalloonTip(NOTIFICATION_DELAY, "ClipboardWatcher", "Clipboard-Watcher wurde aktiviert!", ToolTipIcon.Info) End If oState.MonitoringActive = Not oState.MonitoringActive End Select End Sub Private Async Sub ProfileResultForm_NeedsRefresh(sender As Object, e As Integer) Dim oThisForm As IResultForm = sender Dim oState = My.Application.ClipboardWatcher Dim oProfileSearch As New ProfileSearches(My.LogConfig, Environment, oState.CurrentClipboardContents) If TypeOf sender Is frmDocumentResultList Then Dim oProfileId = e Dim oSearches = Await oProfileSearch.LoadDocumentSearchesAsync(oProfileId) Dim oResults = oSearches.Select(Function(search) Return New DocumentResultList.DocumentResult() With { .Title = search.TabCaption, .Datatable = search.DataTable } End Function).ToList() oThisForm.RefreshResults(oResults) End If End Sub Private Sub TestToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles TestToolStripMenuItem.Click frmtest.Show() End Sub Private Sub ShowErrorMessage(pEx As Exception) Dim oCallingClass = LogConfig.GetClassFullName(IncludeMethodNames:=True, Parts:=2) ErrorHandler.ShowErrorMessage(pEx, oCallingClass) End Sub Private Function GetResultWindowString(SearchContent As String) As String If SearchContent <> String.Empty Then If My.Application.User.Language = DigitalData.Modules.ZooFlow.State.UserState.LANG_DE_DE Then Return $"Suche Nach '{SearchContent}'" Else Return $"Search For '{SearchContent}'" End If Else Return String.Empty End If End Function Private Async Sub TextEdit1_KeyUp(sender As Object, e As KeyEventArgs) Handles txtQuicksearch1.KeyUp If e.KeyCode = Keys.Return Then Await CheckQuickSearch1() End If End Sub Private Async Function CheckQuickSearch1() As Threading.Tasks.Task Dim oSearchText = txtQuicksearch1.Text If oSearchText <> String.Empty Then Dim oHandle = SplashScreenManager.ShowOverlayForm(Me) Dim oToken = RunningTaskTokenSource.Token Try Dim oResult = Await Search.RunWithSearchTerm(oSearchText) If oResult.OK = False Then NotifyIcon.ShowBalloonTip(20_000, "Info", oResult.ErrorMessage, ToolTipIcon.Info) End If Catch ex As Exception ShowErrorMessage(ex) Finally RunningTask = Nothing SplashScreenManager.CloseOverlayForm(oHandle) txtQuicksearch1.Text = "" End Try End If End Function Private Sub buttonExitZooflow_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnExitZooflow.ItemClick ExitZooflow() End Sub Private Sub BarButtonItem1_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnRestartZooflow.ItemClick Application.Restart() End Sub Private Sub BarButtonItem6_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnServiceConfig.ItemClick Try Dim oForm As New frmServiceConfig() With { .ServiceAddress = My.Application.Service.Client.ServerAddress, .ServiceOnline = My.Application.Service.Client.IsOnline } oForm.ShowDialog() My.SystemConfig.AppServerConfig = oForm.ServiceAddress My.SystemConfigManager.Save() Catch ex As Exception ErrorHandler.ShowErrorMessage("Service Config") End Try End Sub Private Async Sub BarButtonItem8_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnBasicConfig.ItemClick frmConfigBasic.ShowDialog() Await ConfigureQuicksearch1(True) End Sub Private Sub BarButtonItem9_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnGlobixConfig.ItemClick frmGlobixBasicConfig.ShowDialog() End Sub Private Sub PictureBoxSearch_MouseEnter(sender As Object, e As EventArgs) Handles PictureBoxSearch.MouseEnter PictureBoxSearch.SvgImage = My.Resources.FLOW_Sidebar_Search_aktiv1 End Sub Private Sub PictureBoxSearch_MouseLeave(sender As Object, e As EventArgs) Handles PictureBoxSearch.MouseLeave PictureBoxSearch.SvgImage = My.Resources.FLOW_Sidebar_Search_inaktiv1 End Sub Private Sub PictureBoxPM_Click(sender As Object, e As EventArgs) Handles PictureBoxPM.Click Try Dim oProcessManagerPath = Modules.GetProductProgramPath(DigitalData.Modules.Base.ECM.Product.ProcessManager) If oProcessManagerPath IsNot Nothing AndAlso IO.File.Exists(oProcessManagerPath) Then Process.Start(oProcessManagerPath) Else NotifyIcon.ShowBalloonTip(30000, NI_TITLE, "Path to TaskFlow not properly configured", 3) End If Catch ex As Exception ShowErrorMessage(ex) End Try End Sub Private Function PM_Running() As Boolean Dim p() As Process p = Process.GetProcessesByName("DD_ProcessManager") If p.Count > 0 Then ' Process is running Return True Else ' Process is not running Return False End If End Function Private Sub PictureBoxPM_MouseEnter(sender As Object, e As EventArgs) Handles PictureBoxPM.MouseEnter PictureBoxPM.SvgImage = My.Resources.FLOW_Sidebar_Task_aktiv1 End Sub Private Sub PictureBoxPM_MouseLeave(sender As Object, e As EventArgs) Handles PictureBoxPM.MouseLeave PictureBoxPM.SvgImage = My.Resources.FLOW_Sidebar_Task_inaktiv1 End Sub Private Async Sub PictureEditQuicksearch1_Click(sender As Object, e As EventArgs) Handles PictureEditQuicksearch1.Click Await CheckQuickSearch1() End Sub Private Sub bbtnitmAusblenden_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbtnitmAusblenden.ItemClick UnregisterBar() EinblendenToolStripMenuItem.Visible = True Me.Visible = False End Sub Private Sub EinblendenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles EinblendenToolStripMenuItem.Click RegisterBar(ABEdge.ABE_RIGHT) Me.Visible = True End Sub Private Sub SucheEntwurfToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SucheEntwurfToolStripMenuItem.Click Dim oForm = New frmFlowSearch2() oForm.Show() End Sub Private Sub AdvBandedGridView1_DoubleClick(sender As Object, e As EventArgs) Handles RecentFilesView.DoubleClick If RecentFilesView.FocusedRowHandle >= 0 Then Dim oHandle = SplashScreenManager.ShowOverlayForm(Me) Try Dim oFile As DataRowView = RecentFilesView.GetRow(RecentFilesView.FocusedRowHandle) Dim oRow As DataRow = oFile.Row Dim oObjectId As Long = oRow.Item("DocId") Dim oDataSource As DataTable = GridControlRecentFiles.DataSource Dim oResult = oDataSource.AsEnumerable(). Where(Function(row) row.Item(0) = oObjectId). CopyToDataTable() Search.RunWithDataTable(oResult, "Suche") Catch ex As Exception ErrorHandler.ShowErrorMessage(ex, "Laden eines Dokuments") Finally SplashScreenManager.CloseOverlayForm(oHandle) End Try End If End Sub Private Sub TimerDisplay_Tick(sender As Object, e As EventArgs) Handles TimerDisplay.Tick DISPLAY_TASKS() End Sub Sub DISPLAY_TASKS() Try Dim oSQL = $"SELECT * FROM TBZF_USER_DISPLAY_JOBS WHERE USR_ID = {My.Application.User.UserId}" Dim oDT As DataTable = My.Database.GetDatatable("TBZF_USER_DISPLAY_JOBS", oSQL, EDMI.API.Constants.DatabaseType.ECM, $"USR_ID = {My.Application.User.UserId}") If Not IsNothing(oDT) Then If oDT.Rows.Count > 0 Then Dim oTooLTip = "TaskFlow " PMTaskBadgeGroup.Visible = False PMTaskBadgeIndividual.Visible = False For Each oRow As DataRow In oDT.Rows If oRow.Item("JOB_TITLE") = "PM_INDIVIDUAL_JOB" Then PMTaskBadgeIndividual.Properties.Text = oRow.Item("DESCR") PMTaskBadgeIndividual.Visible = True oTooLTip += $"({PMTaskBadgeIndividual.Properties.Text} Individual" ElseIf oRow.Item("JOB_TITLE") = "PM_GROUP_JOB" Then PMTaskBadgeGroup.Properties.Text = oRow.Item("DESCR") oTooLTip += $"- and {PMTaskBadgeGroup.Properties.Text} Group-" PMTaskBadgeGroup.Visible = True End If Next oTooLTip += $"Tasks)" PictureBoxPM.ToolTip = oTooLTip Else PMTaskBadgeGroup.Visible = False PMTaskBadgeIndividual.Visible = False End If Else PMTaskBadgeGroup.Visible = False PMTaskBadgeIndividual.Visible = False End If Catch ex As Exception End Try End Sub End Class