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())
'''
''' Eindeutiges Drag-Format für DocID-Transfers zwischen frmNodeNavigation-Instanzen.
''' Muss mit frmNodeNavigation.DRAGDROP_FORMAT_DOCID identisch sein.
'''
Public Shared ReadOnly DRAGDROP_FORMAT_DOCID As String = "DD_RecordOrganizer_DocID"
'''
''' Zeichen, die im Dateinamen Probleme bei DB-Import und Dateihandling verursachen können.
'''
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
'''
''' Hängt eine Datei an files_dropped an – mit vorheriger Sonderzeichen-Prüfung.
''' Gibt False zurück wenn der Dateiname ungültig ist.
'''
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