Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Print Word Document from C# without starting MS Word

Status
Not open for further replies.

StevenK

Programmer
Jan 5, 2001
1,294
GB
I'm guessing this is simply done - by I can't see it yet.
How do I force a MS Word document to print directly (to a printer) without first calling up MS Word.
At the moment we set up MS Word from code and then make it visible such that the user can press the 'Print' button.
We want to force their hand and print directly without their needing to press the additional button.
Any thoughts ?
Thanks in advance
Steve
 
I've found some code on the web to print out a MS Word document but can't seem to get the right parameters passed to the syntax to make things happen.
The code is as follows :

object myTrue = true;
object myFalse = false;
object missingValue = Type.Missing;
object range = Word.WdPrintOutRange.wdPrintAllDocument;
object items = Word.WdPrintOutItem.wdPrintDocumentContent;
object copies = "1";
object pages = "1";
object pageType = Word.WdPrintOutPages.wdPrintAllPages;

wrdApp.PrintOut(ref myTrue, ref myFalse, ref range,
ref missingValue, ref missingValue, ref missingValue,
ref items, ref copies, ref pages, ref pageType, ref myFalse, ref myTrue, ref missingValue, ref myFalse, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue);

[where wrdApp = new Word.ApplicationClass()]

I get 'Type Mismatch' when I try and run the code and cannot (for the life of me) establish which of the parameters is failing on me.

Any help would be appreciated.

Thanks in advance
Steve
 
Hi

I wrote this, probably based on the same example you've seen. It's just a console app, hastily put together, and probably contains some rather dubious logic, but it does seem to wrok.

The prerequisites are that you need to be running a minimum of Windows 2k, Word is installed (obvious really) and that you have a default printer (again, obvious).

Basically you specify a directory which contains your docs. If there are any temp files, these will be ignored.

Make sure your not running word when you run this, it will kill it off before processing starts.

Configuration is handled using and xml file (see below). Just make sure it's in the same directory as the exe. Don't set the QueueQueryInterval too low and make sure the BatchSize isn't too high.

The BatchSize element will set the number of word docs to process in a single hit. The program then checks to see if all the documents have left the print queue, if they have it move on to the next one.

At the end the Winword process should deep six itself.

HTH

BigGlenn

Useful stuff below...

Create an Xml file called PrintProcessor.config.xml and put this in it


<ppc:printProcessorConfiguration xmlns:ppc=&quot; <BatchSize>10</BatchSize>
<MSWordProcessName>WINWORD</MSWordProcessName>
<MSWordPath>c:\Program Files\Microsoft Office\Office\winword.exe</MSWordPath>
<LogName LoggingEnabled=&quot;true&quot;>PrintProcessor.log</LogName>
<QueryQueueInterval>8000</QueryQueueInterval> <!-- milliseconds!!!!!! -->
</ppc:printProcessorConfiguration>


Heres the source


using System;
using System.Collections;
using System.Diagnostics;
using System.Drawing.Printing;
using System.IO;
using System.Management;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Xml;
using Word;


class PrintProcessor
{
private static string m_ProcessDirectory;
private static int m_ActiveBatchId;
private static int m_TotalBatches;
private static string[] m_ActiveBatch;
private static string[] m_FilesToProcess;
private static bool m_BatchComplete;
private static XmlDocument m_Configuration;
private static XmlNamespaceManager m_Nsm;

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main( string[] args )
{
try
{
LoadConfigurationFile( );
PrepareLog( );

WriteLog( Greeting() );
WriteLog( &quot;Checking parameters&quot; );
Console.WriteLine( Greeting() );
if ( args.Length < 1 )
{
m_ProcessDirectory = Environment.CurrentDirectory;
}
else
{
if ( !Directory.Exists( args[0] ) )
{
throw new DirectoryNotFoundException( &quot;Unable to continue. The directory specified is not valid&quot; );
}
else
{
m_ProcessDirectory = args[0];
}
}

KillWord( );

ProcessBatches( );
}
catch ( Exception e )
{
Console.WriteLine( e.GetBaseException().Message );
Console.WriteLine( &quot;***Processing abended***&quot; );
WriteLog( e.GetBaseException().Message );
}
finally
{
Console.WriteLine( &quot;\r\nPress ENTER to continue...&quot; );
Console.ReadLine();
WriteLog( &quot;****End of Log****&quot; );
}
}

/// <summary>
/// The configuration file is assumed to be in the same directory as the executable
/// </summary>
private static void LoadConfigurationFile()
{
m_Configuration = new XmlDocument();
m_Configuration.Load( &quot;PrintProcessor.config.xml&quot; );
m_Nsm = new XmlNamespaceManager( m_Configuration.NameTable );
m_Nsm.AddNamespace( &quot;ppc&quot;, &quot;mynamespace.co.uk&quot; );
}

private static void ProcessBatches( )
{
//Split the documents into batches
try
{
//Get the file names
m_FilesToProcess = CleanTempFiles( Directory.GetFiles( m_ProcessDirectory, &quot;*.doc&quot; ) );

ArrayList batches = new ArrayList();
int fpCount = m_FilesToProcess.GetLength( 0 );

WriteLog( &quot;Splitting batches...&quot; );
int howMany = fpCount / BatchSize;
int modulus = fpCount % BatchSize;

if ( howMany > 1 )
{
for ( int i = 0; i < howMany; i++ )
{
batches.Add( CopyRange( m_FilesToProcess, i * BatchSize, BatchSize ) );
m_TotalBatches++;
}

if ( modulus > 0 )
{
batches.Add( CopyRange( m_FilesToProcess, fpCount - modulus, modulus ) );
m_TotalBatches++;
}
}
else if ( howMany == 1 && modulus != 0 )
{
batches.Add( CopyRange( m_FilesToProcess, 0, BatchSize ) );
m_TotalBatches++;

batches.Add( CopyRange( m_FilesToProcess, BatchSize, modulus ) );
m_TotalBatches++;
}
else
{
batches.Add( CopyRange( m_FilesToProcess, 0, fpCount ) );
m_TotalBatches++;
}

//Process the individual batches
foreach ( string[] batch in batches )
{
m_ActiveBatchId++;
m_ActiveBatch = batch;
WriteLog( &quot;Processing batch &quot; + m_ActiveBatchId + &quot; of &quot; + m_TotalBatches );
PrintUsingWordObject( m_ActiveBatch );
}
Console.Write( &quot;\r\nAll batches have completed&quot; );
}
catch ( Exception e )
{
throw e;
}
}

/// <summary>
/// Process the current batch
/// </summary>
/// <param name=&quot;batch&quot;>m_ActiveBatch</param>
private static void PrintUsingWordObject( string[] batch )
{
object saveChanges = false;
object originalFormat = Missing.Value;
object routeDocument = Missing.Value;

ApplicationClass app = new ApplicationClass();
_Document doc;
foreach ( string file in batch )
{
Console.WriteLine( &quot;Attempting to process {0}&quot;, file );
WriteLog ( &quot;Attempting to process &quot; + file );
app.Visible = false;
object visible = true;
object fileName = file;
object optional=Missing.Value;

doc = app.Documents.Open(ref fileName,ref optional,ref
optional,ref optional,ref optional,ref optional,ref optional,ref
optional,ref optional,ref optional,ref optional,ref visible );

object myTrue = true;
object myFalse = false;
object missingValue = Type.Missing;
object range = Word.WdPrintOutRange.wdPrintAllDocument;
object items = Word.WdPrintOutItem.wdPrintDocumentContent;
object copies = &quot;1&quot;;
object pages = Missing.Value;
object pageType = Word.WdPrintOutPages.wdPrintAllPages;

doc.PrintOut(ref myTrue, ref myFalse, ref range,
ref missingValue, ref missingValue, ref missingValue,
ref items, ref copies, ref pages, ref pageType, ref myFalse,
ref myTrue, ref missingValue, ref myFalse, ref missingValue,
ref missingValue, ref missingValue, ref missingValue);

}
//Should be in the print queue
Console.Write( &quot;Processing batch {0} of {1}\r&quot;, m_ActiveBatchId, m_TotalBatches );
while ( !m_BatchComplete )
{
CheckPrintQueue();
Thread.Sleep( QueryQueueInterval );
}
m_BatchComplete = false;
app.Quit(ref saveChanges, ref originalFormat, ref routeDocument);
}

#region &quot;Handy functions&quot;

private static void PrepareLog()
{
WriteLog( &quot;Preparing log...&quot; );
if ( LoggingEnabled )
{
if ( File.Exists( LogName ) )
{
File.Copy( LogName, DateTime.Now.ToString(&quot;yyyy-MM-dd HHmmss&quot;) + &quot;_&quot; + LogName );
File.Delete( LogName );
}
}
}

/// <summary>
/// Writes to a log file, will also log to the console if you want
/// </summary>
/// <param name=&quot;message&quot;></param>
/// <param name=&quot;writeToConsole&quot;></param>
private static void WriteLog( string message )
{
using ( StreamWriter sw = new StreamWriter( LogName, true ) )
{
sw.WriteLine( message );
}
}

/// <summary>
/// Don't want any word instances running when the app starts
/// </summary>
private static void KillWord()
{
//First thing to do is kill of WINWORD.EXE
WriteLog( &quot;Killing any pre-existing MS Word instances...&quot; );
Process[] kill = Process.GetProcessesByName( MSWordProcessName );
foreach ( Process killme in kill )
{
killme.Kill();
}
}

/// <summary>
///
/// </summary>
/// <returns></returns>
private static string Greeting()
{
StringBuilder sb = new StringBuilder();
sb.Append( &quot;Print Processor - unexus2000@yahoo.co.uk 2003\r\n&quot; );
sb.Append( &quot;Author - Glenn B\r\n&quot; );
sb.Append( &quot;Processing Started @ &quot; );
sb.Append( DateTime.Now.ToString( &quot;yyyy-MM-dd HH:mm:ss&quot; ) );

return sb.ToString();
}

/// <summary>
/// Added this to stop it printing any of the temporary documents that may get generated
/// </summary>
/// <param name=&quot;dirtyFiles&quot;></param>
/// <returns></returns>
private static string[] CleanTempFiles( string[] dirtyFiles )
{
ArrayList temp = new ArrayList();
foreach ( string s in dirtyFiles )
{
if ( s.IndexOf( &quot;~&quot; ) == -1 )
{
temp.Add( s );
}
}
return (string[])temp.ToArray( typeof(string) );
}

/// <summary>
/// Probably something in the framework to do this, could have done it OOP style, but this will.
/// </summary>
/// <param name=&quot;source&quot;></param>
/// <param name=&quot;startIndex&quot;></param>
/// <param name=&quot;count&quot;></param>
/// <returns></returns>
private static string[] CopyRange( string[] source, int startIndex, int count )
{
string[] range = new string[count];
for( int i = 0; i < count; i++ )
{
range = source[startIndex + i];
}
return range;
}
#endregion

#region &quot;Printer type stuff&quot;

/// <summary>
/// Processes the parse print queue information and checks against the current batch
/// to see if it's still printing.
/// </summary>
/// <returns></returns>
private static bool StillPrintingBatch()
{
bool spb = false;
//Check to see if any of the files in the batch are still printing
foreach ( string queueItem in ParsePrintQueue() )
{
foreach( string fileName in m_ActiveBatch )
{
if ( fileName.IndexOf( queueItem ) != -1 )
{
spb = true;
break;
}
}
if ( spb )
{
break;
}
}

return spb;
}

private static void CheckPrintQueue()
{
//Check to see if the batch is complete, if so set the property

if ( StillPrintingBatch() )
{
m_BatchComplete = false;
}
else
{
m_BatchComplete = true;
}
}

/// <summary>
///
/// </summary>
/// <returns>Returns a parsed array of print queue entries</returns>
private static string[] ParsePrintQueue()
{
ObjectQuery oq = new ObjectQuery( &quot;SELECT * FROM Win32_PrintJob&quot; );

ManagementObjectSearcher mos = new ManagementObjectSearcher( oq );
ManagementObjectCollection moc = mos.Get();

ArrayList doc = new ArrayList();
foreach ( ManagementObject mo in moc )
{
string document = mo[&quot;Document&quot;].ToString();
int li = document.LastIndexOf( &quot;-&quot;, document.Length );
doc.Add( document.Substring( li + 1 ).Trim() );
}

return ( string[] )doc.ToArray( typeof( string ) );
}
#endregion

#region &quot;Properties&quot;

/// <summary>
/// obtains the interval from the xml file
/// </summary>
private static int QueryQueueInterval
{
get { return int.Parse( m_Configuration.SelectSingleNode( &quot;*/QueryQueueInterval&quot; ).InnerText );}
}

private static string MSWordProcessName
{
get { return m_Configuration.SelectSingleNode( &quot;*/MSWordProcessName&quot; ).InnerText; }
}

private static string MSWordPath
{
get { return m_Configuration.SelectSingleNode( &quot;*/MSWordPath&quot; ).InnerText; }
}

private static string LogName
{
get { return m_Configuration.SelectSingleNode( &quot;*/LogName&quot;, m_Nsm ).InnerText; }
}

private static bool LoggingEnabled
{
get { return ( m_Configuration.SelectSingleNode( &quot;*/LogName/@LoggingEnabled&quot; ).InnerText == &quot;true&quot;) ? true : false; }
}

private static int BatchSize
{
get { return int.Parse( m_Configuration.SelectSingleNode( &quot;*/BatchSize&quot; ).InnerText );}
}
#endregion
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top