Printing copies of document from form textbox - c#

Is there a way to print the number of copies given in a textbox in a C# windows form application?
With my current code the document gets printed the required number of prints, but after the first print there is a dialog that says that the document already is opened and I have to open a copy. When I open this copy, the document prints again, but only if I accept to open the copy. Is there a way to print the document multiple times without getting the dialog of the copy of the document every time?
When the form is filled in correct, I want it to be stored on my hard drive and want it to print the number given in a textbox on a previous form. The value from this textbox is stored in the variable intAantalPoorten.
Thanks a lot!
Regards Bert
CreateWordDocument(#"N:\De wienes\Productieformulieren\Sjablonen\Poortblad.docx", #"N:\De wienes\Productieformulieren\Producties poortbladen\Poortblad " + txtKlantnaam.Text + "-" + txtReferentie.Text + ".docx");
ProcessStartInfo info = new ProcessStartInfo(#"N:\De wienes\Productieformulieren\Producties poortbladen\Poortblad " + txtKlantnaam.Text + "-" + txtReferentie.Text + ".docx");
for (intAAntalPrints = 0; intAAntalPrints <= intAantalPoorten; intAAntalPrints++)
{
info.Verb = "Print";
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(info);
}

You're probably not using the best programming model. The thing you're doing is relying on the windows shell to open the document and invoke the registered verb (as defined by Word in the local registry). This is the most primitive and least functional way to get the job done. For example, there's no way to change which printer you're printing to...or how many copies or which pages, etc.
Instead, there's a rich programming model that Word (and all the Office apps) provide. You can open documents, and print them specifying the number of copies that you want.
To get access to this programming model, you need to reference the .COM interop assembly for Word, which is:
...and the Office Core interop assembly:
Then, it's just a matter of driving Word to do what you want. For example:
using System;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1: Form
{
public Form1( )
{
InitializeComponent( );
}
private void button1_Click( object sender, EventArgs e )
{
//--> assumes the textBox1.Text contains the file to open...
var app = new Microsoft.Office.Interop.Word.Application( );
var doc = app.Documents.Open( textBox1.Text, ReadOnly: true );
doc.PrintOut( Copies: 1 );
doc.Close( );
app.Quit( );
}
}
}
Note that this requires Word to be installed on the local machine. For more information, check out the word object model.

Related

Network printers ignoring number of copies sent programatically

The setup - a local Windows 10 PC has multiple network printers installed. A GUI C# WinForm application (.NET) is constantly running in the background, and occasionally downloads a PDF file from a predefined URL (read from an *.ini file).
The problem occurs when the said PDF file is printed. Instead of accepting the number of copies sent from the application, the printer keeps printing just one copy of the file.
This is the relevant part of my code:
string webPrinter = "HP LaserJet PCL 6"; // is set in another part of the code
string iniFilePrinter = "hp LaserJet 1320 PCL 5"; // is set in another part of the code - read from the ini file
string dirName = "C:\\mydir";
string newDocName = "mydoc.pdf";
short numCopies = 1;
if(event1 == "event1") { // taken from another part of the code
numCopies = webNumCopies; // taken from another part of the code
} else if(event2 == "event2") {
numCopies = iniNumCopies; // taken from another part of the code - read from the ini file
}
var path = dirName + "\\" + newDocName;
try
{
using (var document = PdfiumViewer.PdfDocument.Load(path))
{
using (var printDocument = document.CreatePrintDocument())
{
System.Drawing.Printing.PrinterSettings settings = new System.Drawing.Printing.PrinterSettings();
string defaultPrinterName = settings.PrinterName;
printDocument.DocumentName = newDocName;
printDocument.PrinterSettings.PrintFileName = newDocName;
printDocument.PrinterSettings.Copies = numCopies;
printDocument.PrintController = new System.Drawing.Printing.StandardPrintController();
printDocument.PrinterSettings.PrinterName = webPrinter;
MessageBox.Show("Before: " + printDocument.PrinterSettings.Copies.ToString() + " --- " + newDocName);
if (!printDocument.PrinterSettings.IsValid)
{
printDocument.PrinterSettings.PrinterName = iniFilePrinter;
if(!printDocument.PrinterSettings.IsValid)
{
printDocument.PrinterSettings.PrinterName = defaultPrinterName;
}
}
MessageBox.Show("After: " + printDocument.PrinterSettings.Copies.ToString() + " --- " + newDocName);
printDocument.Print();
}
}
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
The exception has never been triggered, and the print succeeds on every single try. Changing the number of copies within if/else also happens when the conditions are met, and the MessageBox.Show() parts of the code do show the expected number of copies (2,3,7, anything but 1, when it's not supposed to be 1) immediatelly before invoking printDocument.Print().
I've also tried printing unrelated documents from various other programs (MS Word, various custom applications, PDF readers and the like), and the number of copies has always been 1. However, software like Google Chrome or FireFox manage to get things printed in the specified number of copies.
I was thinking that there might be something about the printer's setting which makes it ignore the number of copies sent. Based on that assumption, I've checked the settings of all of the printers, and have found that the number of copies is actually set to 1.
If that is indeed the cause of my problem, how can I bypass that setting (without actually changing it), the way that Google Chrome and Firefox seem to be able to do it? I know that I could probably change that limit programmatically (set it to my number of copies, and then change it back to the original value, once the printing has been completed), but that doesn't seem like the proper way of doing it.
EDIT
I've expanded my code by including a print dialog, like this:
PrintDialog printDlg = new PrintDialog();
printDlg.Document = printDocument;
printDlg.AllowSelection = true;
printDlg.AllowSomePages = true;
if (printDlg.ShowDialog() == DialogResult.OK)
{
printDocument.Print();
}
Still, the results are the same - even when the user changes the number of copies within the print dialog, the printer ignores them. The same code was tested on another (local) printer, connected to an unrelated Windows 10 PC, and there the number of copies from the dialog was not ignored.
I've also noticed that the print dialog from my application, and that from notepad.exe are different (image below). Is there a way for me to call up the same print dialog notepad.exe uses? The reason I'd like to do this, is because that one gets the job done (xy number of copies in the print dialog, xy number of copies printed).

Word Interop Batch Printing

I have an application that creates multiple (regularly 1000+) Word files and then prints them.
I have created the below code that, once the PrintDialog is Ok'd proceeds to print the documents that reside in a folder. However recently we've had some strange behaviour following some Office updates (its Office 2010, which we cannot upgrade). The screen literally flickers, like a really bad graphics problem, then Word crashes after about 500 prints. This hasn't happened before and has been running for probably 12 months+ without issue.
As you can see, the application opens one instance of Word, then uses that to open>print>close each document. I can't see how this causes a problem, as Word only ever has one document open at a time. The memory size of winword.exe also doesn't increase significantly beyond the size of when its first opened too, so the Office updates don't initially appear to have introduced a memory leak.
Is there a more efficient way of doing this?
if (printDialog.ShowDialog() == DialogResult.OK)
{
int c = 1;
int total = directoryInfo.GetFiles().Count();
// Set the Progress bar details
App.Current.Dispatcher.Invoke((Action)delegate { MainWindow.ui_progressBar.Maximum = directoryInfo.GetFiles().Length; });
// loop through the files in order
foreach (FileInfo report in directoryInfo.GetFiles().OrderBy(x => x.FullName))
{
UpdateUI("Printing " + c.ToString() + " / " + total.ToString());
Microsoft.Office.Interop.Word.Document reportFile = wordApp.Documents.Add(report.FullName);
wordApp.ActivePrinter = printDialog.PrinterSettings.PrinterName;
wordApp.ActiveDocument.PrintOut();
reportFile.Close(SaveChanges: false);
reportFile = null;
PrinterCounter++;
App.Current.Dispatcher.Invoke((Action)delegate { MainWindow.ui_progressBar.Value = PrinterCounter; });
c++;
}
}

Save annotations into SQL Server database using adobe javascript

I am having problems trying to save (insert) a .pdf with annotations into a SQL Server database. The database is located inside Visual Studio and I am currently using adobe javascript to save it, but I run into security settings prevent access to this property or method when i clicked the button inside the pdf. I'm using a pdf button field from spire.pdf to try to save into the db and pass the script into pdf javascript action.
So far, i have tried using trusted privilege function, using adbc connection and odbc connection as well as the soap method but it doesn't work and I'm quite lost at what to do or continue next. These methods can be found inside adobe javascript reference as well as api.
PdfPageBase page = pdf.Pages[i];
PdfButtonField button = new PdfButtonField(page, "Save");
button.Bounds = new RectangleF(420, 10, 100, 40);
button.BorderColor = new PdfRGBColor(Color.AliceBlue);
button.BorderStyle = PdfBorderStyle.Solid;
button.ForeColor = new PdfRGBColor(Color.White);
button.Text = "Save";
button.BackColor = new PdfRGBColor(Color.Blue);
button.ToolTip = "Save";
button.Font = new PdfFont(PdfFontFamily.Helvetica, 9f);
pdf.Form.Fields.Add(button);
String script = "var nButton=app.alert({"
+ " cMsg: \"Do you want to save this paper into the database?\","
+ " nIcon: 2,"
+ " nType : 2,"
+ " cTitle: \"Confirm Save?\""
+ "});"
+ "if ( nButton == 4 ) {var myProxy = SOAP.connect(\"http://localhost:57103/test123.svc?wsdl) \"); var testString = (\"This is a test string\"); var result = (myProxy.echoString(testString)); console.println(\"Result is : + result\")};";
PdfJavaScriptAction confirm = new PdfJavaScriptAction(script);
button.Actions.GotFocus = confirm;
The expected result i should get is to be able to save the pdf with annotations into the SQL Server database inside Visual Studio and being able to retrieve it with the annotations. However, the actual result showed the security settings prevent access to this property or method and i cannot proceed to continue.
Would really appreciate some help, thank you! :)
ADBC in Acrobat JavaScript is has been off by default since Acrobat 9. To activate ADBC, create a registry key of type DWORD with the name “bJSEnable” and a value of “true” (1) in the following location:
HKEY_CURRENT_USER\SOFTWARE\Adobe\Adobe Acrobat\VERSION\ADBC
Also the SOAP object was deprecated beginning with Acrobat 8.0. Use Net.SOAP instead.

How to launch a process which will open a text file in any editor and automatically move cursor to a certain line number?

From c#, I want to launch a process which will open a text file in any editor and automatically move cursor to a certain line number.
I can open a file using
Process.Start(#"c:\myfile.txt");
but I don't know how to move cursor at specific location in that file.
Answer with source code:
yes, I used notepad++
private void openLog() {
try {
// see if notepad++ is installed on user's machine
var nppDir = (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Notepad++", null, null);
if (nppDir != null) {
var nppExePath = Path.Combine(nppDir, "Notepad++.exe");
var nppReadmePath = Path.Combine(yourDirectory,fileName );
var line = 20;
var sb = new StringBuilder();
sb.AppendFormat("\"{0}\" -n{1}", nppReadmePath, lineNo);
Process.Start(nppExePath, sb.ToString());
} else {
string newPath = #"\\mySharedDrive\notpad++\bin\notepad++.exe";
Process.Start(newPath, #"\\" + filePath + " -n" + lineNo); // take exe from my shared drive
}
} catch (Exception e) {
Process.Start(#"\\" + FilePath); // open using notepad
}
}
Get Notepad++, then you can do this:
var nppDir = (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Notepad++", null, null);
var nppExePath = Path.Combine(nppDir, "Notepad++.exe");
var nppReadmePath = Path.Combine(nppDir, "readme.txt");
var line = 20;
var sb = new StringBuilder();
sb.AppendFormat("\"{0}\" -n{1}", nppReadmePath, line);
Process.Start(nppExePath, sb.ToString());
In this example we get install path of n++ from the registry, build path to exe and readme.txt file, opens its own readme.txt file with cursor on line 20.
Using StringBuilder is more efficient than using multiple appends (explanation somewhere on SO).
The solution very heavily depends on which process/editor is opened on your system. That editor would have to have a developer API that you could use to access functionality such as setting ranges and altering the cursor position. For example, if the editor that is opened is Microsoft Word, you would use the Word Interop API to set a selection at a specific position. There is no universal way to do this in 'any editor' since each one has its own API (or no outward facing API at all).
Perhaps you are going this the wrong way. I'm not sure what you are trying to accomplish, but I think it would be alot easier to just open the text file in an editor that belongs to your application. Perhaps another form with a WYSIWYG editor control. That way you have full control on where the cursor will land in that editor. Otherwise, there are just way too many unknowns for anything feasibly workable.

C# Prevent Adobe Reader Window from coming up when trying to print a document

For reasons I can't get into right now, I need to prevent the Adobe Reader window from opening up when I try to print a document. The developer that was working on this before me has the following flags set, although I'm not really sure what they're for -
if (RegistryManager.GetAcrobatVersion() >= 9.0f)
printerArg = "\"" + printerName + "\"";
else
printerArg = printerName;
Process myProc = new Process();
myProc.StartInfo.FileName = fileName;
myProc.StartInfo.Verb = "printto";
myProc.StartInfo.UseShellExecute = true;
myProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
myProc.StartInfo.CreateNoWindow = true;
myProc.StartInfo.Arguments = "\"" + printerName + "\"";
bool result = myProc.Start();
if (myProc.WaitForInputIdle())
{
if (!myProc.HasExited)
{
myProc.WaitForExit(Convert.ToInt32(5000));
myProc.Kill();
}
}
myProc.Close();
Any help is much appreciated!
Thanks,
Teja.
While I can't answer your question specifically, I found that I couldn't do this as Adobe changed Reader I think at version 9 or 10 so that you couldn't supress the print dialog, and the window itself kept coming up anyway, and since my users all had different versions of Reader installed I couldn't get anything consistently working. If you want to try anyway have a look at Reader's API - you need to add a reference to the correct COM library and go from there. Painful.
I ended up dropping Adobe completely by running the PDF through GhostScript. Following is the helper class I created to do the job. gsExePath should be something like C:\Program Files\gs\gs8.71\bin\gswin32c.exe.
public class GSInterface
{
public string GhostScriptExePath { get; private set; }
public GSInterface(string gsExePath)
{
this.GhostScriptExePath = gsExePath;
}
public virtual void CallGhostScript(string[] args)
{
var p = new Process();
p.StartInfo.FileName = this.GhostScriptExePath;
p.StartInfo.Arguments = string.Join(" ", args);
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();
p.WaitForExit();
}
public void Print(string filename, string printerName)
{
this.CallGhostScript(new string[] {
"-q",
"-sDEVICE=mswinpr2",
"-sPAPERSIZE=a4",
"-dNOPAUSE",
"-dNoCancel",
"-dBATCH",
"-dDuplex",
string.Format(#"-sOutputFile=""\\spool\{0}""", printerName),
string.Format(#"""{0}""", filename)
});
}
}
The following should print to the Windows default printer:
var printerName = new System.Drawing.Printing.PrinterSettings().PrinterName;
var gs = new GSInterface(gsExePath);
gs.Print(filename, printername);
This may apply only to the computers where I work, or, more broadly, to this version of Adobe (10) on PCs with Windows 7 installed, but I was able to suppress the opening of Acrobat (Pro) each time I printed to .pdf in any other application by doing the following:
Control Panel > (Devices and) Printers > Double click 'Adobe PDF'> Click 'Printer' > 'Printing Preferences' > Uncheck "View Adobe PDF Results" in the 'Adobe PDF Settings' Tab.
Maybe it is helpful for you to use the "/n" parameter of Adobe Reader.
At least your program keeps the focus. But one instance of the reader stays open.
AcroRd32.exe /n /t ...
See: Questions 619158
Regarding the solution Adam proposed (switching off the View Adobe PDF Results from control panel) and Serge Belov commented (on how to do it programmatically), in the registry this change affects the ViewPrintOutput value at 4 positions:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Adobe PDF\PrinterDriverData
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Print\Printers\Adobe PDF\PrinterDriverData
Computer\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Print\Printers\Adobe PDF\PrinterDriverData
Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers\Adobe PDF\PrinterDriverData
However, if you change it from the registry, it doesn't affect the adobe pdf's behaviour, it still shows the resulting pdf after printing
This might be helpful, though
https://groups.google.com/g/microsoft.public.access.reports/c/LWphtEVp6UI

Categories

Resources