Why is this call to InvokeVerb ("&Print") not working?

3.1k views Asked by At

I'm just trying to batch print a large amount of files from a folder. The folder contains multiple file types, and I just want to invoke the print method equivalent to Right-Click > Print.

It seems like I should be able to do this using the InvokeVerb method of Shell32.FolderItem object. So, I can't figure out why, when I run the code below, nothing prints.

Any ideas?

( GetFolder is just a wrapper for the Shell32.BrowseForFolder function which returns the path to the folder selected. That function works without issue. For testing you can just replace with a path to a folder.)

Sub printFOO()
    Dim shApp           As Shell32.Shell
    Dim srFSO           As Scripting.FileSystemObject
    Dim strPath         As String
    Dim shFIcol         As Shell32.FolderItems
    Dim shFIx           As Shell32.FolderItem
    Dim shFLDx          As Shell32.Folder
    Dim lngX            As Long

    Set shApp = New Shell32.Shell
    Set srFSO = New Scripting.FileSystemObject

    strPath = GetFolder("Choose a folder...")

    Set shFLDx = shApp.NameSpace(strPath)
    Set shFIcol = shFLDx.Items()


    For Each shFIx In shFIcol
            'For lngX = 0 To shFIx.Verbs.Count
                'Debug.Print shFIx.Verbs.ITEM(lngX).Name
            'Next
            'msgbox("printing "&shFIx.name)
            shFIx.InvokeVerb ("&Print")
            DoEvents
    Next
End Sub
4

There are 4 answers

5
CBRF23 On BEST ANSWER

Okay, so I still don't have an answer as to WHY the InvokeVerb method was not working to print, but I do have a way to print files now using the ShellExecute function suggested by @Radek.

Figured I would share my working code here. Feel free to suggest improvements ;)

Option Explicit

Public Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteW" (ByVal hWnd As Long, _
                                                                    ByVal lpOperation As LongPtr, _
                                                                    ByVal lpFile As LongPtr, _
                                                                    ByVal lpParameters As LongPtr, _
                                                                    ByVal lpDirectory As LongPtr, _
                                                                    ByVal nShowCmd As Long) As Long


Public Const SW_HIDE As Long = 0
'Hides the window and activates another window.

Public Const SW_MAXIMIZE  As Long = 3
'Maximizes the specified window.

Public Const SW_MINIMIZE  As Long = 6
'Minimizes the specified window and activates the next top-level window in the z-order.

Public Const SW_RESTORE  As Long = 9
'Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when restoring a minimized window.

Public Const SW_SHOW  As Long = 5
'Activates the window and displays it in its current size and position.

Public Const SW_SHOWDEFAULT  As Long = 10
'Sets the show state based on the SW_ flag specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. An application should call ShowWindow with this flag to set the initial show state of its main window.

Public Const SW_SHOWMAXIMIZED  As Long = 3
'Activates the window and displays it as a maximized window.

Public Const SW_SHOWMINIMIZED  As Long = 2
'Activates the window and displays it as a minimized window.

Public Const SW_SHOWMINNOACTIVE  As Long = 7
'Displays the window as a minimized window. The active window remains active.

Public Const SW_SHOWNA  As Long = 8
'Displays the window in its current state. The active window remains active.

Public Const SW_SHOWNOACTIVATE  As Long = 4
'Displays a window in its most recent size and position. The active window remains active.

Public Const SW_SHOWNORMAL  As Long = 1
'Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.

Public Enum shexActions
    shexEDIT
    shexEXPLORE
    shexFIND
    shexOPEN
    shexPRINT
End Enum

Private Function getShellAction(ByRef enACTION As shexActions) As String
    Select Case enACTION
        Case shexActions.shexEDIT
            getShellAction = "EDIT"
        Case shexActions.shexEXPLORE
            getShellAction = "EXPLORE"
        Case shexActions.shexFIND
            getShellAction = "FIND"
        Case shexActions.shexOPEN
            getShellAction = "OPEN"
        Case shexActions.shexprint
            getShellAction = "PRINT"
    End Select
End Function



Public Function ShellEx(ByRef strFILE As String, _
                        Optional ByRef lngWINDOWHANDLE As Long = 0, _
                        Optional ByRef shexACTION As shexActions = (-1), _
                        Optional ByRef strPARAMETERS As String, _
                        Optional ByRef strDIRECTORY As String, _
                        Optional ByRef lngSHOWCOMMAND As Long = 0) As Long

    Dim lngReturnCheck As Long

    lngReturnCheck = (-1)

    lngReturnCheck = ShellExecute(hWnd:=lngWINDOWHANDLE, lpOperation:=StrPtr(getShellAction(shexACTION)), lpFile:=StrPtr(strFILE), lpParameters:=StrPtr(strPARAMETERS), lpDirectory:=StrPtr(strDIRECTORY), nShowCmd:=lngSHOWCOMMAND)

        While lngReturnCheck = (-1)
            DoEvents
        Wend

    ShellEx = lngReturnCheck
End Function

Sub printBAR()
    Dim shFIcol         As Shell32.FolderItems
    Dim shFIx           As Shell32.FolderItem
    Dim shFLDx          As Shell32.Folder
    Dim lngX            As Long

    Set shFLDx = GetFolder("Choose a folder...", True)

    Set shFIcol = shFLDx.Items()

    For Each shFIx In shFIcol
            lngX = ShellEx(shFIx.Path, , shexPRINT)
            Debug.Print lngX
    Next
End Sub
3
AudioBubble On

Here's a program that does it using slightly different method. It also lists verbs available.

HelpMsg = vbcrlf & "  ShVerb" & vbcrlf & vbcrlf & "  David Candy 2014" & vbcrlf & vbcrlf & "  Lists or runs an explorer verb (right click menu) on a file or folder" & vbcrlf  & vbcrlf & "    ShVerb <filename> [verb]" & vbcrlf & vbcrlf & "  Used without a verb it lists the verbs available for the file or folder" & vbcrlf & vbcrlf
HelpMsg = HelpMsg & "  The program lists most verbs but only ones above the first separator" & vbcrlf & "  of the menu work when used this way" & vbcrlf & vbcrlf 
HelpMsg = HelpMsg & "  The Properties verb can be used. However the program has to keep running" & vbcrlf & "  to hold the properties dialog open. It keeps running by displaying" & vbcrlf & "  a message box." 
Set objShell = CreateObject("Shell.Application")
Set Ag = WScript.Arguments 
set WshShell = WScript.CreateObject("WScript.Shell") 
Set fso = CreateObject("Scripting.FileSystemObject")

    If Ag.count = 0 then 
        wscript.echo "  ShVerb - No file specified"
        wscript.echo HelpMsg 
        wscript.quit
    Else If Ag.count = 1 then 
        If LCase(Replace(Ag(0),"-", "/")) = "/h" or Replace(Ag(0),"-", "/") = "/?" then 
            wscript.echo HelpMsg 
            wscript.quit
        End If
    ElseIf Ag.count > 2 then 
        wscript.echo vbcrlf & "  ShVerb - To many parameters" & vbcrlf & "  Use quotes around filenames and verbs containing spaces"  & vbcrlf
        wscript.echo HelpMsg 
        wscript.quit
    End If

    If fso.DriveExists(Ag(0)) = True then
        Set objFolder = objShell.Namespace(fso.GetFileName(Ag(0)))
'       Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
        Set objFolderItem = objFolder.self
        msgbox ag(0)
    ElseIf fso.FolderExists(Ag(0)) = True then
        Set objFolder = objShell.Namespace(fso.GetParentFolderName(Ag(0)))
        Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
    ElseIf fso.fileExists(Ag(0)) = True then
        Set objFolder = objShell.Namespace(fso.GetParentFolderName(Ag(0)))
        Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
    Else
        wscript.echo "  ShVerb - " & Ag(0) & " not found"
        wscript.echo HelpMsg 
        wscript.quit
    End If

    Set objVerbs = objFolderItem.Verbs

    'If only one argument list verbs for that item

    If Ag.count = 1 then
        For Each cmd in objFolderItem.Verbs
            If len(cmd) <> 0 then CmdList = CmdList & vbcrlf & replace(cmd.name, "&", "") 
        Next
        wscript.echo mid(CmdList, 2)

    'If two arguments do verbs for that item

    ElseIf Ag.count = 2 then
        For Each cmd in objFolderItem.Verbs
            If lcase(replace(cmd, "&", "")) = LCase(Ag(1)) then 
                wscript.echo Cmd.doit 
                Exit For
            End If
        Next
    'Properties is special cased. Script has to stay running for Properties dialog to show.
        If Lcase(Ag(1)) = "properties" then
            WSHShell.AppActivate(ObjFolderItem.Name & " Properties")
            msgbox "This message box has to stay open to keep the " & ObjFolderItem.Name & " Properties dialog open."
        End If  
    End If
End If
0
kevmar On

If you are open to using powershell to solve this:

#Save this as Print-Files.ps1
[CmdletBinding()]
param(
    [Property(Mandatory=$true,
        ValueFromPipelineByPropertyName=$true,
        Position=0)]
    [string]$Path)


foreach($file in (Get-ChildItem $path ))
{
    Start-Process –FilePath $file.FullName –Verb Print
}
1
Radek On

You dont need the FSO for folder browse dialogue. Try shApp.BrowseForFolder(0, "Select Folder to print from", 0, 0). By this method you get directly the shell folder object. Also you may need to check each folder-item if is file or folder.

Sub printFgOO()
    Dim shApp           As Shell32.Shell
    Dim shFIcol         As Shell32.FolderItems
    Dim shFIx           As Shell32.FolderItem
    Dim shFLDx          As Shell32.Folder
    Dim lngX            As Long

    Set shApp = New Shell32.Shell
    Set shFLDx = shApp.BrowseForFolder(0, "Select Folder to print from", 0, 0)
    Set shFIcol = shFLDx.Items()

    For Each shFIx In shFIcol
        If Not shFIx.IsFolder Then    ' Print only if is file
            shFIx.InvokeVerb ("&Print")
            DoEvents
        End If
    Next
End Sub

OR try function ShellExecute as described here!