diff --git a/Controls.DocumentViewer/App.config b/Controls.DocumentViewer/App.config
index b7160380..0927f884 100644
--- a/Controls.DocumentViewer/App.config
+++ b/Controls.DocumentViewer/App.config
@@ -23,7 +23,7 @@
-
+
diff --git a/Controls.DocumentViewer/DocumentViewer.Designer.vb b/Controls.DocumentViewer/DocumentViewer.Designer.vb
index e08d99f5..f68aebe7 100644
--- a/Controls.DocumentViewer/DocumentViewer.Designer.vb
+++ b/Controls.DocumentViewer/DocumentViewer.Designer.vb
@@ -24,7 +24,6 @@ Partial Class DocumentViewer
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(DocumentViewer))
- Me.GdViewer = New GdPicture14.GdViewer()
Me.OpenFileDialog = New System.Windows.Forms.OpenFileDialog()
Me.BarManager1 = New DevExpress.XtraBars.BarManager(Me.components)
Me.ToolbarDocumentViewer = New DevExpress.XtraBars.Bar()
@@ -74,82 +73,6 @@ Partial Class DocumentViewer
CType(Me.RepositoryItemSearchControl1, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
- 'GdViewer
- '
- Me.GdViewer.AllowDropFile = False
- Me.GdViewer.AnimateGIF = True
- Me.GdViewer.AnnotationDropShadow = False
- Me.GdViewer.AnnotationEnableMultiSelect = True
- Me.GdViewer.AnnotationResizeRotateHandlesColor = System.Drawing.Color.FromArgb(CType(CType(0, Byte), Integer), CType(CType(0, Byte), Integer), CType(CType(128, Byte), Integer))
- Me.GdViewer.AnnotationResizeRotateHandlesScale = 1.0!
- Me.GdViewer.AnnotationSelectionLineColor = System.Drawing.Color.FromArgb(CType(CType(255, Byte), Integer), CType(CType(0, Byte), Integer), CType(CType(0, Byte), Integer))
- Me.GdViewer.AutoScrollMargin = New System.Drawing.Size(0, 0)
- Me.GdViewer.AutoScrollMinSize = New System.Drawing.Size(0, 0)
- Me.GdViewer.BackColor = System.Drawing.SystemColors.AppWorkspace
- Me.GdViewer.BackgroundImage = Nothing
- Me.GdViewer.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None
- Me.GdViewer.ClipAnnotsToPageBounds = True
- Me.GdViewer.ClipRegionsToPageBounds = True
- Me.GdViewer.ContinuousViewMode = True
- Me.GdViewer.DisplayQuality = GdPicture14.DisplayQuality.DisplayQualityAutomatic
- Me.GdViewer.DisplayQualityAuto = True
- Me.GdViewer.Dock = System.Windows.Forms.DockStyle.Fill
- Me.GdViewer.DocumentAlignment = GdPicture14.ViewerDocumentAlignment.DocumentAlignmentMiddleCenter
- Me.GdViewer.DocumentPosition = GdPicture14.ViewerDocumentPosition.DocumentPositionMiddleCenter
- Me.GdViewer.DrawPageBorders = True
- Me.GdViewer.EnableDeferredPainting = True
- Me.GdViewer.EnabledProgressBar = True
- Me.GdViewer.EnableFuzzySearch = False
- Me.GdViewer.EnableICM = False
- Me.GdViewer.EnableMenu = True
- Me.GdViewer.EnableMouseWheel = True
- Me.GdViewer.EnableTextSelection = True
- Me.GdViewer.ForceScrollBars = False
- Me.GdViewer.ForceTemporaryMode = False
- Me.GdViewer.ForeColor = System.Drawing.Color.Black
- Me.GdViewer.Gamma = 1.0!
- Me.GdViewer.HQAnnotationRendering = True
- Me.GdViewer.IgnoreDocumentResolution = False
- Me.GdViewer.KeepDocumentPosition = False
- Me.GdViewer.Location = New System.Drawing.Point(0, 33)
- Me.GdViewer.LockViewer = False
- Me.GdViewer.MagnifierHeight = 90
- Me.GdViewer.MagnifierWidth = 160
- Me.GdViewer.MagnifierZoomX = 2.0!
- Me.GdViewer.MagnifierZoomY = 2.0!
- Me.GdViewer.MouseButtonForMouseMode = GdPicture14.MouseButton.MouseButtonLeft
- Me.GdViewer.MouseMode = GdPicture14.ViewerMouseMode.MouseModePan
- Me.GdViewer.MouseWheelMode = GdPicture14.ViewerMouseWheelMode.MouseWheelModeVerticalScroll
- Me.GdViewer.Name = "GdViewer"
- Me.GdViewer.PageBordersColor = System.Drawing.Color.Black
- Me.GdViewer.PageBordersPenSize = 1
- Me.GdViewer.PageDisplayMode = GdPicture14.PageDisplayMode.MultiplePagesView
- Me.GdViewer.PdfDisplayFormField = True
- Me.GdViewer.PdfEnableFileLinks = True
- Me.GdViewer.PdfEnableLinks = True
- Me.GdViewer.PdfIncreaseTextContrast = False
- Me.GdViewer.PdfShowDialogForPassword = True
- Me.GdViewer.PdfShowOpenFileDialogForDecryption = True
- Me.GdViewer.PdfVerifyDigitalCertificates = False
- Me.GdViewer.PreserveViewRotation = True
- Me.GdViewer.RectBorderColor = System.Drawing.Color.Black
- Me.GdViewer.RectBorderSize = 1
- Me.GdViewer.RectIsEditable = True
- Me.GdViewer.RegionsAreEditable = True
- Me.GdViewer.RenderGdPictureAnnots = True
- Me.GdViewer.ScrollBars = True
- Me.GdViewer.ScrollLargeChange = CType(50, Short)
- Me.GdViewer.ScrollSmallChange = CType(1, Short)
- Me.GdViewer.SilentMode = True
- Me.GdViewer.Size = New System.Drawing.Size(841, 522)
- Me.GdViewer.TabIndex = 0
- Me.GdViewer.TabStop = False
- Me.GdViewer.ViewRotation = System.Drawing.RotateFlipType.RotateNoneFlipNone
- Me.GdViewer.Zoom = 1.0R
- Me.GdViewer.ZoomCenterAtMousePosition = False
- Me.GdViewer.ZoomMode = GdPicture14.ViewerZoomMode.ZoomMode100
- Me.GdViewer.ZoomStep = 25
- '
'OpenFileDialog
'
Me.OpenFileDialog.FileName = "OpenFileDialog1"
@@ -478,11 +401,6 @@ Partial Class DocumentViewer
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.BackColor = System.Drawing.SystemColors.ControlLightLight
- Me.Controls.Add(Me.lblInfo)
- Me.Controls.Add(Me.RichEditControl1)
- Me.Controls.Add(Me.lbFileNotLoaded)
- Me.Controls.Add(Me.SpreadsheetControl1)
- Me.Controls.Add(Me.GdViewer)
Me.Controls.Add(Me.barDockControlLeft)
Me.Controls.Add(Me.barDockControlRight)
Me.Controls.Add(Me.barDockControlBottom)
diff --git a/Controls.DocumentViewer/DocumentViewer.vb b/Controls.DocumentViewer/DocumentViewer.vb
index 89d0633b..1441527d 100644
--- a/Controls.DocumentViewer/DocumentViewer.vb
+++ b/Controls.DocumentViewer/DocumentViewer.vb
@@ -66,6 +66,8 @@ Public Class DocumentViewer
Private _TempFiles As New List(Of String)
Private Sub DocumentViewer_Load(sender As Object, e As EventArgs) Handles Me.Load
+ ' Ensure search is initialized once the control (and GdViewer) exists
+ EnsureSearchInitialized()
UpdateMainUi()
End Sub
'hallo
@@ -110,7 +112,8 @@ Public Class DocumentViewer
_licenseKey = pLicenseKey
_licenseManager.RegisterKEY(_licenseKey)
_Annotations = New Annotations(pLogConfig)
- _Search = New Search(pLogConfig, GdViewer)
+ ' Defer creating Search until GdViewer is ready
+ EnsureSearchInitialized()
_ToolbarSettings = pToolbarSettings
Dim oConfigPath = ConfigPath()
@@ -122,6 +125,17 @@ Public Class DocumentViewer
End Try
End Function
+ ' Create the Search helper only when both the log config and the GdViewer control exist
+ Private Sub EnsureSearchInitialized()
+ Try
+ If _Search Is Nothing AndAlso _logConfig IsNot Nothing AndAlso GdViewer IsNot Nothing Then
+ _Search = New Search(_logConfig, GdViewer)
+ End If
+ Catch ex As Exception
+ _logger?.Error(ex)
+ End Try
+ End Sub
+
'''
''' Load a file from a path and display it
'''
@@ -223,7 +237,17 @@ Public Class DocumentViewer
Public Sub CloseDocument()
Try
- GdViewer.CloseDocument()
+ ' Null-sicher schließen
+ If GdViewer IsNot Nothing Then
+ Try
+ GdViewer.CloseDocument()
+ Catch exInner As Exception
+ _logger?.Warn("Fehler beim Schließen von GdViewer")
+ _logger?.Error(exInner)
+ End Try
+ Else
+ _logger?.Debug("CloseDocument: GdViewer ist Nothing – nichts zu schließen")
+ End If
_FileInfo = Nothing
_FilePath = Nothing
@@ -299,23 +323,23 @@ Public Class DocumentViewer
GdViewer.Focus()
UpdateMainUi()
End Sub
- Private Sub btnFirstPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonFirstPage.ItemClick
+ Private Sub BtnFirstPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonFirstPage.ItemClick
GdViewer.DisplayFirstPage()
End Sub
- Private Sub btnPreviousPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonPrevPage.ItemClick
+ Private Sub BtnPreviousPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonPrevPage.ItemClick
GdViewer.DisplayPreviousPage()
End Sub
- Private Sub btnNextPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonNextPage.ItemClick
+ Private Sub BtnNextPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonNextPage.ItemClick
GdViewer.DisplayNextPage()
End Sub
- Private Sub btnLastPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonLastPage.ItemClick
+ Private Sub BtnLastPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonLastPage.ItemClick
GdViewer.DisplayLastPage()
End Sub
- Private Sub tbCurrentPage_Leave(ByVal sender As System.Object, ByVal e As EventArgs) Handles txtCurrentPage.EditValueChanged
+ Private Sub TbCurrentPage_Leave(ByVal sender As System.Object, ByVal e As EventArgs) Handles txtCurrentPage.EditValueChanged
Dim page As Integer = 0
If Integer.TryParse(txtCurrentPage.EditValue, page) Then
If page > 0 And page <= GdViewer.PageCount Then
@@ -352,11 +376,11 @@ Public Class DocumentViewer
GdViewer.PrintDialog()
End Sub
- Private Sub btnRotateLeft_Click(sender As Object, e As EventArgs) Handles buttonRotateLeft.ItemClick
+ Private Sub BtnRotateLeft_Click(sender As Object, e As EventArgs) Handles buttonRotateLeft.ItemClick
GdViewer.Rotate(RotateFlipType.Rotate270FlipNone)
End Sub
- Private Sub btnRotateRight_Click(sender As Object, e As EventArgs) Handles buttonRotateRight.ItemClick
+ Private Sub BtnRotateRight_Click(sender As Object, e As EventArgs) Handles buttonRotateRight.ItemClick
GdViewer.Rotate(RotateFlipType.Rotate90FlipNone)
End Sub
@@ -381,7 +405,7 @@ Public Class DocumentViewer
End If
End Sub
- Private Sub btnSettings_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonSettings.ItemClick
+ Private Sub BtnSettings_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonSettings.ItemClick
Using frmSettings As New frmViewerSettings(GdViewer)
frmSettings.ShowDialog(Me)
End Using
@@ -468,6 +492,12 @@ Public Class DocumentViewer
End Sub
Private Function DoLoadFile(FilePath As String, Optional ViewOverride As String = "") As Boolean
Try
+ ' Ensure the embedded GdViewer control exists before using it
+ If Not EnsureViewerReady() Then
+ _logger?.Warn("GdViewer control is not initialized yet. Delaying load.")
+ Return False
+ End If
+
lblInfo.Visible = False
Dim oFileInfo = New FileInfo(FilePath)
Dim oExtension As String = oFileInfo.Extension.ToUpper
@@ -503,12 +533,6 @@ Public Class DocumentViewer
GdViewer.Visible = False
SpreadsheetControl1.Dock = DockStyle.Fill
- 'Case ".EML", ".DOC", ".DOCX", ".ODT", ".RTF", ".TXT"
- ' RichEditControl1.LoadDocument(FilePath, GetDocumentFormat(oExtension))
-
- ' RichEditControl1.Visible = True
- ' GdViewer.Visible = False
- ' RichEditControl1.Dock = DockStyle.Fill
Case Else
Select Case oExtension.ToUpper
Case ".EML", ".DOC", ".DOCX", ".XLS", ".XLSX", ".ODT", ".RTF", ".TXT"
@@ -555,6 +579,32 @@ Public Class DocumentViewer
End Try
End Function
+ ' Ensures the embedded GdViewer control exists and is added to the visual tree
+ Private Function EnsureViewerReady() As Boolean
+ Try
+ ' If the control field is Nothing (e.g., designer not yet created), try to lazy-create and add it
+ If GdViewer Is Nothing Then
+ ' Attempt to find an existing instance by name in Controls collection
+ Dim existing = Me.Controls.OfType(Of GdPicture14.GdViewer)().FirstOrDefault()
+ If existing IsNot Nothing Then
+ ' Assign the designer field via reflection if needed, otherwise use it directly
+ GdViewer = existing
+ Else
+ ' Last resort: create a new viewer and add it
+ Dim viewer = New GdPicture14.GdViewer()
+ viewer.Dock = DockStyle.Fill
+ Me.Controls.Add(viewer)
+ GdViewer = viewer
+ End If
+ End If
+
+ Return GdViewer IsNot Nothing
+ Catch ex As Exception
+ _logger?.Error(ex)
+ Return False
+ End Try
+ End Function
+
Private Sub FitToPage()
GdViewer.ZoomMode = ViewerZoomMode.ZoomModeFitToViewer
End Sub
@@ -703,18 +753,21 @@ Public Class DocumentViewer
End Sub
Private Sub btnSearch2_ItemClick(sender As Object, e As XtraBars.ItemClickEventArgs) Handles btnSearch2.ItemClick
- If Not String.IsNullOrEmpty(txtSearch.EditValue) Then
+ EnsureSearchInitialized()
+ If _Search IsNot Nothing AndAlso Not String.IsNullOrEmpty(txtSearch.EditValue) Then
_Search.SearchAll(txtSearch.EditValue?.ToString)
End If
End Sub
Private Sub btnPrevHighlight_ItemClick(sender As Object, e As XtraBars.ItemClickEventArgs) Handles btnPrevHighlight.ItemClick
- _Search.PrevHighlight()
+ EnsureSearchInitialized()
+ _Search?.PrevHighlight()
End Sub
Private Sub btnNextHighlight_ItemClick(sender As Object, e As XtraBars.ItemClickEventArgs) Handles btnNextHighlight.ItemClick
- _Search.NextHighlight()
+ EnsureSearchInitialized()
+ _Search?.NextHighlight()
End Sub
Private Sub txtSearch_EditValueChanged(sender As Object, e As EventArgs) Handles txtSearch.EditValueChanged
diff --git a/Controls.DocumentViewer/DocumentViewer.vbproj b/Controls.DocumentViewer/DocumentViewer.vbproj
index bef79e71..e0494014 100644
--- a/Controls.DocumentViewer/DocumentViewer.vbproj
+++ b/Controls.DocumentViewer/DocumentViewer.vbproj
@@ -96,86 +96,74 @@
..\packages\DocumentFormat.OpenXml.Framework.3.2.0\lib\net46\DocumentFormat.OpenXml.Framework.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.barcode.1d.writer.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.barcode.1d.writer.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.barcode.2d.writer.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.barcode.2d.writer.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.CAD.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.CAD.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.CAD.DWG.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.CAD.DWG.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.Common.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.Common.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.Document.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.Document.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.Email.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.Email.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.HTML.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.HTML.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.Imaging.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.Imaging.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.Imaging.Formats.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.Imaging.Formats.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.Imaging.Formats.Conversion.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.Imaging.Formats.Conversion.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.Imaging.Rendering.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.Imaging.Rendering.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.MSOfficeBinary.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.MSOfficeBinary.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.OpenDocument.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.OpenDocument.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.OpenXML.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.OpenXML.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.OpenXML.Templating.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.OpenXML.Templating.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.PDF.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.PDF.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.RTF.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.RTF.dll
-
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.SVG.dll
+
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.SVG.dll
- ..\packages\GdPicture.14.3.19\lib\net462\GdPicture.NET.14.wia.gateway.dll
+ ..\packages\GdPicture.14.3.3\lib\net462\GdPicture.NET.14.wia.gateway.dll
True
-
- ..\packages\IndexRange.1.0.3\lib\net45\IndexRange.dll
-
..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll
-
- ..\packages\Microsoft.Bcl.HashCode.6.0.0\lib\net462\Microsoft.Bcl.HashCode.dll
-
-
- ..\packages\GdPicture.14.3.19\lib\net462\NativeSDK.Settings.dll
-
-
- ..\packages\GdPicture.14.3.19\lib\net462\NativeSDK.Settings.Edition.dll
-
..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
@@ -185,8 +173,8 @@
..\packages\NLog.5.0.5\lib\net46\NLog.dll
-
- ..\packages\OpenMcdf.3.0.0\lib\netstandard2.0\OpenMcdf.dll
+
+ ..\packages\OpenMcdf.2.4.1\lib\net40\OpenMcdf.dll
@@ -206,8 +194,8 @@
..\packages\System.CodeDom.8.0.0\lib\net462\System.CodeDom.dll
-
- ..\packages\System.Collections.Immutable.9.0.0\lib\net462\System.Collections.Immutable.dll
+
+ ..\packages\System.Collections.Immutable.8.0.0\lib\net462\System.Collections.Immutable.dll
@@ -359,11 +347,11 @@
-
+
Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".
-
+
\ No newline at end of file
diff --git a/Controls.DocumentViewer/My Project/AssemblyInfo.vb b/Controls.DocumentViewer/My Project/AssemblyInfo.vb
index 1f14e62d..3d6979a4 100644
--- a/Controls.DocumentViewer/My Project/AssemblyInfo.vb
+++ b/Controls.DocumentViewer/My Project/AssemblyInfo.vb
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben:
'
-
-
+
+
diff --git a/Controls.DocumentViewer/packages.config b/Controls.DocumentViewer/packages.config
index 46ecac0c..18dc42d5 100644
--- a/Controls.DocumentViewer/packages.config
+++ b/Controls.DocumentViewer/packages.config
@@ -3,24 +3,22 @@
-
-
-
+
+
-
-
+
-
+
diff --git a/GUIs.Common/app.config b/GUIs.Common/app.config
index 9081ad45..0f74ee4e 100644
--- a/GUIs.Common/app.config
+++ b/GUIs.Common/app.config
@@ -103,6 +103,10 @@
+
+
+
+
diff --git a/GUIs.Test.TestGUI/My Project/licenses.licx b/GUIs.Test.TestGUI/My Project/licenses.licx
index e69de29b..cb7c55fb 100644
--- a/GUIs.Test.TestGUI/My Project/licenses.licx
+++ b/GUIs.Test.TestGUI/My Project/licenses.licx
@@ -0,0 +1 @@
+DevExpress.XtraEditors.TextEdit, DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a
diff --git a/GUIs.Test.TestGUI/MyApplication.vb b/GUIs.Test.TestGUI/MyApplication.vb
new file mode 100644
index 00000000..68fe6785
--- /dev/null
+++ b/GUIs.Test.TestGUI/MyApplication.vb
@@ -0,0 +1,49 @@
+Imports DigitalData.Modules.Database
+Imports DigitalData.Modules.EDMI.API
+Imports DigitalData.Modules.EDMI.API.Modules
+Imports DigitalData.Modules.Logging
+Imports DigitalData.Modules.ZooFlow
+
+Namespace My
+ '''
+ ''' Extends the My Namespace
+ ''' Example: My.LogConfig
+ '''
+
+ Module Extension
+ Property LogConfig As LogConfig
+#Region "Database"
+ Property Database As DatabaseWithFallback
+ Property DatabaseECM As MSSQLServer
+ Property DatabaseIDB As MSSQLServer
+ End Module
+
+#End Region
+ Partial Friend Class MyApplication
+ Public Property Skin As String = ""
+ Public Property Palette As String = ""
+ Public Property GlobixDropAreaStyle As String = "PROGRESSIVE"
+
+ Public Property Settings As New State.SettingsState
+ Public Property User As New State.UserState
+ Public Property Service As New State.ServiceState
+ Public Property Modules As New Dictionary(Of String, State.ModuleState)
+ Public Property ModulesActive As New List(Of String)
+
+
+ Public CommandLineFunction As String
+ Public CommandLineArguments As New Dictionary(Of String, String)
+
+ Public Function GetEnvironment() As Environment
+ Return New Environment With {
+ .Database = My.DatabaseECM,
+ .DatabaseIDB = My.DatabaseIDB,
+ .Modules = My.Application.Modules,
+ .Service = My.Application.Service,
+ .Settings = My.Application.Settings,
+ .User = My.Application.User
+ }
+ End Function
+
+ End Class
+End Namespace
\ No newline at end of file
diff --git a/GUIs.Test.TestGUI/TestGUI.vbproj b/GUIs.Test.TestGUI/TestGUI.vbproj
index 9469e29a..f036ba40 100644
--- a/GUIs.Test.TestGUI/TestGUI.vbproj
+++ b/GUIs.Test.TestGUI/TestGUI.vbproj
@@ -94,6 +94,10 @@
..\..\DDModules\Database\bin\Debug\DigitalData.Modules.Database.dll
+
+ False
+ P:\Projekte DIGITAL DATA\DIGITAL DATA - Entwicklung\DLL_Bibliotheken\Digital Data\DD_Modules\DigitalData.Modules.EDMI.API.dll
+
..\..\DDModules\Encryption\bin\Debug\DigitalData.Modules.Encryption.dll
@@ -118,6 +122,10 @@
..\..\DDModules\Windream\bin\Debug\DigitalData.Modules.Windream.dll
+
+ False
+ ..\..\DDModules\ZooFlow\bin\Debug\DigitalData.Modules.ZooFlow.dll
+
..\packages\DocumentFormat.OpenXml.3.2.0\lib\net46\DocumentFormat.OpenXml.dll
@@ -407,6 +415,7 @@
Settings.settings
True
+
@@ -488,10 +497,6 @@
{a8c3f298-76ab-4359-ab3c-986e313b4336}
EDMIService
-
- {7deec36e-ea5f-4711-ad1e-fd8894f4ad77}
- DDZUGFeRDService
-
diff --git a/GUIs.Test.TestGUI/frmFilesystem.Designer.vb b/GUIs.Test.TestGUI/frmFilesystem.Designer.vb
index 7c530ea3..49790b0a 100644
--- a/GUIs.Test.TestGUI/frmFilesystem.Designer.vb
+++ b/GUIs.Test.TestGUI/frmFilesystem.Designer.vb
@@ -23,28 +23,141 @@ Partial Class frmFilesystem
_
Private Sub InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button()
+ Me.Button2 = New System.Windows.Forms.Button()
+ Me.GroupBox1 = New System.Windows.Forms.GroupBox()
+ Me.Button3 = New System.Windows.Forms.Button()
+ Me.TextBox1 = New System.Windows.Forms.TextBox()
+ Me.SaveFileDialog1 = New System.Windows.Forms.SaveFileDialog()
+ Me.txtServiceAddress = New DevExpress.XtraEditors.TextEdit()
+ Me.Label1 = New System.Windows.Forms.Label()
+ Me.txtServicePort = New DevExpress.XtraEditors.TextEdit()
+ Me.Button4 = New System.Windows.Forms.Button()
+ Me.txtStatus = New System.Windows.Forms.TextBox()
+ Me.GroupBox1.SuspendLayout()
+ CType(Me.txtServiceAddress.Properties, System.ComponentModel.ISupportInitialize).BeginInit()
+ CType(Me.txtServicePort.Properties, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
'Button1
'
- Me.Button1.Location = New System.Drawing.Point(12, 12)
+ Me.Button1.Location = New System.Drawing.Point(59, 343)
Me.Button1.Name = "Button1"
- Me.Button1.Size = New System.Drawing.Size(75, 23)
+ Me.Button1.Size = New System.Drawing.Size(288, 23)
Me.Button1.TabIndex = 0
- Me.Button1.Text = "Button1"
+ Me.Button1.Text = "CreateDateDirectory"
Me.Button1.UseVisualStyleBackColor = True
'
+ 'Button2
+ '
+ Me.Button2.Location = New System.Drawing.Point(6, 71)
+ Me.Button2.Name = "Button2"
+ Me.Button2.Size = New System.Drawing.Size(288, 23)
+ Me.Button2.TabIndex = 1
+ Me.Button2.Text = "Stream simple file"
+ Me.Button2.UseVisualStyleBackColor = True
+ '
+ 'GroupBox1
+ '
+ Me.GroupBox1.Controls.Add(Me.Button3)
+ Me.GroupBox1.Controls.Add(Me.TextBox1)
+ Me.GroupBox1.Controls.Add(Me.Button2)
+ Me.GroupBox1.Location = New System.Drawing.Point(36, 153)
+ Me.GroupBox1.Name = "GroupBox1"
+ Me.GroupBox1.Size = New System.Drawing.Size(709, 157)
+ Me.GroupBox1.TabIndex = 2
+ Me.GroupBox1.TabStop = False
+ Me.GroupBox1.Text = "Stream simple file"
+ '
+ 'Button3
+ '
+ Me.Button3.Location = New System.Drawing.Point(6, 19)
+ Me.Button3.Name = "Button3"
+ Me.Button3.Size = New System.Drawing.Size(181, 23)
+ Me.Button3.TabIndex = 3
+ Me.Button3.Text = "1. Choose file"
+ Me.Button3.UseVisualStyleBackColor = True
+ '
+ 'TextBox1
+ '
+ Me.TextBox1.Location = New System.Drawing.Point(6, 45)
+ Me.TextBox1.Name = "TextBox1"
+ Me.TextBox1.Size = New System.Drawing.Size(669, 20)
+ Me.TextBox1.TabIndex = 2
+ '
+ 'txtServiceAddress
+ '
+ Me.txtServiceAddress.Location = New System.Drawing.Point(36, 37)
+ Me.txtServiceAddress.Name = "txtServiceAddress"
+ Me.txtServiceAddress.Size = New System.Drawing.Size(485, 20)
+ Me.txtServiceAddress.TabIndex = 5
+ '
+ 'Label1
+ '
+ Me.Label1.AutoSize = True
+ Me.Label1.Location = New System.Drawing.Point(33, 21)
+ Me.Label1.Name = "Label1"
+ Me.Label1.Size = New System.Drawing.Size(81, 13)
+ Me.Label1.TabIndex = 6
+ Me.Label1.Text = "ServiceAdresse"
+ '
+ 'txtServicePort
+ '
+ Me.txtServicePort.EditValue = New Decimal(New Integer() {9000, 0, 0, 0})
+ Me.txtServicePort.Location = New System.Drawing.Point(36, 63)
+ Me.txtServicePort.Name = "txtServicePort"
+ Me.txtServicePort.Properties.EditValueChangedFiringMode = DevExpress.XtraEditors.Controls.EditValueChangedFiringMode.Buffered
+ Me.txtServicePort.Properties.MaskSettings.Set("MaskManagerType", GetType(DevExpress.Data.Mask.NumericMaskManager))
+ Me.txtServicePort.Size = New System.Drawing.Size(485, 20)
+ Me.txtServicePort.TabIndex = 7
+ '
+ 'Button4
+ '
+ Me.Button4.Location = New System.Drawing.Point(36, 89)
+ Me.Button4.Name = "Button4"
+ Me.Button4.Size = New System.Drawing.Size(75, 23)
+ Me.Button4.TabIndex = 8
+ Me.Button4.Text = "Connect"
+ Me.Button4.UseVisualStyleBackColor = True
+ '
+ 'txtStatus
+ '
+ Me.txtStatus.Location = New System.Drawing.Point(527, 37)
+ Me.txtStatus.Name = "txtStatus"
+ Me.txtStatus.Size = New System.Drawing.Size(100, 20)
+ Me.txtStatus.TabIndex = 9
+ '
'frmFilesystem
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(800, 450)
+ Me.Controls.Add(Me.txtStatus)
+ Me.Controls.Add(Me.Button4)
+ Me.Controls.Add(Me.txtServicePort)
+ Me.Controls.Add(Me.Label1)
+ Me.Controls.Add(Me.txtServiceAddress)
+ Me.Controls.Add(Me.GroupBox1)
Me.Controls.Add(Me.Button1)
Me.Name = "frmFilesystem"
Me.Text = "frmFilesystem"
+ Me.GroupBox1.ResumeLayout(False)
+ Me.GroupBox1.PerformLayout()
+ CType(Me.txtServiceAddress.Properties, System.ComponentModel.ISupportInitialize).EndInit()
+ CType(Me.txtServicePort.Properties, System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
+ Me.PerformLayout()
End Sub
Friend WithEvents Button1 As Button
+ Friend WithEvents Button2 As Button
+ Friend WithEvents GroupBox1 As GroupBox
+ Friend WithEvents Button3 As Button
+ Friend WithEvents TextBox1 As TextBox
+ Friend WithEvents SaveFileDialog1 As SaveFileDialog
+ Friend WithEvents txtServiceAddress As DevExpress.XtraEditors.TextEdit
+ Friend WithEvents Label1 As Label
+ Friend WithEvents txtServicePort As DevExpress.XtraEditors.TextEdit
+ Friend WithEvents Button4 As Button
+ Friend WithEvents txtStatus As TextBox
End Class
diff --git a/GUIs.Test.TestGUI/frmFilesystem.resx b/GUIs.Test.TestGUI/frmFilesystem.resx
index 1af7de15..4008a9ee 100644
--- a/GUIs.Test.TestGUI/frmFilesystem.resx
+++ b/GUIs.Test.TestGUI/frmFilesystem.resx
@@ -117,4 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ 17, 17
+
\ No newline at end of file
diff --git a/GUIs.Test.TestGUI/frmFilesystem.vb b/GUIs.Test.TestGUI/frmFilesystem.vb
index ad4cfa91..b352ebbb 100644
--- a/GUIs.Test.TestGUI/frmFilesystem.vb
+++ b/GUIs.Test.TestGUI/frmFilesystem.vb
@@ -1,8 +1,29 @@
-Imports DigitalData.Modules.Logging
+Imports System.Collections.Generic
+Imports System.IO
+Imports System.Numerics ' Verweis auf System.Numerics assembly hinzufügen!
+Imports System.Security.Cryptography
+Imports DigitalData.GUIs.Common
+Imports DigitalData.Modules.Base.IDB.Constants
+Imports DigitalData.Modules.Database
+Imports DigitalData.Modules.EDMI.API
+Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
+Imports DigitalData.Modules.Logging
+Imports DigitalData.Modules.ZooFlow.State
Public Class frmFilesystem
+ Private Client As Client
+ Private Logger As Logger
+
+ Private Const STATUS_CONNECTED = "Connection Established"
+ Private Const STATUS_CONNECTING = "Trying to create connection..."
+ Private Const STATUS_FAILED = "Connection Failed!"
+
+ Private ConnectionChanged As Boolean = False
+
+ Public Property ServiceAddress As String = ""
+ Public Property ServiceOnline As Boolean = False
Private LogConfig As LogConfig
- Private Filesystem As DigitalData.Modules.Filesystem.File
+ Private MYDD_Filesystem As DigitalData.Modules.Filesystem.File
Private ShortName As String = "E:\some_test_file.txt"
Private LongName As String = "E:\some_test_file_with_some_more_data_and_with_some_more_data_and_with_some_more_data_and_with_some_more_data_and_with_some_more_data_and_with_some_more_data_and_with_some_more_data_and_with_some_more_data_and_with_some_more_data_and_with_some_more.txt"
@@ -10,7 +31,8 @@ Public Class frmFilesystem
Private Sub frmFilesystem_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
LogConfig = New LogConfig(LogConfig.PathType.Temp)
- Filesystem = New DigitalData.Modules.Filesystem.File(LogConfig)
+ Logger = LogConfig.GetLogger()
+ MYDD_Filesystem = New DigitalData.Modules.Filesystem.File(LogConfig)
'Using oWriter = IO.File.CreateText("E:\some_test_file.txt")
@@ -34,6 +56,138 @@ Public Class frmFilesystem
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
- Dim oDateString = Filesystem.CreateDateDirectory("E:\")
+ Dim oDateString = MYDD_Filesystem.CreateDateDirectory("E:\")
+ End Sub
+
+ Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
+ If SaveFileDialog1.ShowDialog = DialogResult.OK Then
+ ' Fallback: einfache Textdatei schreiben
+ System.IO.File.WriteAllText(SaveFileDialog1.FileName, "Some text data")
+ End If
+ End Sub
+
+ Private Async Function Button2_ClickAsync(sender As Object, e As EventArgs) As Task Handles Button2.Click
+ ' Import a file via EDMI Globix ImportFile API to test Service.EDMIService ImportFileMethod
+ Try
+ If Client Is Nothing OrElse ServiceOnline = False Then
+ MsgBox("Bitte zuerst Verbindung zum EDMI Service herstellen.", MsgBoxStyle.Exclamation, Text)
+ Return
+ End If
+
+ Using ofd As New OpenFileDialog()
+ ofd.Title = "Datei für Import wählen"
+ ofd.Filter = "Alle Dateien (*.*)|*.*"
+ If ofd.ShowDialog() <> DialogResult.OK Then
+ Return
+ End If
+
+ Dim oFilePath = ofd.FileName
+ Dim fi As New FileInfo(oFilePath)
+ Dim fileBytes As Byte() = IO.File.ReadAllBytes(oFilePath)
+
+ ' Basic user context for testing
+ Dim user As New DigitalData.Modules.ZooFlow.State.UserState() With {
+ .UserName = Environment.UserName,
+ .Language = "de-DE",
+ .LanguageId = 1031
+ }
+
+ Dim oObjectStore As String = "SelectedDocType.ObjectStore"
+ Dim oIDBDoctypeId As Long = 1
+ Dim oObjectKind As String = "DOC"
+ Dim oProfileId As Integer = 1
+ Dim oAttributes As List(Of UserAttributeValue) = Nothing
+ Dim oOptions As New Options.ImportFileOptions
+
+ Logger.Debug("FilePath: [{0}]", oFilePath)
+ Logger.Debug("ObjectStore: [{0}]", oObjectStore)
+ Logger.Debug("ObjectKind: [{0}]", oObjectKind)
+ Logger.Debug("ProfileId: [{0}]", oProfileId)
+ Logger.Debug("IDB DoctypeId: [{0}]", oIDBDoctypeId)
+
+ Logger.Info("Running Import")
+
+ Dim oResult = Await My.Application.Service.Client.Globix_ImportFileAsync(
+ oFilePath, oProfileId, oAttributes, oObjectStore, oObjectKind, oIDBDoctypeId, oOptions)
+
+ Logger.Info("Import result: [{0}]", oResult.OK)
+ Logger.Info("Imported file got ObjectId [{0}]", oResult.ObjectId)
+
+ If oResult.OK Then
+ MsgBox("Alles OK")
+ Else
+ Logger.Warn("Import failed with message: [{0}] and details [{1}]", oResult.ErrorMessage, oResult.ErrorDetails)
+ Dim oMsg As String, oTitle As String
+ If My.Application.User.Language = "de-DE" Then
+ oMsg = $"Die Datei wurde nicht verarbeitet.{vbNewLine}{vbNewLine}Fehler: {oResult.ErrorMessage}"
+ oTitle = "Achtung"
+ Else
+ oMsg = $"Unexpected Error in FileFlow{vbNewLine}{vbNewLine}Fehler: {oResult.ErrorMessage}"
+ oTitle = "Attention"
+ End If
+
+
+ MsgBox("Fehler")
+ End If
+ End Using
+ Catch ex As Exception
+ If Logger IsNot Nothing Then Logger.Error(ex)
+ MsgBox("Fehler beim Datei-Import.", MsgBoxStyle.Critical, Text)
+ End Try
+ End Function
+
+
+ Public Class SecureStorageHandler
+
+
+
+ End Class
+
+ Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
+ Try
+ Dim oIPAddress = txtServiceAddress.Text
+ Dim oPort = Integer.Parse(txtServicePort.Text)
+
+ Client = New Client(LogConfig, oIPAddress, oPort)
+
+ txtStatus.Text = STATUS_CONNECTING
+ Dim oResult = Client.Connect()
+
+ If oResult = True Then
+ ServiceAddress = $"{oIPAddress}:{oPort}"
+ ServiceOnline = True
+ txtStatus.Text = STATUS_CONNECTED
+ My.Application.Service.Client = Client
+ Logger.Debug("Loading client config..")
+ Dim oClientConfig = My.Application.Service.Client.ClientConfig
+ Logger.Debug("Establishing ECM connection..")
+ Dim oECMConnectionString = oClientConfig.ConnectionStringECM
+ My.DatabaseECM = New MSSQLServer(My.LogConfig, oECMConnectionString)
+ Logger.Debug("Establishing IDB connection..")
+ Dim oIDBConnectionString = oClientConfig.ConnectionStringIDB
+ My.DatabaseIDB = New MSSQLServer(My.LogConfig, oIDBConnectionString)
+
+ Logger.Debug("Establishing Database connection with fallback..")
+ My.Database = New DatabaseWithFallback(LogConfig, My.Application.Service.Client, My.DatabaseECM, My.DatabaseIDB)
+ Else
+ ServiceAddress = ""
+ ServiceOnline = True
+ txtStatus.Text = STATUS_FAILED
+ ' TODO: Make a connection test that is as elaborate as this one :D
+ 'Select Case oResult
+ ' Case ClassService.ConnectionTestResult.NotFound
+ ' lblStatus.Text = "Dienst konnte nicht gefunden werden. Bitte überprüfen sie Addresse und Port."
+ ' Case ClassService.ConnectionTestResult.EmptyURI
+ ' lblStatus.Text = "Bitte tragen Sie eine gültige Dienst Adresse ein."
+ ' Case ClassService.ConnectionTestResult.Authentication
+ ' lblStatus.Text = "Authentifizierungsfehler. Prüfen Sie, ob sich Ihr Gerät in der korrekten Domäne befindet."
+ ' Case Else
+ ' lblStatus.Text = "Unbekannter Fehler."
+ 'End Select
+ End If
+ Catch ex As Exception
+ If Logger IsNot Nothing Then Logger.Error(ex)
+ MsgBox("Fehler beim Verbindungsaufbau", MsgBoxStyle.Critical, Text)
+ End Try
End Sub
End Class
\ No newline at end of file
diff --git a/Service.EDMIService/EDMIService.vbproj b/Service.EDMIService/EDMIService.vbproj
index 5edf3300..1c749f52 100644
--- a/Service.EDMIService/EDMIService.vbproj
+++ b/Service.EDMIService/EDMIService.vbproj
@@ -226,6 +226,7 @@
+
Component
diff --git a/Service.EDMIService/Methods/IDB/GetFileObject/GetFileObjectMethod.vb b/Service.EDMIService/Methods/IDB/GetFileObject/GetFileObjectMethod.vb
index 9b735d52..613c68c2 100644
--- a/Service.EDMIService/Methods/IDB/GetFileObject/GetFileObjectMethod.vb
+++ b/Service.EDMIService/Methods/IDB/GetFileObject/GetFileObjectMethod.vb
@@ -2,6 +2,7 @@
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Imports System.IO
+Imports DigitalData.Services.EDMIService.Security
Namespace Methods.IDB.GetFileObject
Public Class GetFileObjectMethod
@@ -69,6 +70,29 @@ Namespace Methods.IDB.GetFileObject
End Function
Private Function LoadFileContents(pFilePath As String) As Byte()
+ Try
+ Dim password = Environment.GetEnvironmentVariable("DD_FILE_ENCRYPTION_PASSWORD")
+ If String.IsNullOrWhiteSpace(password) Then
+ Logger.Warn("No encryption password set (DD_FILE_ENCRYPTION_PASSWORD). Attempting legacy plain read for file [{0}]", pFilePath)
+ Return ReadPlain(pFilePath)
+ End If
+
+ Try
+ ' Try decrypt first (preferred path)
+ Logger.Debug("Attempting AES decrypt for file [{0}]", pFilePath)
+ Return SecureFileHandler.DecryptFileToBytes(pFilePath, password)
+ Catch exDec As Exception
+ Logger.Warn("Decrypt failed for file [{0}]. Falling back to plain read. Reason: {1}", pFilePath, exDec.Message)
+ Logger.Error(exDec)
+ Return ReadPlain(pFilePath)
+ End Try
+
+ Catch ex As Exception
+ Logger.Error(ex)
+ Return Nothing
+ End Try
+ End Function
+ Private Function LoadFileContents_Old(pFilePath As String) As Byte()
Try
Using oFileStream As New FileStream(pFilePath, FileMode.Open, FileAccess.Read)
Using oMemoryStream As New MemoryStream()
@@ -85,6 +109,15 @@ Namespace Methods.IDB.GetFileObject
End Try
End Function
+
+ Private Function ReadPlain(pFilePath As String) As Byte()
+ Using oFileStream As New FileStream(pFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)
+ Using oMemoryStream As New MemoryStream()
+ oFileStream.CopyTo(oMemoryStream)
+ Return oMemoryStream.ToArray()
+ End Using
+ End Using
+ End Function
End Class
End Namespace
\ No newline at end of file
diff --git a/Service.EDMIService/Methods/IDB/NewFile/NewFileMethod.vb b/Service.EDMIService/Methods/IDB/NewFile/NewFileMethod.vb
index 98fe1a49..9c38046a 100644
--- a/Service.EDMIService/Methods/IDB/NewFile/NewFileMethod.vb
+++ b/Service.EDMIService/Methods/IDB/NewFile/NewFileMethod.vb
@@ -3,6 +3,7 @@ Imports DigitalData.Modules.Base.IDB.Constants
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Database.MSSQLServer.TransactionMode
Imports DigitalData.Modules.Logging
+Imports DigitalData.Services.EDMIService.Security
Namespace Methods.IDB.NewFile
Public Class NewFileMethod
@@ -22,6 +23,197 @@ Namespace Methods.IDB.NewFile
Logger.Debug("Running [NewFileMethod].")
Dim oFilePath As String = Nothing
+ Try
+ If pData.File Is Nothing Then
+ Throw New ArgumentNullException(NameOf(pData.File))
+ End If
+
+ If pData.KindType Is Nothing Then
+ Throw New ArgumentNullException(NameOf(pData.KindType))
+ End If
+
+ If pData.StoreName Is Nothing Then
+ Throw New ArgumentNullException(NameOf(pData.StoreName))
+ End If
+
+ If pData.User Is Nothing Then
+ Throw New ArgumentNullException(NameOf(pData.User))
+ End If
+
+ If IsNothing(pData.IDBDoctypeId) Then
+ Throw New ArgumentNullException(NameOf(pData.IDBDoctypeId))
+ End If
+
+ Logger.Debug("Checking if checksum already exists..")
+ Dim oExistingObjectId = Helpers.TestFileChecksumExists(pData.File.FileChecksum)
+ If oExistingObjectId > 0 Then
+ Return New NewFileResponse(oExistingObjectId)
+ End If
+
+ Logger.Debug("Creating New ObjectId..")
+ Dim oObjectId = Helpers.NewObjectIdWithTransaction(pData.KindType, pData.User.UserName, Connection, Transaction)
+ If oObjectId = 0 Then
+ LogAndThrow("Could not create new ObjectId!")
+ End If
+ Logger.Debug("New ObjectId [{0}] created!", oObjectId)
+
+ ' Find ObjectStore by Title
+ Logger.Debug("Checking for DataStore [{0}].", pData.StoreName)
+ Dim oStore = GlobalState.ObjectStores.
+ Where(Function(store) store.Title = pData.StoreName).
+ SingleOrDefault()
+
+ If oStore Is Nothing Then
+ LogAndThrow($"DataStore [{pData.StoreName}] does not exist. Exiting.")
+ End If
+ Logger.Debug("Using DataStore [{0}].", pData.StoreName)
+
+ ' Get Store base and final path
+ Logger.Debug("Store BasePath is [{0}]", oStore.Path)
+ Dim oFinalPath = Helpers.GetFileObjectPath(oStore, pData.File.FileImportedAt)
+
+ ' Ensure target directory exists
+ Try
+ If Not IO.Directory.Exists(oFinalPath) Then
+ IO.Directory.CreateDirectory(oFinalPath)
+ End If
+ Catch exDir As Exception
+ LogAndThrow(exDir, $"Target directory [{oFinalPath}] could not be created.")
+ End Try
+
+ ' Get filename
+ Dim oKeepFileName As Boolean = False
+ If oStore.IsArchive Then
+ Logger.Debug("Object Store is an archive: [{0}]", oStore.IsArchive)
+ oKeepFileName = True
+ End If
+
+ Dim oFileName As String = GetFileObjectFileName(oObjectId, pData.File.FileName, oKeepFileName)
+ Logger.Debug("Filename is [{0}]", oFileName)
+
+ oFilePath = IO.Path.Combine(oFinalPath, oFileName)
+ Dim oFileObjectInfo As IO.FileInfo = New IO.FileInfo(oFilePath)
+
+ Dim oFileObjectName As String = oFileObjectInfo.Name
+ Logger.Debug("File Information for [{0}]:", oFileObjectName)
+
+ Dim oFileObjectSize As Long = pData.File.FileContents.Length ' original (plaintext) size
+ Logger.Debug("Original Size: [{0}]", oFileObjectSize)
+
+ Dim oOriginalExtension As String = pData.File.FileInfoRaw.Extension.Substring(1)
+ Logger.Debug("Original Extension: [{0}]", oOriginalExtension)
+
+ Logger.Debug("Checksum: [{0}]", pData.File.FileChecksum)
+
+ ' Retrieve encryption password (environment variable)
+ Dim encryptionPassword As String = Environment.GetEnvironmentVariable("DD_FILE_ENCRYPTION_PASSWORD")
+ If String.IsNullOrWhiteSpace(encryptionPassword) Then
+ LogAndThrow("Encryption password not configured (env DD_FILE_ENCRYPTION_PASSWORD).")
+ End If
+
+ ' Perform encryption with strict failure handling
+ Try
+ Logger.Info("Encrypting and saving file to path [{0}]", oFilePath)
+ SecureFileHandler.EncryptFileFromBytes(pData.File.FileContents, oFilePath, encryptionPassword)
+ Catch exEnc As Exception
+ LogAndThrow(exEnc, $"Could not encrypt/write file [{oFilePath}] to disk!")
+ End Try
+
+ ' Post-encryption validation: file must exist and contain at least header bytes
+ Try
+ Dim fi As New IO.FileInfo(oFilePath)
+ If Not fi.Exists Then
+ LogAndThrow($"Encrypted file was not created at [{oFilePath}].")
+ End If
+ ' Minimum file size:1 (version) +4 (iterations) +32 (salt) =37 bytes
+ If fi.Length < 37 Then
+ LogAndThrow($"Encrypted file at [{oFilePath}] is invalid or truncated (size {fi.Length}).")
+ End If
+ Logger.Debug("Encrypted physical file size: [{0}]", fi.Length)
+ Catch exVal As Exception
+ ' LogAndThrow above will throw; any other IO errors should also abort here
+ LogAndThrow(exVal, "Encrypted file validation failed.")
+ End Try
+
+ '---------------------------------------------------------------------------
+
+ Logger.Info("Creating IDB FileObject for ObjectId [{0}].", oObjectId)
+ ' Insert into DB (store original plaintext size for consistency)
+ Dim oSQL As String = $"EXEC PRIDB_NEW_IDBFO
+ '{oFinalPath}',
+ '{oFileObjectName}',
+ '{oOriginalExtension}',
+ {oFileObjectSize},
+ '{pData.File.FileChecksum}' ,
+ '{pData.User.UserName}',
+ '{oObjectId}',
+ {oStore.Id},
+ {pData.IDBDoctypeId}"
+
+ Dim oResult As Boolean = DatabaseIDB.ExecuteNonQueryWithConnectionObject(oSQL, Connection, ExternalTransaction, Transaction)
+
+ If oResult = False Then
+ LogAndThrow("IDB FileObject could not be created!")
+ End If
+
+ '---------------------------------------------------------------------------
+
+ Dim oSystemAttributes As New Dictionary(Of String, Object) From {
+ {Attributes.ATTRIBUTE_ORIGIN_FILENAME, pData.File.FileName},
+ {Attributes.ATTRIBUTE_ORIGIN_CREATED, pData.File.FileCreatedAt},
+ {Attributes.ATTRIBUTE_ORIGIN_CHANGED, pData.File.FileChangedAt}
+ }
+
+ For Each oAttribute As KeyValuePair(Of String, Object) In oSystemAttributes
+ Try
+ ' Dont write empty attributes
+ If oAttribute.Value Is Nothing Then
+ Continue For
+ End If
+
+ Dim oSuccess = Helpers.SetAttributeValueWithTransaction(Connection, Transaction, oObjectId, oAttribute.Key, oAttribute.Value, pData.User.Language, pData.User.UserName)
+ If oSuccess Then
+ Logger.Debug("System Attribute [{0}] written with value [{1}]", oAttribute.Key, oAttribute.Value)
+ Else
+ Logger.Warn("System attribute value could not be written")
+ End If
+ Catch ex As Exception
+ LogAndThrow(ex, $"System attribute [{oAttribute.Key}] could not be written!")
+ End Try
+ Next
+
+ '---------------------------------------------------------------------------
+
+ ' Finally, commit the transaction
+ Transaction?.Commit()
+
+ Return New NewFileResponse(oObjectId)
+
+ Catch ex As Exception
+ Logger.Warn("Error occurred while creating file!")
+ Logger.Error(ex)
+
+ Logger.Info("Cleaning up files.")
+ If Not IsNothing(oFilePath) AndAlso IO.File.Exists(oFilePath) Then
+ Try
+ IO.File.Delete(oFilePath)
+ Catch exInner As Exception
+ Logger.Warn("Error while cleaning up files.")
+ Logger.Error(exInner)
+ End Try
+ End If
+
+ Logger.Info("Rolling back transaction.")
+ Transaction?.Rollback()
+
+ Return New NewFileResponse(ex)
+
+ End Try
+ End Function
+ Public Function Run_Old(pData As NewFileRequest) As NewFileResponse
+ Logger.Debug("Running [NewFileMethod Old].")
+ Dim oFilePath As String = Nothing
+
Try
If pData.File Is Nothing Then
Throw New ArgumentNullException(NameOf(pData.File))
@@ -181,7 +373,6 @@ Namespace Methods.IDB.NewFile
End Try
End Function
-
Private Function GetFileObjectFileName(IDB_OBJ_ID As Long, pFilename As String, pKeepFilename As Boolean) As String
' TODO: save actual extensions
If pKeepFilename Then
diff --git a/Service.EDMIService/Security/SecureFileHandler.vb b/Service.EDMIService/Security/SecureFileHandler.vb
new file mode 100644
index 00000000..cc4f470f
--- /dev/null
+++ b/Service.EDMIService/Security/SecureFileHandler.vb
@@ -0,0 +1,146 @@
+Imports System.IO
+Imports System.Security.Cryptography
+
+Namespace Security
+ '''
+ ''' Provides secure AES file encryption and decryption using PBKDF2 (Rfc2898DeriveBytes) for key derivation.
+ ''' File format:
+ ''' [1 byte Version][4 bytes IterationCount (Int32, big-endian)][32 bytes Salt][Encrypted Payload]
+ '''
+ Public NotInheritable Class SecureFileHandler
+ Private Sub New()
+ End Sub
+
+ Private Const CURRENT_VERSION As Byte = 1
+ Private Const SALT_LENGTH As Integer = 32
+ Private Const KEY_SIZE_BYTES As Integer = 32 ' AES-256
+ Private Const IV_SIZE_BYTES As Integer = 16 ' AES Block size (128 bit)
+ Private Const DEFAULT_ITERATIONS As Integer = 100000
+ Private Const BUFFER_SIZE As Integer = 81920 '80KB streaming buffer
+
+ '''
+ ''' Encrypts the provided byte array and writes an encrypted file to the target path using streaming.
+ '''
+ Public Shared Sub EncryptFileFromBytes(sourceData() As Byte, targetFilePath As String, password As String, Optional iterations As Integer = DEFAULT_ITERATIONS)
+ If sourceData Is Nothing Then Throw New ArgumentNullException(NameOf(sourceData))
+ If String.IsNullOrWhiteSpace(password) Then Throw New ArgumentNullException(NameOf(password))
+ Using fsOut = New FileStream(targetFilePath, FileMode.Create, FileAccess.Write, FileShare.None)
+ Dim salt = GenerateRandomBytes(SALT_LENGTH)
+
+ ' Write header: Version, Iterations, Salt
+ fsOut.WriteByte(CURRENT_VERSION)
+ WriteInt32BigEndian(fsOut, iterations)
+ fsOut.Write(salt, 0, salt.Length)
+
+ Using keyDerivation = New Rfc2898DeriveBytes(password, salt, iterations)
+ Dim key = keyDerivation.GetBytes(KEY_SIZE_BYTES)
+ Dim iv = keyDerivation.GetBytes(IV_SIZE_BYTES)
+
+ Dim aesAlg As System.Security.Cryptography.Aes = System.Security.Cryptography.Aes.Create()
+ Try
+ aesAlg.KeySize = KEY_SIZE_BYTES * 8
+ aesAlg.BlockSize = IV_SIZE_BYTES * 8
+ aesAlg.Mode = CipherMode.CBC
+ aesAlg.Padding = PaddingMode.PKCS7
+ aesAlg.Key = key
+ aesAlg.IV = iv
+
+ Using crypto = aesAlg.CreateEncryptor()
+ Using cs = New CryptoStream(fsOut, crypto, CryptoStreamMode.Write)
+ Using msIn = New MemoryStream(sourceData, writable:=False)
+ Dim buffer(BUFFER_SIZE - 1) As Byte
+ Dim read As Integer
+ Do
+ read = msIn.Read(buffer, 0, buffer.Length)
+ If read <= 0 Then Exit Do
+ cs.Write(buffer, 0, read)
+ Loop
+ End Using
+ cs.FlushFinalBlock()
+ End Using
+ End Using
+ Finally
+ aesAlg.Dispose()
+ End Try
+ End Using
+ End Using
+ End Sub
+
+ '''
+ ''' Decrypts the encrypted file and returns the plaintext bytes.
+ '''
+ Public Shared Function DecryptFileToBytes(encryptedFilePath As String, password As String) As Byte()
+ If String.IsNullOrWhiteSpace(encryptedFilePath) Then Throw New ArgumentNullException(NameOf(encryptedFilePath))
+ If String.IsNullOrWhiteSpace(password) Then Throw New ArgumentNullException(NameOf(password))
+ Using fsIn = New FileStream(encryptedFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)
+ Dim version = CByte(fsIn.ReadByte())
+ If version <> CURRENT_VERSION Then Throw New InvalidDataException("Unsupported file version.")
+ Dim iterations = ReadInt32BigEndian(fsIn)
+ Dim salt = New Byte(SALT_LENGTH - 1) {}
+ ReadExact(fsIn, salt, 0, salt.Length)
+
+ Using keyDerivation = New Rfc2898DeriveBytes(password, salt, iterations)
+ Dim key = keyDerivation.GetBytes(KEY_SIZE_BYTES)
+ Dim iv = keyDerivation.GetBytes(IV_SIZE_BYTES)
+
+ Dim aesAlg As System.Security.Cryptography.Aes = System.Security.Cryptography.Aes.Create()
+ Try
+ aesAlg.KeySize = KEY_SIZE_BYTES * 8
+ aesAlg.BlockSize = IV_SIZE_BYTES * 8
+ aesAlg.Mode = CipherMode.CBC
+ aesAlg.Padding = PaddingMode.PKCS7
+ aesAlg.Key = key
+ aesAlg.IV = iv
+
+ Using crypto = aesAlg.CreateDecryptor()
+ Using cs = New CryptoStream(fsIn, crypto, CryptoStreamMode.Read)
+ Using msOut = New MemoryStream()
+ Dim buffer(BUFFER_SIZE - 1) As Byte
+ Dim read As Integer
+ Do
+ read = cs.Read(buffer, 0, buffer.Length)
+ If read <= 0 Then Exit Do
+ msOut.Write(buffer, 0, read)
+ Loop
+ Return msOut.ToArray()
+ End Using
+ End Using
+ End Using
+ Finally
+ aesAlg.Dispose()
+ End Try
+ End Using
+ End Using
+ End Function
+
+ Private Shared Function GenerateRandomBytes(length As Integer) As Byte()
+ Dim data = New Byte(length - 1) {}
+ Using rng = RandomNumberGenerator.Create()
+ rng.GetBytes(data)
+ End Using
+ Return data
+ End Function
+
+ Private Shared Sub WriteInt32BigEndian(stream As Stream, value As Integer)
+ Dim bytes = BitConverter.GetBytes(value)
+ If BitConverter.IsLittleEndian Then Array.Reverse(bytes)
+ stream.Write(bytes, 0, bytes.Length)
+ End Sub
+
+ Private Shared Function ReadInt32BigEndian(stream As Stream) As Integer
+ Dim bytes = New Byte(3) {}
+ ReadExact(stream, bytes, 0, 4)
+ If BitConverter.IsLittleEndian Then Array.Reverse(bytes)
+ Return BitConverter.ToInt32(bytes, 0)
+ End Function
+
+ Private Shared Sub ReadExact(stream As Stream, buffer As Byte(), offset As Integer, count As Integer)
+ Dim totalRead As Integer = 0
+ While totalRead < count
+ Dim read = stream.Read(buffer, offset + totalRead, count - totalRead)
+ If read <= 0 Then Throw New EndOfStreamException("Unexpected end of stream.")
+ totalRead += read
+ End While
+ End Sub
+ End Class
+End Namespace