Backgroundworker Shell wird nicht unterstützt

  • VB.NET
  • .NET 4.0

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von mhcomp.

    Backgroundworker Shell wird nicht unterstützt

    Hallo,
    zunächst worum es geht:

    Ein Kunde hat ein Tool, welches Verzeichnisse kopiert/verschiebt. Das Programm soll so "korrigiert" werden, dass Verknüpfungen erstellt werden, anstatt die Verzeichnisse zu kopieren bzw. zu verschieben.

    Genutzt wurde VB .NET 4.0 mit einer WinForms Anwendung. Wenn ich das Programm starte bzw. debugge, erhalte ich eine Exception beim Erstellen eines Shell Objektes

    Quellcode

    1. Dim oShell As New Shell32.Shell


    Die Fehlermeldung lautet

    ​Das COM-Objekt des Typs "System.__ComObject" kann nicht in den Schnittstellentyp "Shell32.Shell" umgewandelt werden. Dieser Vorgang konnte nicht durchgeführt werden, da der QueryInterface-Aufruf an die COM-Komponente für die Schnittstelle mit der IID "{286E6F1B-7113-4355-9562-96B7E9D64C54}" aufgrund des folgenden Fehlers nicht durchgeführt werden konnte: Schnittstelle nicht unterstützt (Ausnahme von HRESULT: 0x80004002 (E_NOINTERFACE)).


    Die Problematik wurde bereits schon einmal hier besprochen, leider ohne Lösung

    Bachgroundworker Shell

    Die Shell32.dll ist bei den Referenzen eingebunden. Ich habe begonnen, den Code aufzuräumen und ihn mit Kommentaren zu versehen, wie gleich zu sehen sein wird, ist aber noch viel zu tun. Zunächst klickt der Anwender auf einen "Anlegen" Button und startet den Prozess. Es wird ein neues BackgroundWorker Objekt erzeugt, diesem werden dann die nötigen Variablen als Parameter übergeben. Gestartet wird dieser per

    Quellcode

    1. Worker.RunWorkerAsync(params)


    Das getriggerte Do_Work Event zieht sich die übergebenen Variablen des Workers und baut verschiedene Pfade zusammen, die hinterher für die Shortcuts benötigt werden. Zum Schluss wird diese Methode aufgerufen, die, wenn ich es richtig verstanden habe, die Verknüpfung im Zielverzeichnis anlegt:

    Quellcode

    1. ​ ' Verknüpfung erstellen
    2. Private Function CreateShortcut(ByVal sLinkFile As String, ByVal sTargetFile As String, Optional ByVal sArguments As String = "", Optional ByVal sDescription As String = "", Optional ByVal sWorkingDir As String = "") As Boolean
    3. Try
    4. Dim oShell As New Shell32.Shell
    5. Dim oFolder As Shell32.Folder
    6. Dim oLink As Shell32.ShellLinkObject
    7. ' Ordner und Dateinamen extrahieren
    8. Dim lastPathSegmentIndex As Integer = sLinkFile.LastIndexOf("\")
    9. Dim sPath As String = sLinkFile.Substring(0, lastPathSegmentIndex)
    10. Dim sFile As String = sLinkFile.Substring(lastPathSegmentIndex + 1)
    11. ' Wichtig! Link-Datei erstellen (0 Bytes)
    12. Dim F As Short = FreeFile()
    13. FileOpen(F, sLinkFile, OpenMode.Output)
    14. FileClose(F)
    15. oFolder = oShell.NameSpace(sPath)
    16. oLink = oFolder.Items.Item(sFile).GetLink
    17. ' Eigenschaften der Verknüpfung
    18. With oLink
    19. If sArguments.Length > 0 Then .Arguments = sArguments
    20. If sDescription.Length > 0 Then .Description = sDescription
    21. If sWorkingDir.Length > 0 Then .WorkingDirectory = sWorkingDir
    22. .Path = sTargetFile
    23. ' Verknüpfung speichern
    24. .Save()
    25. End With
    26. ' Objekte zerstören
    27. oLink = Nothing
    28. oFolder = Nothing
    29. oShell = Nothing
    30. Return True
    31. Catch ex As Exception
    32. ' Fehler! ggf. Link-Datei löschen, falls bereit erstellt
    33. If System.IO.File.Exists(sLinkFile) Then Kill(sLinkFile)
    34. Return False
    35. End Try
    36. End Function


    Dort fliegt er mir dann bei

    Quellcode

    1. Dim oShell As New Shell32.Shell


    direkt um die Ohren mit der erwähnten Fehlermeldung. Kennt sich jemand damit aus und kann helfen?
    Shell-Links zu erstellen ist nicht trivial.
    Mach dir erstmal eine ganz einfache Test-Anwendung, die nix macht als einen Shell-Link erstellen.
    Insbesondere nix mit Backgroundworker oder Threads.

    Vlt. kannste die Anwendung auch anhängen, und jmd aussm Forum, der dafür den Code kennt, kann das einbasteln.
    @ErfinderDesRades ich weiß nicht, ob die gesamte Forms Anwendung notwendig ist, aber ich habe schon einmal begonnen halbwegs aufzuräumen und den Code mit kurzen Kommentaren zu versehen, damit ich einigermaßen den Überblick behalten kann :D

    Der Kunde kann über die Forms Anwendung ein paar Felder befüllen, zb "Kundenname", "Projektnummer" etc. und kann dann mit dem Tool eine Ordnerstruktur erstellen lassen. Da seine Entwicklungsabteilung und der Vertrieb ihre eigene Ordnerstruktur haben und der Kunde kein DMS hat, soll das Projekt beim Vertrieb verbleiben und bei der Entwicklungsabteilung NUR eine Verknüpfung erstellt werden. Aktuell hat er wohl das Problem, dass der Code das Verzeichnis vom Vertrieb kopiert / verschiebt.

    Hier mal der gekürzte Code, in der Hoffnung jemand findet bereits den Bug, wieso die Shell bei mir den Fehler wirft.
    Der Code beginnt bei Bt_anlegen_Click und sammelt alle Daten der GUI zusammen. Danach geht es weiter zu TestWorker_DoWork, wo die Verzeichnispfade zusammengesetzt werden. HandleShortcut soll dann die Shell Methode aufrufen und die passenden Pfade reingeben. CreateShortcut selbst kümmert sich dann um die Shell Aufrufe.

    Quellcode

    1. Public Class Form1
    2. #Region "Shared"
    3. #Region "Paths"
    4. Private Const ROOT = "C:\" ' "X:\"
    5. Private Const PROJECTS_DIR = ROOT & "Users\mhermsen\Desktop\Projekte\" ' ROOT & "Projekte\"
    6. Private Const CUSTOMERS_DIR = ROOT & "Users\mhermsen\Desktop\Abteilungen\Vertrieb\05_Kunden-Unterlagen" ' ROOT & "Abteilungen\Vertrieb\05_Kunden-Unterlagen"
    7. Private Const TEMPLATES_ROOT = ROOT & "Users\mhermsen\Desktop\Archiv\Z-Muster-Form\" ' ROOT & "Archiv\Z-Muster-Form\"
    8. Private Const TEMPLATES_DIR = TEMPLATES_ROOT & "Musterverzeichnis19\"
    9. Private Const TEMPLATES_EMPTY_DIR = TEMPLATES_ROOT & "Musterverzeichnis18_Leer\"
    10. Private Const TEMPLATES_FORGE_DIR = TEMPLATES_ROOT & "Schmiedetechnik\"
    11. Private Const ACL_BAT_ROOT = ROOT & "Users\mhermsen\Desktop\" ' ROOT & "Programme\TOOLS\Projektverzeichnis\"
    12. Private Const ACL_BAT_PATH = ACL_BAT_ROOT & "setACL.bat "
    13. Private Const ACL_BAT_PATH_ST = ACL_BAT_ROOT & "setACLst.bat "
    14. Private Const KOM_NR_DIR = ROOT & "Users\mhermsen\Desktop\KomNr\" ' ROOT & "KomNr\"
    15. #End Region
    16. ' Wurde das Projekt bereits angelegt?
    17. Public angelegt As Boolean
    18. ' Verknüpfung erstellen
    19. Private Function CreateShortcut(ByVal sLinkFile As String, ByVal sTargetFile As String, Optional ByVal sArguments As String = "", Optional ByVal sDescription As String = "", Optional ByVal sWorkingDir As String = "") As Boolean
    20. Try
    21. Dim oShell As New Shell32.Shell
    22. Dim oFolder As Shell32.Folder
    23. Dim oLink As Shell32.ShellLinkObject
    24. ' Ordner und Dateinamen extrahieren
    25. Dim lastPathSegmentIndex As Integer = sLinkFile.LastIndexOf("\")
    26. Dim sPath As String = sLinkFile.Substring(0, lastPathSegmentIndex)
    27. Dim sFile As String = sLinkFile.Substring(lastPathSegmentIndex + 1)
    28. ' Wichtig! Link-Datei erstellen (0 Bytes)
    29. Dim F As Short = FreeFile()
    30. FileOpen(F, sLinkFile, OpenMode.Output)
    31. FileClose(F)
    32. oFolder = oShell.NameSpace(sPath)
    33. oLink = oFolder.Items.Item(sFile).GetLink
    34. ' Eigenschaften der Verknüpfung
    35. With oLink
    36. If sArguments.Length > 0 Then .Arguments = sArguments
    37. If sDescription.Length > 0 Then .Description = sDescription
    38. If sWorkingDir.Length > 0 Then .WorkingDirectory = sWorkingDir
    39. .Path = sTargetFile
    40. ' Verknüpfung speichern
    41. .Save()
    42. End With
    43. ' Objekte zerstören
    44. oLink = Nothing
    45. oFolder = Nothing
    46. oShell = Nothing
    47. Return True
    48. Catch ex As Exception
    49. ' Fehler! ggf. Link-Datei löschen, falls bereit erstellt
    50. If System.IO.File.Exists(sLinkFile) Then Kill(sLinkFile)
    51. Return False
    52. End Try
    53. End Function
    54. #End Region
    55. #Region "Druckguss"
    56. ' Worker
    57. Private WithEvents TestWorker As BackgroundWorker
    58. ' Worker iniitieren
    59. Private Sub Bt_anlegen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Bt_anlegen.Click
    60. TestWorker = New System.ComponentModel.BackgroundWorker
    61. Dim param = New WorkParameters()
    62. ' Events anhängen
    63. AddHandler TestWorker.DoWork, New DoWorkEventHandler(AddressOf TestWorker_DoWork)
    64. ' Namen anpassen, falls die Auftragsgröße zwischen 500 und 1000 liegt
    65. Dim AuftragsNummer As String = KomNr.Text
    66. Dim AuftragsGroeße As Integer = Int(AuftragsGr.Text)
    67. If (AuftragsGroeße > 500 And AuftragsGroeße < 1000) Then
    68. AuftragsNummer = String.Concat(AuftragsNummer, "-" & AuftragsGr.Text)
    69. End If
    70. ' Felder für die Worker anlegen
    71. Dim paramArrayInfo As Object() = {KomNr.Text, ProjektNr.Text, FormNr.Text, Kunde.Text, AuftragsGr.Text, MusterFormBox.CheckState, Kunde.SelectedIndex, txtPfad.Text}
    72. ' Worker Felder zuweisen
    73. If AngebotsUnterlagenBox.Checked Then
    74. If Not FolderBrowserDialog1.SelectedPath.ToString.Contains(CUSTOMERS_DIR) Then
    75. MsgBox("Bitte Pfad korrekt auswählen")
    76. End
    77. Else
    78. param.array = paramArrayInfo
    79. End If
    80. Else
    81. txtPfad.Text = ""
    82. param.array = paramArrayInfo
    83. End If
    84. ' Worker starten
    85. TestWorker.RunWorkerAsync(param)
    86. TestWorker.WorkerReportsProgress = True
    87. TestWorker.WorkerSupportsCancellation = True
    88. End Sub
    89. ' Worker starten
    90. Private Sub TestWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles TestWorker.DoWork
    91. If (angelegt) Then
    92. Exit Sub
    93. End If
    94. ' Die konfigurierten Parameter
    95. Dim param = DirectCast(e.Argument, WorkParameters)
    96. ' Werte aus dem param Objekt ziehen
    97. Dim wrkKomNr = param.array(0)
    98. Dim wrkProjektNr = param.array(1)
    99. Dim wrkFormNr = param.array(2)
    100. Dim wrkKunde = param.array(3)
    101. Dim wrkAuftragsGr = param.array(4)
    102. Dim wrkMusterForm = param.array(5)
    103. Dim wrkKundeSelIndex = param.array(6)
    104. Dim wrkPfad = param.array(7)
    105. ' Namen anpassen, falls die Auftragsgröße zwischen 500 und 1000 liegt
    106. Dim AuftragsNummer As String = wrkKomNr
    107. Dim AuftragsGroeße As Integer = Int(wrkAuftragsGr)
    108. If (AuftragsGroeße > 500 And AuftragsGroeße < 1000) Then
    109. AuftragsNummer = String.Concat(AuftragsNummer, "-" & wrkAuftragsGr)
    110. End If
    111. Dim duplikat As Boolean = False
    112. ' Worker Felder überprüfen
    113. If (Len(wrkProjektNr) <> 0 And wrkKomNr <> "" And wrkAuftragsGr <> "" And Len(wrkFormNr) <> 0 And (wrkKundeSelIndex <> -1 Or wrkKunde <> "")) Then
    114. Dim pathToCopyTo As String = PROJECTS_DIR & wrkKunde & "\" & wrkProjektNr & "\" & wrkFormNr & "\"
    115. Dim pathToCopyToWithOrderNumber As String = pathToCopyTo & AuftragsNummer
    116. Dim shortcutPath As String = KOM_NR_DIR & AuftragsNummer & ".lnk"
    117. ' Ist das Verzeichnis ein Duplikat?
    118. If Directory.Exists(pathToCopyTo) Then
    119. For Each foundFile In GetDirs(pathToCopyTo)
    120. Dim KomNrn As String = GetLastPathSegment(foundFile)
    121. ' Ist die Kom.-Nr. identisch zur Auftragsnummer?
    122. If Not (KomNrn <> AuftragsNummer) Then
    123. duplikat = True
    124. MsgBox("Kom.-Nr. existiert bereits in diesem Verzeichnis!")
    125. End If
    126. Next ' Schleife abbrechen
    127. If Not (duplikat = True) Then
    128. HandleShortcut(wrkMusterForm, pathToCopyToWithOrderNumber, wrkPfad, shortcutPath)
    129. End If
    130. Else
    131. HandleShortcut(wrkMusterForm, pathToCopyToWithOrderNumber, wrkPfad, shortcutPath)
    132. End If
    133. Else
    134. MsgBox("Es müssen alle Felder ausgefüllt werden!") '
    135. End If
    136. End Sub
    137. Private Sub HandleShortcut(wrkMusterForm As Boolean, pathToCopyToWithOrderNumber As String, wrkPfad As String, shortcutPath As String)
    138. Dim dirToCopyFrom As String
    139. If wrkMusterForm Then
    140. dirToCopyFrom = TEMPLATES_DIR
    141. Else
    142. dirToCopyFrom = TEMPLATES_EMPTY_DIR
    143. End If
    144. My.Computer.FileSystem.CopyDirectory(dirToCopyFrom, pathToCopyToWithOrderNumber)
    145. ' CreateShortcut(dirToCopyFrom, pathToCopyToWithOrderNumber)
    146. If wrkPfad <> "" Then
    147. ' FileSystem.CopyDirectory(wrkPfad, pathToCopyToWithOrderNumber & "\Angebots_Unterlagen")
    148. CreateShortcut(wrkPfad, pathToCopyToWithOrderNumber & "\Angebots_Unterlagen")
    149. End If
    150. 'Verknüpfung zum Fertigungsordner der entsprechenden Kommission Namen (KomNr.Text).lnk
    151. CreateShortcut(shortcutPath, pathToCopyToWithOrderNumber & "\Fertigung\")
    152. Shell(ACL_BAT_PATH & pathToCopyToWithOrderNumber, AppWinStyle.Hide, True, )
    153. angelegt = True
    154. MsgBox("Erfolgreich angelegt!")
    155. End Sub
    156. #End Region
    157. #Region "Helpers"
    158. ' Liefert das letzte Segment des Pfades zurück
    159. Private Function GetLastPathSegment(path As String)
    160. Return Split(path, "\")(Split(path, "\").Length - 1)
    161. End Function
    162. ' Liefert alle Dateien auf oberster Verzeichnisebene zurück
    163. Private Function GetDirs(path As String)
    164. Return My.Computer.FileSystem.GetDirectories(path, FileIO.SearchOption.SearchTopLevelOnly, "*")
    165. End Function
    166. ' Konfiguration der Worker
    167. Private Class WorkParameters
    168. 'Public Text As String
    169. Public array As Object()
    170. End Class
    171. #End Region
    172. End Class
    Hi,

    teste mal diese Variante, um einen Shortcut zu erstellen...


    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim w As New WshShellClass()
    3. Dim s As IWshRuntimeLibrary.IWshShortcut
    4. Dim target As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    5. s = CType(w.CreateShortcut(target & "\shortcut.lnk"), IWshShortcut)
    6. s.TargetPath = "c:\windows\system32\calc.exe"
    7. s.Save()
    8. End Sub


    Braucht einen Verweis auf die COM-Komponente Windwos Script Host Object Model

    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o

    How to turn OPTION STRICT ON
    Why OPTION STRICT ON