Files
RecordOrganizer/app/DD-Record-Organizer/Classes/ClassDragDrop.vb
2026-03-24 12:42:53 +01:00

429 lines
22 KiB
VB.net
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Imports System.IO
Imports Microsoft.Office.Interop
Imports Microsoft.Office.Interop.Outlook
Public Class ClassDragDrop
Public Shared files_dropped As String()
Public Shared Event FilesDroppedReady(ByVal files As String())
''' <summary>
''' Eindeutiges Drag-Format für DocID-Transfers zwischen frmNodeNavigation-Instanzen.
''' Muss mit frmNodeNavigation.DRAGDROP_FORMAT_DOCID identisch sein.
''' </summary>
Public Shared ReadOnly DRAGDROP_FORMAT_DOCID As String = "DD_RecordOrganizer_DocID"
''' <summary>
''' Zeichen, die im Dateinamen Probleme bei DB-Import und Dateihandling verursachen können.
''' </summary>
Private Shared ReadOnly ProblematicChars As Char() = {
"'"c, "`"c, ";"c, "%"c, "&"c, "+"c, "#"c, "~"c,
"{"c, "}"c, "["c, "]"c, "^"c, "="c, "@"c
}
Private Shared Function CheckAndSanitizeFilename(filePath As String) As String
Try
Dim dir As String = Path.GetDirectoryName(filePath)
Dim originalName As String = Path.GetFileNameWithoutExtension(filePath)
Dim ext As String = Path.GetExtension(filePath)
' ── 1) Unicode-Normalisierung NFD → NFC ──────────────────────────────
Dim normalizedName As String = originalName.Normalize(System.Text.NormalizationForm.FormC)
Dim hadNormalizationIssue As Boolean = (normalizedName <> originalName)
If hadNormalizationIssue Then
LOGGER?.Warn($"CheckAndSanitizeFilename: NFD-Encoding erkannt in [{originalName}{ext}]")
Dim normMsg As String
If USER_LANGUAGE <> "de-DE" Then
normMsg = $"The filename contains Unicode characters in decomposed form (NFD encoding)." &
vbCrLf & vbCrLf &
$"File: {originalName}{ext}" & vbCrLf & vbCrLf &
"This causes garbled characters in the database (e.g. ü → Ru¨ckbau)." & vbCrLf & vbCrLf &
"Please rename the file and try again." & vbCrLf &
"The import of this file has been aborted."
Else
normMsg = $"Der Dateiname enthält nicht sichtbare Unicode-Zeichen in dekomponiierter Form (NFD-Kodierung)." &
vbCrLf & vbCrLf &
$"Datei: {originalName}{ext}" & vbCrLf & vbCrLf &
"Dies kann zu kryptischen Zeichen in der Datenbank (z.B. ü → Ru¨ckbau) oder Problemen beim Import nach windream führen." & vbCrLf & vbCrLf &
"Ursache dafür kann sein, das die Datei aus einer NICHT Windows Umgebung erstellt wurde. (MacOS, Linux etc)" & vbCrLf &
"Bitte benennen Sie die Datei um und versuchen Sie es erneut." & vbCrLf &
"Der Import dieser Datei wurde abgebrochen."
End If
Dim normCaption As String = If(USER_LANGUAGE <> "de-DE", "Invalid Filename", "Ungültiger Dateiname")
MessageBox.Show(normMsg, normCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning)
LOGGER?.Warn($"CheckAndSanitizeFilename: Import abgebrochen wegen NFD-Problem [{originalName}{ext}].")
Return Nothing
End If
' ── 2) Leerzeichen-Probleme prüfen (führend, abschließend, doppelt) ──
Dim hasLeadingOrTrailingSpace As Boolean = (originalName <> originalName.Trim())
Dim hasDoubleSpace As Boolean = originalName.Contains(" ") ' zwei aufeinanderfolgende Leerzeichen
If hasLeadingOrTrailingSpace OrElse hasDoubleSpace Then
LOGGER?.Warn($"CheckAndSanitizeFilename: Leerzeichen-Problem in [{originalName}{ext}]")
Dim spaceMsg As String
If USER_LANGUAGE <> "de-DE" Then
spaceMsg = $"The filename contains leading, trailing or consecutive spaces:" &
vbCrLf & vbCrLf &
$"File: ""{originalName}{ext}""" & vbCrLf & vbCrLf &
"This can cause problems during database import or file comparisons." & vbCrLf & vbCrLf &
"Please rename the file (remove extra spaces) and try again." & vbCrLf &
"The import of this file has been aborted."
Else
spaceMsg = $"Der Dateiname enthält führende, abschließende oder doppelte Leerzeichen:" &
vbCrLf & vbCrLf &
$"Datei: ""{originalName}{ext}""" & vbCrLf & vbCrLf &
"Dies kann beim Datenbankimport oder Dateivergleichen zu Problemen führen." & vbCrLf & vbCrLf &
"Bitte benennen Sie die Datei um (Leerzeichen entfernen) und versuchen Sie es erneut." & vbCrLf &
"Der Import dieser Datei wurde abgebrochen."
End If
Dim spaceCaption As String = If(USER_LANGUAGE <> "de-DE", "Invalid Filename", "Ungültiger Dateiname")
MessageBox.Show(spaceMsg, spaceCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning)
LOGGER?.Warn($"CheckAndSanitizeFilename: Import abgebrochen wegen Leerzeichen-Problem [{originalName}{ext}].")
Return Nothing
End If
' ── 3) Problematische Sonderzeichen prüfen ───────────────────────────
Dim found As New System.Text.StringBuilder()
For Each c As Char In ProblematicChars
If originalName.IndexOf(c) >= 0 Then
If found.Length > 0 Then found.Append(" ")
found.Append($"'{c}'")
End If
Next
If found.Length = 0 Then
Return filePath
End If
LOGGER?.Warn($"CheckAndSanitizeFilename: Problematische Zeichen in [{originalName}{ext}]: {found}")
Dim msg As String
If USER_LANGUAGE <> "de-DE" Then
msg = $"The filename contains characters that cause problems during database import or file handling:" &
vbCrLf & vbCrLf &
$"File: {originalName}{ext}" & vbCrLf &
$"Problematic chars: {found}" & vbCrLf & vbCrLf &
"Please rename the file and try again." & vbCrLf &
"The import of this file has been aborted."
Else
msg = $"Der Dateiname enthält nicht sichtbare Zeichen, die beim Datenbankimport oder späteren Dateihandling in windream Probleme verursachen:" &
vbCrLf & vbCrLf &
$"Datei: {originalName}{ext}" & vbCrLf &
$"Problematische Zeichen: {found}" & vbCrLf & vbCrLf &
"Ursache dafür kann sein, das die Datei aus einer NICHT Windows Umgebung erstellt wurde. (MacOS, Linux etc)" & vbCrLf &
"Bitte benennen Sie die Datei um und versuchen Sie es erneut." & vbCrLf &
"Der Import dieser Datei wurde abgebrochen."
End If
Dim caption As String = If(USER_LANGUAGE <> "de-DE", "Invalid Filename", "Ungültiger Dateiname")
MessageBox.Show(msg, caption, MessageBoxButtons.OK, MessageBoxIcon.Warning)
LOGGER?.Warn($"CheckAndSanitizeFilename: Import abgebrochen für [{originalName}{ext}].")
Return Nothing
Catch ex As System.Exception
LOGGER?.Warn("CheckAndSanitizeFilename Fehler: " & ex.Message)
Return filePath
End Try
End Function
Public Shared Function Drop_File(e As DragEventArgs)
Try
LOGGER.Debug("In Drop_File....")
ClassHelper.DELETE_PMO_FILE_USER_OPEN_FILES()
files_dropped = New String() {}
Dim hasOutlookUnicode As Boolean = e.Data.GetDataPresent("FileGroupDescriptorW")
Dim hasOutlookAnsi As Boolean = e.Data.GetDataPresent("FileGroupDescriptor")
Dim hasOutlookContents As Boolean = e.Data.GetDataPresent("FileContents")
Dim hasChromiumMime As Boolean = e.Data.GetDataPresent("Chromium Web Custom MIME Data Format")
Dim hasFileNameW As Boolean = e.Data.GetDataPresent("FileNameW") OrElse e.Data.GetDataPresent("FileName")
Dim hasFileDrop As Boolean = e.Data.GetDataPresent(DataFormats.FileDrop)
'1) Klassische Outlook-Attachments: Descriptor + Contents
If (hasOutlookUnicode OrElse hasOutlookAnsi) AndAlso hasOutlookContents Then
' ... dein bestehender Descriptor/Contents-Code ...
' Return True wenn erfolgreich
End If
'2) ATTACHMENT oder komplette Mail aus Outlook/WebView2: KEIN Descriptor+Contents, ABER FileDrop vorhanden
If hasFileDrop AndAlso (hasChromiumMime OrElse hasFileNameW) AndAlso Not hasOutlookContents Then
LOGGER?.Debug("WebView2/Outlook Attachment or Mail: try FileDrop, skip Outlook COM initially")
Dim ok As Boolean = HandleFileDrop(e)
If ok Then Return True
LOGGER?.Warn("FileDrop vorhanden, aber leer. Fallback auf Outlook COM für komplette Mail.")
ScheduleOutlookComFallback()
Return True
End If
'3) Outlook Mail (.msg): Descriptor ohne Contents ODER Chromium/WebView2 Indikatoren nur wenn KEIN FileDrop vorhanden
If Not hasFileDrop AndAlso ((hasOutlookAnsi OrElse hasOutlookUnicode) OrElse hasChromiumMime OrElse hasFileNameW) Then
Try
Dim oApp As Outlook.Application = Nothing
Try
oApp = New Outlook.Application()
Catch ex As System.Exception
MsgBox("Fehler beim Initialisieren der Outlook-API:" & vbNewLine & ex.Message, MsgBoxStyle.Critical)
GoTo CheckFileDrop
End Try
Dim explorer = oApp.ActiveExplorer
If explorer IsNot Nothing AndAlso explorer.Selection IsNot Nothing AndAlso explorer.Selection.Count > 0 Then
LOGGER?.Debug("Drop of msg (Outlook Explorer Selection)")
For i As Integer = 1 To explorer.Selection.Count
Dim myobj As Object = explorer.Selection.Item(i)
If myobj Is Nothing Then Continue For
SaveMailItemToTemp(myobj)
Next
Return True
Else
Dim inspector = oApp.ActiveInspector
If inspector IsNot Nothing AndAlso inspector.CurrentItem IsNot Nothing Then
LOGGER?.Debug("Drop of msg (ActiveInspector.CurrentItem) Fallback")
SaveMailItemToTemp(inspector.CurrentItem)
Return True
Else
LOGGER?.Warn("Outlook: Keine Auswahl im Explorer und kein ActiveInspector.CurrentItem verfügbar.")
If hasFileNameW Then
Dim namesObj As Object = e.Data.GetData(If(e.Data.GetDataPresent("FileNameW"), "FileNameW", "FileName"), True)
Dim names As String() = TryCast(namesObj, String())
If names Is Nothing Then
Dim nameSingle As String = TryCast(namesObj, String)
If Not String.IsNullOrWhiteSpace(nameSingle) Then
LOGGER?.Warn("Vorgeschlagener Name (ohne Inhalt): " & nameSingle)
End If
Else
LOGGER?.Warn("Vorgeschlagene Namen (ohne Inhalt): " & String.Join("; ", names))
End If
End If
GoTo CheckFileDrop
End If
End If
Catch ex As System.Exception
LOGGER?.Warn("Outlook MSG-Drop Fehler: " & ex.Message)
End Try
End If
CheckFileDrop:
'4) Filesystem FileDrop (klassisch ODER WebView2 delayed rendering)
If hasFileDrop Then
If HandleFileDrop(e) Then Return True
ScheduleOutlookComFallback()
Return True
End If
'5) SCAN-StringFormat
If e.Data.GetDataPresent(DataFormats.StringFormat) Then
Dim Wert As String = TryCast(e.Data.GetData(DataFormats.StringFormat), String)
If Not String.IsNullOrEmpty(Wert) Then
Dim idx As Integer = files_dropped.Length
ReDim Preserve files_dropped(idx)
files_dropped(idx) = "@SCAN@" & Wert
Return True
End If
End If
Catch ex As System.Exception
MsgBox("Unexpected Error in Drop_File: " & ex.Message, MsgBoxStyle.Critical)
End Try
LOGGER?.Warn("Drop_File: Kein extrahierbarer Inhalt. Bitte Attachment aus der Nachrichtenliste ziehen oder zunächst speichern.")
Return False
End Function
' FileDrop defensiv behandeln erst ohne, dann mit autoConvert
Private Shared Function HandleFileDrop(e As DragEventArgs) As Boolean
Try
Dim rawObj As Object = e.Data.GetData(DataFormats.FileDrop)
Dim rawFiles As String() = TryCast(rawObj, String())
If Not (rawFiles Is Nothing OrElse rawFiles.Length = 0) Then
For Each f In rawFiles
LOGGER?.Info("FileDrop (raw) - File: " & f)
AppendDroppedFile("@DROPFROMFSYSTEM@", f)
Next
Return True
End If
Dim convObj As Object = e.Data.GetData(DataFormats.FileDrop, True)
Dim convFiles As String() = TryCast(convObj, String())
If Not (convFiles Is Nothing OrElse convFiles.Length = 0) Then
For Each f In convFiles
LOGGER?.Info("FileDrop (autoConvert) - File: " & f)
AppendDroppedFile("@DROPFROMFSYSTEM@", f)
Next
Return True
End If
LOGGER?.Warn("FileDrop vorhanden, aber keine Dateien (raw/autoConvert leer).")
Return False
Catch ex As System.Exception
LOGGER?.Warn("HandleFileDrop Fehler: " & ex.Message)
Return False
End Try
End Function
''' <summary>
''' Hängt eine Datei an files_dropped an mit vorheriger Sonderzeichen-Prüfung.
''' Gibt False zurück wenn der Dateiname ungültig ist.
''' </summary>
Private Shared Function AppendDroppedFile(prefix As String, filePath As String) As Boolean
Dim checkedPath As String = CheckAndSanitizeFilename(filePath)
If checkedPath Is Nothing Then
Return False
End If
Dim idx As Integer = files_dropped.Length
ReDim Preserve files_dropped(idx)
files_dropped(idx) = prefix & checkedPath
Return True
End Function
Private Shared Sub SaveMailItemToTemp(ByVal mailObj As Object)
Dim subj As String = ""
Try
subj = mailObj.Subject
Catch
subj = "NO_SUBJECT"
End Try
If String.IsNullOrWhiteSpace(subj) Then subj = "NO_SUBJECT"
Dim safeName = subj.Replace("\", "-").Replace("/", "-").Replace(":", "") _
.Replace("?", "").Replace("!", "").Replace("%", "").Replace("$", "")
Dim strFile As String = IO.Path.Combine(Path.GetTempPath(), safeName & ".msg")
LOGGER?.Info("Drop of msg - File:" & strFile)
Try
mailObj.SaveAs(strFile)
AppendDroppedFile("@OUTLOOK_MESSAGE@", strFile)
Catch ex As System.Exception
MsgBox("Error in Save Email2Tempfile" & vbNewLine & ex.Message, MsgBoxStyle.Critical)
End Try
End Sub
Private Shared Sub ScheduleOutlookComFallback()
Try
Dim t As New Threading.Thread(
Sub()
Try
Threading.Thread.Sleep(200)
Dim maxRetries As Integer = 10
Dim saved As Boolean = False
For attempt As Integer = 1 To maxRetries
If TrySaveSelectedMailViaOutlook() Then
LOGGER?.Info("Outlook COM Fallback: Mail gespeichert. Versuch " & attempt)
saved = True
Exit For
End If
LOGGER?.Debug("Outlook COM Fallback: Keine Auswahl, Retry " & attempt)
Threading.Thread.Sleep(200)
Next
If saved Then
Dim uiForm = If(System.Windows.Forms.Application.OpenForms.Count > 0, System.Windows.Forms.Application.OpenForms(0), Nothing)
If uiForm IsNot Nothing Then
uiForm.BeginInvoke(
Sub()
Try
RaiseEvent FilesDroppedReady(files_dropped)
Catch ex2 As System.Exception
LOGGER?.Warn("FilesDroppedReady Invoke Fehler: " & ex2.Message)
End Try
End Sub)
Else
RaiseEvent FilesDroppedReady(files_dropped)
End If
Else
LOGGER?.Warn("Outlook COM Fallback: Nach Retries keine Mail gespeichert.")
End If
Catch ex As System.Exception
LOGGER?.Warn("Outlook COM Fallback Thread Fehler: " & ex.Message)
End Try
End Sub
)
t.IsBackground = True
t.SetApartmentState(Threading.ApartmentState.STA)
t.Start()
Catch ex As System.Exception
LOGGER?.Warn("ScheduleOutlookComFallback Fehler: " & ex.Message)
End Try
End Sub
Private Shared Function TrySaveSelectedMailViaOutlook() As Boolean
Try
Dim oApp As Outlook.Application = Nothing
Try
oApp = New Outlook.Application()
Catch ex As System.Exception
LOGGER?.Warn("Outlook COM Init fehlgeschlagen: " & ex.Message)
Return False
End Try
Dim savedAny As Boolean = False
Dim inspector = oApp.ActiveInspector
If inspector IsNot Nothing AndAlso inspector.CurrentItem IsNot Nothing Then
LOGGER?.Debug("Fallback: ActiveInspector.CurrentItem speichern")
SaveMailItemToTemp(inspector.CurrentItem)
savedAny = True
End If
If Not savedAny Then
Dim explorer = oApp.ActiveExplorer
If explorer IsNot Nothing AndAlso explorer.Selection IsNot Nothing AndAlso explorer.Selection.Count > 0 Then
LOGGER?.Debug("Fallback: Explorer.Selection speichern")
For i As Integer = 1 To explorer.Selection.Count
Dim myobj As Object = explorer.Selection.Item(i)
If myobj Is Nothing Then Continue For
SaveMailItemToTemp(myobj)
savedAny = True
Next
End If
End If
Return savedAny
Catch ex As System.Exception
LOGGER?.Warn("TrySaveSelectedMailViaOutlook Fehler: " & ex.Message)
Return False
End Try
End Function
Public Shared Sub Drag_enter(e As DragEventArgs)
Try
My.Settings.WD_INDEXDOKART_SAVE = ""
' ✅ DocID-Format hat Vorrang Early Exit
If e.Data.GetDataPresent(DRAGDROP_FORMAT_DOCID) Then
e.Effect = DragDropEffects.Copy
LOGGER?.Debug("DragEnter ... DocID-Format erkannt (Inter-Instance Transfer)")
Return
End If
Dim hasOutlookUnicode As Boolean = e.Data.GetDataPresent("FileGroupDescriptorW")
Dim hasOutlookAnsi As Boolean = e.Data.GetDataPresent("FileGroupDescriptor")
Dim hasOutlookDescriptor As Boolean = hasOutlookUnicode OrElse hasOutlookAnsi
Dim hasChromiumMime As Boolean = e.Data.GetDataPresent("Chromium Web Custom MIME Data Format")
Dim hasFileNameW As Boolean = e.Data.GetDataPresent("FileNameW") OrElse e.Data.GetDataPresent("FileName")
Dim hasOutlookLike As Boolean = hasOutlookDescriptor OrElse hasChromiumMime OrElse hasFileNameW
Dim hasFileDrop As Boolean = e.Data.GetDataPresent(DataFormats.FileDrop)
If hasOutlookLike Then
e.Effect = DragDropEffects.Copy
LOGGER?.Debug("DragEnter ... Outlook/WebView2 erkannt (Descriptor/Chromium/FileNameW)")
ElseIf hasFileDrop Then
e.Effect = DragDropEffects.Copy
LOGGER?.Debug("DragEnter ... SimpleFileDrop")
Else
e.Effect = DragDropEffects.None
LOGGER?.Debug("DragEnter ... Other FileFormat")
End If
LOGGER?.Debug("DragEnter Formats: " & String.Join(", ", e.Data.GetFormats()))
Catch ex As System.Exception
End Try
End Sub
End Class