[VB] Mehrere Dateien einem Process übergeben?

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von hassowuff.

    [VB] Mehrere Dateien einem Process übergeben?

    Hallo Ihr lieben!

    Wenn ich im Explorer mehrere Bilddateien auswähle, rechtsklick mache und Drucken wähle, öffnet sich ein Foto-Druckdialog von Windows. In diesem sind nun alle ausgewählten Bilder vorhanden.

    Mit einer einzelnen Datei erreiche ich gleiches auch aus meinem Programm heraus:

    VB.NET-Quellcode

    1. Dim pr As Process = New Process
    2. pr.StartInfo.FileName = filepathOfMyImage
    3. pr.StartInfo.UseShellExecute = True
    4. pr.StartInfo.Verb = "print"
    5. pr.Start()


    Nur mit mehreren bekomme ich es nicht hin Daher habe ich mir gerade so beholfen:

    VB.NET-Quellcode

    1. For Each file As String In pathArrayOfMyImageFiles
    2. Dim fileType As String = file.Substring(file.LastIndexOf(".") + 1).Trim().ToUpper()
    3. Select Case fileType
    4. Case "PNG", "JPG", "GIF", "JPEG", "BMP"
    5. Dim pr As Process = New Process
    6. pr.StartInfo.FileName = file
    7. pr.StartInfo.UseShellExecute = True
    8. pr.StartInfo.Verb = "print"
    9. pr.Start()
    10. Case Else
    11. End Select
    12. Next


    Ist es möglich irgendwie dem Druckdialog gleich alle Dateien mitzugeben - Wenn ja wie könnte ich vorgehen?

    Lg. Hassowuff
    __________________________
    01:
    CLS : SCREEN 12
    02: LINE (0, 20)-(640, 22), 15, BF
    03: ECHO "MFG HASSOWUFF"
    [F5]
    Moinsen @hassowuff

    'Zitat aus der MS Dokumentation'
    Quelle: docs.microsoft.com/en-us/windo…hellapi-shellexecuteinfoa

    lpFile

    Type: LPCTSTR

    The address of a null-terminated string that specifies the name of the file or object on which ShellExecuteEx will perform the action specified by the lpVerb parameter. The system registry verbs that are supported by the ShellExecuteEx
    function include "open" for executable files and document files and
    "print" for document files for which a print handler has been
    registered. Other applications might have added Shell verbs through the
    system registry, such as "play" for .avi and .wav files. To specify a
    Shell namespace object, pass the fully qualified parse name and set the SEE_MASK_INVOKEIDLIST flag in the fMask parameter.

    Note: If the SEE_MASK_INVOKEIDLIST flag is set, you can use either lpFile or lpIDList to identify the item by its file system path or its PIDL respectively. One of the two values—lpFile or lpIDList—must be set.

    Note: If the path is not included with the name, the current directory is assumed.


    So wie ich das lese werden nur die Dateinamen übergeben, und zusätzlich ein "Referenz-Ordner" als Parameter angegeben.

    Zudem, versuche einmal die "Cases" mit Kleinbuchstaben bei der Dateiendung!?!?!

    Mehr fällt mir, vor dem ersten Kaffee, nicht ein AndAlso auf AndAlso ab. ?( ;) :/ :thumbsup:

    Wie sieht denn der String-Array aus (pathArrayOfMyImageFiles) ?
    Vielleicht reicht es dann nur die "Vollständigen"-Pfade pro Datei von der Dateibenennung abzutrennen,
    oder wenn nur Dateibenennung vorhanden, dann irgendwie den Ordnerpfad reinpröpeln... :P

    c.u Joshi aus HaHa-Land , mit zweiter Staatsbürgeschaft dem LaLa-Land.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Joshi“ ()

    Hi

    @hassowuff
    Du kannst Dir von den Dateien eine PIDL (ITEMIDLIST) (SHGetDesktopFolder -> Interface IShellFolder, IShellFolder.ParseDisplayName(Deine Datei) -> PIDL ) holen und packst diese in ein ITEMIDLIST-Array. Per SHCreateShellItemArrayFromIDLists erstellst aus dem ITEMIDLIST-Array ein Interface IShellItemArray. Vom IShellItemArray holst Du Dir mit BindToHandler(BHID_SFUIObject) ein Interface IContextMenu. Per IContextMenu.InvokeCommand führst halt den "print" Befehl aus.

    Alternativ kannst auch das Interface IFileOpenDialog (Flag FOS_ALLOWMULTISELECT) verwenden um die Dateien auszuwählen. IFileOpenDialog.GetResults liefert Dir dann ein Interface IShellItemArray von den selektierten Dateien zurück. Der Rest ist dann wie oben beschrieben über das Interface IContextMenu.
    Mfg -Franky-
    Hallo Ihr lieben!

    Ich habe mal eure Antworten studiert und selbst noch weiter recherchiert^^
    Also Google hat zu diesem Thema zahlreiche offen gebliebene Fragen gefunden, jedoch keine richtige Antwort..

    Was habe ich bereits?

    Selektiere ich mehrere Bilder -> Rechtsklick -> Drucken, so kommt der Fotodruckdialog, der wiederum aber keinen Eintrag im Taskmanager erzeugt, so konnte ich keine ".exe"-Datei ausfindig machen.

    Das Verb "Print" bzw. "PrintTo" führt in diesem Fall scheinbar folgenden Befehl aus: "C:\WINDOWS\system32\rundll32.exe c:\windows\system32\shimgvw.dll,ImageView_PrintTo /pt %1 %2 %3 %4"
    %1 steht hier für den Pfad und Dateinamen einer einzelnen Datei, %2 und %3 wird wohl seit WinME oder so nicht mehr genutzt und mit %4 kann man einen Drucker definieren.
    Ein kurzer Test über die PowerShell bestätigte das auch. Kann es sein, dass der Bilder-Druck-Dialog ein Dialog innerhalb des Explorers ist? Ich bin schon dazu geneigt, einfach einen eigenen Dialog zu Entwickeln.

    Die DLL selbst ist schlecht Dokumentiert, jedoch habe ich mir diese einmal angesehen und kann dort auch keinen Hinweis auf die Übergabe mehrerer Dateien finden, nur dann Frage ich mich wie es der Explorer macht.
    Unschlüssig bin ich auch noch, ob ich mit der DLL-Datei nicht auf einem Irrweg bin, finde allerdings auch in der Windows-Registry "HKEY_CLASSES_ROOT" keine anderen Hinweise außer diesen:


    PS noch @-Franky-: Deine Vorgehensweise habe ich verstanden, finde ich auch gar nicht schlecht nur die Umsetzung nach deiner Beschreibung übersteigt meine Fähigkeiten^^

    Aber ich konnte eine ähnliche Vorgehensweise in einem anderen Forum auch finden:
    Spoiler anzeigen

    I too have searched far and wide for this solution. The best thing I've been able to come up with (and I'm very happy with btw) is to use VBScript under Windows Script Host to load the image in to Windows Photo Viewer and then send keyboard command to the application.

    TestPrint.vbs

    VB.NET-Quellcode

    1. Const iNormalFocus = 1Set
    2. objShell = WScript.CreateObject("WScript.Shell")
    3. objShell.Run "rundll32 " & chr(34) & "%ProgramFiles(x86)%\Windows Photo Viewer\PhotoViewer.dll" & chr(34) & ",ImageView_Edit c:\temp\20141217_000220.jpg",iNormalFocusWscript.Sleep 300
    4. objShell.AppActivate "Console1"
    5. Wscript.Sleep 100
    6. objShell.SendKeys "^p"
    7. Wscript.Sleep 900
    8. objShell.SendKeys "%F"
    9. Wscript.Sleep 900
    10. objShell.SendKeys "%P"
    11. Wscript.Sleep 10000
    12. objShell.SendKeys "%F"
    13. Wscript.Sleep 900
    14. objShell.SendKeys "X"


    This opens the image and does the following:

    Control P to bring up the print dialog
    Waits
    ALT F to disable "Fit picture to frame"
    Waits
    ALT P to print
    Waits longer (for the print job to submit)
    ALT F to bring up the file menu
    Waits
    X to exit
    It is strange that the print dialog stays after the job is submitted, but it looses focus and closes upon the application exit.

    See technet.microsoft.com/en-us/library/ee156592.aspx for more information.


    Hat noch jemand eine Idee, oder: Wie kann kann ich prüfen ob ich mit der DLL am richtigen Ende suche?

    Lg. Hassowuff
    __________________________
    01:
    CLS : SCREEN 12
    02: LINE (0, 20)-(640, 22), 15, BF
    03: ECHO "MFG HASSOWUFF"
    [F5]
    @hassowuff

    Deine Vorgehensweise habe ich verstanden, finde ich auch gar nicht schlecht nur die Umsetzung nach deiner Beschreibung übersteigt meine Fähigkeiten​

    Das ist zwar nicht ganz der Weg den der Explorer nimmt, aber so ähnlich. Am Ende kommt ja der Rechtsklick auf die selektierten Dateien und das Kontextmenü wo Du dann halt Drucken auswählst und der dazugehörende registrierte Handler für Bilder (die shimgvw.dll offensichtlich) aufgerufen wird. Bei meiner Idee zeigen wir zwar nicht das Kontextmenü an, sondern führen den Befehl direkt aus.

    Wenn ich wirklich viel Zeit hätte, was bei mir kaum vorkommt, könnte ich ein .NET Bsp basteln. Um sich da viel Arbeit mit den ganzen Interfaces zu sparen, würde ich nur mit den Pointern, der VTable und Delegates arbeiten (nur die benötigten Funktionen eines Interfaces) anstatt die Interfaces komplett, mit allen Funktionen, im Code einzubauen. Mal schauen, vllt am Wochenende. Versprechen kann ich da aber nichts das ich dazu komme. Vllt hat ja ein anderer hier mehr Zeit als ich und bastelt was zusammen.
    Mfg -Franky-
    @-Franky- Vielen vielen Dank für deine Mühen! Ich versuche dennoch, mir den Weg den du beschrieben hast zu erarbeiten!
    __________________________
    01:
    CLS : SCREEN 12
    02: LINE (0, 20)-(640, 22), 15, BF
    03: ECHO "MFG HASSOWUFF"
    [F5]
    Hi

    @hassowuff

    Hab heute ein bissel Zeit gefunden meine Idee umzusetzen. Ist jetzt alles auf die schnelle zusammen gebaut und ein wenig anders geworden wie ich es ursprünglich geplant hatte. What ever. Hauptsache es läuft. Das Prinzip dürfte klar sein. Wer möchte, darf das ganze natürlich gern verbessern, erweitern usw. ;)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.Runtime.InteropServices
    4. Public Class Form1
    5. Private Const S_OK As Integer = 0
    6. Private Const CMDSTR_PRINT As String = "Print"
    7. Private Const BHID_SFUIObject As String = "3981E225-f559-11d3-8E3a-00c04f6837d5"
    8. Private Const IID_IShellItemArray As String = "b63ea76d-1f85-456f-a19c-48159efa858b"
    9. Private Const IID_IContextMenu As String = "000214e4-0000-0000-c000-000000000046"
    10. <StructLayout(LayoutKind.Sequential)>
    11. Private Structure CMINVOKECOMMANDINFOEX
    12. Dim cbSize As Integer
    13. Dim fMask As Integer
    14. Dim hwnd As IntPtr
    15. <MarshalAs(UnmanagedType.LPStr)> Dim lpVerb As String
    16. <MarshalAs(UnmanagedType.LPStr)> Dim lpParameters As String
    17. <MarshalAs(UnmanagedType.LPStr)> Dim lpDirectory As String
    18. Dim nShow As Integer
    19. Dim dwHotKey As Integer
    20. Dim hIcon As IntPtr
    21. <MarshalAs(UnmanagedType.LPStr)> Dim lpTitle As String
    22. <MarshalAs(UnmanagedType.LPWStr)> Dim lpVerbW As String
    23. <MarshalAs(UnmanagedType.LPWStr)> Dim lpParametersW As String
    24. <MarshalAs(UnmanagedType.LPWStr)> Dim lpDirectoryW As String
    25. <MarshalAs(UnmanagedType.LPWStr)> Dim lpTitleW As String
    26. Dim ptInvokeX As Integer
    27. Dim ptInvokeY As Integer
    28. End Structure
    29. <DllImport("Shell32.dll", EntryPoint:="SHParseDisplayName")>
    30. <PreserveSig> Private Shared Function SHParseDisplayName(<[In], MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String,
    31. <[In]> ByVal pbc As IntPtr,
    32. <Out> ByRef ppidl As IntPtr,
    33. <[In]> ByVal sfgaoIn As IntPtr,
    34. <Out> ByRef psfgaoOut As IntPtr) As Integer
    35. End Function
    36. <DllImport("Shell32.dll", EntryPoint:="SHCreateShellItemArrayFromIDLists")>
    37. <PreserveSig> Private Shared Function SHCreateShellItemArrayFromIDLists(<[In]> ByVal cidl As Integer,
    38. <[In]> ByVal rgpidl As IntPtr(),
    39. <Out, MarshalAs(UnmanagedType.Interface)> ByRef ppsiItemArray As IShellItemArray) As Integer
    40. End Function
    41. <DllImport("User32.dll", EntryPoint:="CreateMenu")>
    42. Private Shared Function CreateMenu() As IntPtr
    43. End Function
    44. <DllImport("User32.dll", EntryPoint:="DestroyMenu")>
    45. Private Shared Function DestroyMenu(<[In]> ByVal hMenu As IntPtr) As Boolean
    46. End Function
    47. <ComImport>
    48. <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    49. <Guid(IID_IShellItemArray)>
    50. Private Interface IShellItemArray
    51. <PreserveSig> Function BindToHandler(<[In]> ByVal pbc As IntPtr,
    52. <[In], MarshalAs(UnmanagedType.LPStruct)> ByVal bhid As Guid,
    53. <[In], MarshalAs(UnmanagedType.LPStruct)> ByVal riid As Guid,
    54. <Out, MarshalAs(UnmanagedType.IUnknown)> ByRef ppvOut As Object) As Integer
    55. 'GetPropertyStore
    56. 'GetPropertyDescriptionList
    57. 'GetAttributes
    58. 'GetCount
    59. 'GetItemAt
    60. 'EnumItems
    61. End Interface
    62. <ComImport>
    63. <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    64. <Guid(IID_IContextMenu)>
    65. Private Interface IContextMenu
    66. <PreserveSig> Function QueryContextMenu(<[In]> ByVal hMenu As IntPtr,
    67. <[In]> ByVal indexMenu As Integer,
    68. <[In]> ByVal idCmdFirst As Integer,
    69. <[In]> ByVal idCmdLast As Integer,
    70. <[In]> ByVal uFlags As Integer) As Integer
    71. <PreserveSig> Function InvokeCommand(<[In], MarshalAs(UnmanagedType.Struct)> ByRef pici As CMINVOKECOMMANDINFOEX) As Integer
    72. 'GetCommandString
    73. End Interface
    74. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    75. Dim sFiles As String() = New String(3) {}
    76. Dim pPidlArr As IntPtr() = New IntPtr(sFiles.Length - 1) {}
    77. ' Bilder
    78. sFiles(0) = "d:\test01.jpg"
    79. sFiles(1) = "d:\test02.jpg"
    80. sFiles(2) = "d:\test03.jpg"
    81. sFiles(3) = "d:\test04.jpg"
    82. ' von allen Bilder die PIDL ermitteln und in einem Array speichern
    83. For intItem As Integer = 0 To sFiles.Length - 1
    84. Dim pPIDL As IntPtr = IntPtr.Zero
    85. If SHParseDisplayName(sFiles(intItem), IntPtr.Zero, pPIDL,
    86. IntPtr.Zero, IntPtr.Zero) = S_OK Then
    87. pPidlArr(intItem) = pPIDL
    88. End If
    89. Next
    90. Dim IIShellItemArray As IShellItemArray = Nothing
    91. ' vom PIDL-Array ein IShellItemArray erstellen
    92. If SHCreateShellItemArrayFromIDLists(pPidlArr.Length, pPidlArr,
    93. IIShellItemArray) = S_OK Then
    94. Dim oIContextMenu As Object = Nothing
    95. ' vom IShellItemArray ein IContextMenu erstellen
    96. If IIShellItemArray.BindToHandler(IntPtr.Zero, New Guid(BHID_SFUIObject),
    97. New Guid(IID_IContextMenu), oIContextMenu) = S_OK Then
    98. Dim IIContextMenu As IContextMenu = DirectCast(oIContextMenu, IContextMenu)
    99. ' ein Menü erstellen
    100. Dim hMenu As IntPtr = CreateMenu()
    101. If hMenu <> IntPtr.Zero Then
    102. ' Menü zuweisen (alle Kontextmenüeinträge werden hier geladen)
    103. If IIContextMenu.QueryContextMenu(hMenu, 0, 0, &H7FFF, 0) > 0 Then
    104. ' ab hier könnte man das Kontextmenü z.B. anzeigen, Anzahl der
    105. ' Kontextmenüeintrage ermitteln, ID eines Kontextmenüeintrages
    106. ' ermitteln, Verb (open, print usw.) eines Kontextmenüeintrages
    107. ' ermitteln usw.
    108. Dim tCMICI As New CMINVOKECOMMANDINFOEX
    109. ' Befehl (Verb) der aus dem Kontextmenü ausgeführt werden soll
    110. With tCMICI
    111. .cbSize = Marshal.SizeOf(tCMICI)
    112. .lpVerb = CMDSTR_PRINT
    113. End With
    114. ' Befehl ausführen
    115. If IIContextMenu.InvokeCommand(tCMICI) = S_OK Then
    116. Debug.Print("OK")
    117. End If
    118. End If
    119. ' Menü löschen
    120. DestroyMenu(hMenu)
    121. End If
    122. ' IContextMenu löschen
    123. Marshal.FinalReleaseComObject(IIContextMenu)
    124. End If
    125. ' IShellItemArray löschen
    126. Marshal.FinalReleaseComObject(IIShellItemArray)
    127. End If
    128. For intItem As Integer = 0 To pPidlArr.Length - 1
    129. ' alle PIDLs freigeben
    130. Marshal.FreeCoTaskMem(pPidlArr(intItem))
    131. Next
    132. End Sub
    133. End Class

    Mfg -Franky-
    WTF! Mit deinem Kopf wäre ich gern in einem Netzwerk^^ Vielen Dank dafür! Ich überarbeite gerade mein ganzes Programm und setze es von Grund auf nochmal auf ganz neue "Beine", denn meine Ansprüche daran sind recht hoch^^
    Sobald das Grundgerüst steht werde ich das ganze mit aufgreifen und ausführlich testen! Ich melde mich wenn ich soweit bin! Aber wie gesagt vielen, vielen Dank!

    PS: Ich erarbeite ein Programm zum massenhaften scannen und verwalten von Dokumenten und Unterlagen und das ganze so, dass sich Unterlagen auch zu Gruppen, Kategorien, Unternehmen und Personen sortieren lassen. Möglichst eine Hybridlösung aus physischer und virtueller Speicherung.. Das stressigste für mich dabei ist es, wenn 100te Dokumente gescannt sind sie auch Personen und Kategorien zuzuordnen und um zu benennen und mehrseitige Unterlagen zu einem zusammen zu fassen und ggf. in PDF's umzuwandeln. Daher soll mein Programm eine erweiterte Lösung der "Windows Fax und Scan"-App werden.
    __________________________
    01:
    CLS : SCREEN 12
    02: LINE (0, 20)-(640, 22), 15, BF
    03: ECHO "MFG HASSOWUFF"
    [F5]