using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Management; using Microsoft.Win32; namespace RobvanderWoude { class PrintAny { public static string progver = "3.04"; // Remember last file type, this may save lots of time searching for the associated Print(To) commands or verbs public static string lasttype = string.Empty; public static string lastprintcommand = string.Empty; public static bool skipprintercheck = false; public static bool skipverbs = false; static int Main( string[] args ) { try { #region Command Line Parsing string filespec = string.Empty; string printer = string.Empty; string option = string.Empty; if ( args.Length == 0 ) { return ShowHelp( ); } if ( args.Length > 4 ) { return ShowHelp( "Too many command line arguments" ); } foreach ( string arg in args ) { if ( arg[0] == '/' ) { if ( arg == "/?" ) { return ShowHelp( ); } else if ( arg.ToUpper( ) == "/NP" ) { if ( skipprintercheck ) { return ShowHelp( "Duplicate command line switch /NP" ); } skipprintercheck = true; } else if ( arg.ToUpper( ) == "/NV" ) { if ( skipverbs ) { return ShowHelp( "Duplicate command line switch /NV" ); } skipverbs = true; } else { return ShowHelp( "Invalid command line switch {0}", arg ); } } else if ( string.IsNullOrEmpty( filespec ) ) { filespec = arg; } else if ( string.IsNullOrEmpty( printer ) ) { printer = arg; } else { return ShowHelp( "Invalid command line argument \"{0}\"", arg ); } } if ( !string.IsNullOrWhiteSpace( printer ) && !PrinterExists( printer ) ) { return ShowHelp( "Printer not found: \"{0}\"", printer ); } #endregion // Use the current directory if no directory was specified if ( filespec.IndexOf( '\\' ) == -1 ) { filespec = Path.Combine( Directory.GetCurrentDirectory( ), filespec ); } // Get a list of all files in the specified directory string[] files = Directory.GetFiles( Path.GetDirectoryName( filespec ), Path.GetFileName( filespec ) ); // Iterate through the list of all files . . .*/ foreach ( string file in files ) { PrintFile( file, printer ); } return 0; } catch ( Exception e ) { return ShowHelp( e.Message ); } } public static int ExecutePrintCommand( string printcommand ) { try { string command = string.Empty; string arguments = string.Empty; if ( printcommand.StartsWith( "\"" ) ) { // Strip leading doublequote from command command = printcommand.Substring( 1 ); // Arguments are everything following trailing doublequote of command arguments = command.Substring( command.IndexOf( '"' ) + 1 ); // Strip trailing doublequote from command command = command.Substring( 0, command.IndexOf( '"' ) ); } else { // Command is first "word" of string command = printcommand.Substring( 0, printcommand.IndexOf( ' ' ) ); // Arguments is the rest of the string arguments = printcommand.Substring( printcommand.IndexOf( ' ' ) + 1 ); } ProcessStartInfo prog = new ProcessStartInfo( command ); prog.Arguments = arguments; prog.CreateNoWindow = true; prog.UseShellExecute = true; Process proc = new Process( ); proc.StartInfo = prog; proc.Start( ); proc.CloseMainWindow( ); proc.Close( ); Console.WriteLine( printcommand ); return 0; } catch ( Exception e ) { return ShowHelp( e.Message ); } } // Search the registry for the required Print(To) command public static string GetRegPrintCommand( string file, string printer ) { string ext = Path.GetExtension( file ); RegistryKey hkcrext = Registry.ClassesRoot.OpenSubKey( ext ); string ftype = hkcrext.GetValue( "" ).ToString( ); RegistryKey curver = Registry.ClassesRoot.OpenSubKey( ftype + "\\CurVer" ); if ( curver != null ) { ftype = curver.GetValue( "" ).ToString( ); } string printcmd = string.Empty; RegistryKey hkcrprint = Registry.ClassesRoot.OpenSubKey( ftype + "\\shell\\Print\\command" ); if ( hkcrprint != null ) { printcmd = hkcrprint.GetValue( "" ).ToString( ); } string printtocmd = string.Empty; RegistryKey hkcrprintto = Registry.ClassesRoot.OpenSubKey( ftype + "\\shell\\Printto\\command" ); if ( hkcrprintto != null ) { printtocmd = hkcrprintto.GetValue( "" ).ToString( ); } try { hkcrext.Close( ); curver.Close( ); hkcrprint.Close( ); hkcrprintto.Close( ); } catch { } // If a key cannot be closed, we'll just ignore it if ( string.IsNullOrWhiteSpace( printer ) ) { return printcmd; } else { return printtocmd; } } public static bool PrinterExists( string printer ) { if ( skipprintercheck ) { return true; } string query = String.Format( "SELECT * FROM Win32_Printer WHERE Name='{0}'", printer.Replace( @"\", @"\\" ) ); ManagementObjectSearcher searcher = new ManagementObjectSearcher( "root\\CIMV2", query ); int found = searcher.Get( ).Count; if ( found == 1 ) { return true; } else { return false; } } // Print a single specified file to the specified (or default) printer public static int PrintFile( string file, string printer ) { if ( !skipverbs ) { // First we'll try to use the Print or PrintTo Verbs, if available bool printverb = false; bool printtoverb = false; ProcessStartInfo fileinfo = new ProcessStartInfo( file ); fileinfo.UseShellExecute = true; if ( fileinfo.Verbs.Length > 0 ) { foreach ( string verb in fileinfo.Verbs ) { if ( verb.ToLower( ) == "print" ) { printverb = true; } if ( verb.ToLower( ) == "printto" ) { printtoverb = true; } } } if ( string.IsNullOrWhiteSpace( printer ) ) { if ( printverb ) { fileinfo.Verb = "Print"; Process proc = new Process( ); proc.StartInfo = fileinfo; proc.Start( ); Console.WriteLine( "Print \"{0}\"", file ); return 0; } } else { if ( printtoverb ) { fileinfo.Verb = "PrintTo"; fileinfo.Arguments = printer; Process proc = new Process( ); proc.StartInfo = fileinfo; proc.Start( ); Console.WriteLine( "PrintTo \"{0}\", \"{1}\"", file, printer ); return 0; } } } // If the required Verb is not available, we'll try it the old-fashioned // way by reading the Print or PrintTo command from the registry string printcmd = GetRegPrintCommand( file, printer ); // Now we have to substitute "%1" and "%2" in the Print(To) command withe the properly escaped and trimmed parameters if ( printcmd.IndexOf( "%1" ) == -1 ) { return ShowHelp( "Command line printing not available for file type " + Path.GetExtension( file ) ); } printcmd = printcmd.Replace( "%1", "\"" + file + "\"" ); printcmd = printcmd.Replace( @"""""", @"""" ); if ( printcmd.IndexOf( "%2" ) == -1 ) { if ( !string.IsNullOrWhiteSpace( printer ) ) { return ShowHelp( "Printer cannot be specified for file type " + Path.GetExtension( file ) ); } } else { printcmd = printcmd.Replace( "%2", "\"" + printer + "\"" ); printcmd = printcmd.Replace( @"""""", @"""" ); } printcmd = printcmd.Replace( "\"%3\"", "" ); printcmd = printcmd.Replace( "%3", "" ); printcmd = printcmd.Replace( "\"%4\"", "" ); printcmd = printcmd.Replace( "%4", "" ); return ExecutePrintCommand( printcmd ); } public static int ShowHelp( params string[] errmsg ) { /* PrintAny.exe, Version 3.04 Print files using the registered Print(To) command or verb for the file types Usage: PrintAny.exe filespec [ printer ] [ options ] Where: filespec the file(s) to be printed (wildcards allowed) printer the printer to be used Options: /NP No Printer check: skip check for printer in WMI (may be necessary for network printers) /NV No Verb: force the program to find the Print(To) command in the registry (may be necessary for some combinations of file type and printer, e.g. PDFs on network printers) Examples: PrintAny.exe "d:\some folder\some file.pdf" PrintAny.exe "d:\some folder\some file.pdf" "Color Printer Sales Dept" PrintAny.exe "d:\some folder\*.pdf" "\\server\printer" /NP /NV Notes: Use doublequotes if the file and/or printer names contain spaces. The Print(To) verb or command is displayed for each matching file. Not all file types have registered Print(To) commands or verbs. Written by Rob van der Woude http://www.robvanderwoude.com */ if ( errmsg.Length > 0 ) { List errargs = new List( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR:\t" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } Console.Error.WriteLine( ); Console.Error.WriteLine( "PrintAny.exe, Version {0}", progver ); Console.Error.WriteLine( "Print files using the registered Print(To) command or verb for the file types" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "PrintAny.exe filespec [ printer ] [ options ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "filespec" ); Console.ResetColor( ); Console.Error.WriteLine( " the file(s) to be printed (wildcards allowed)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " printer" ); Console.ResetColor( ); Console.Error.WriteLine( " the printer to be used" ); Console.Error.WriteLine( ); Console.Error.Write( "Options: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/NP N" ); Console.ResetColor( ); Console.Error.Write( "o " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "P" ); Console.ResetColor( ); Console.Error.WriteLine( "rinter check: skip check for printer in WMI" ); Console.Error.WriteLine( " (may be necessary for network printers)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /NV N" ); Console.ResetColor( ); Console.Error.Write( "o " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "V" ); Console.ResetColor( ); Console.Error.WriteLine( "erb: force the program to find the Print(To) command" ); Console.Error.WriteLine( " in the registry (may be necessary for some combinations" ); Console.Error.WriteLine( " of file type and printer, e.g. PDFs on network printers)" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Examples: PrintAny.exe \"d:\\some folder\\some file.doc\"" ); Console.Error.WriteLine( " PrintAny.exe \"d:\\some folder\\some file.pdf\" \"Color Printer Sales\"" ); Console.Error.WriteLine( " PrintAny.exe \"d:\\some folder\\*.pdf\" \"\\\\server\\printer\" /NP /NV" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Notes: Use doublequotes if the file and/or printer names contain spaces." ); Console.Error.WriteLine( " The Print(To) verb or command is displayed for each matching file." ); Console.Error.WriteLine( " Not all file types have registered Print(To) commands or verbs." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "http://www.robvanderwoude.com" ); return 1; } } }