Print html document from Windows Service without print dialog - c#

I am using a windows service and i want to print a .html page when the service will start. I am using this code and it's printing well. But a print dialog box come, how do i print without the print dialog box?
public void printdoc(string document)
{
Process printjob = new Process();
printjob.StartInfo.FileName = document;
printjob.StartInfo.UseShellExecute = true;
printjob.StartInfo.Verb = "print";
printjob.StartInfo.CreateNoWindow = true;
printjob.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
printjob.Start();
}
Have there any other way to print this without showing the print dialog box.
Update: in response to this:
But i have already used this class but when i am calling the
axW.ExecWB(SHDocVw.OLECMDID.OLECMDID_PRINT,SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_PROMPTUSER , ref em, ref em);
My program getting block here when i am using from window service but it is working fine from windows application.

First off, here's the code:
using System.Reflection;
using System.Threading;
using SHDocVw;
namespace HTMLPrinting
{
public class HTMLPrinter
{
private bool documentLoaded;
private bool documentPrinted;
private void ie_DocumentComplete(object pDisp, ref object URL)
{
documentLoaded = true;
}
private void ie_PrintTemplateTeardown(object pDisp)
{
documentPrinted = true;
}
public void Print(string htmlFilename)
{
documentLoaded = false;
documentPrinted = false;
InternetExplorer ie = new InternetExplorerClass();
ie.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(ie_DocumentComplete);
ie.PrintTemplateTeardown += new DWebBrowserEvents2_PrintTemplateTeardownEventHandler(ie_PrintTemplateTeardown);
object missing = Missing.Value;
ie.Navigate(htmlFilename, ref missing, ref missing, ref missing, ref missing);
while (!documentLoaded && ie.QueryStatusWB(OLECMDID.OLECMDID_PRINT) != OLECMDF.OLECMDF_ENABLED)
Thread.Sleep(100);
ie.ExecWB(OLECMDID.OLECMDID_PRINT, OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, ref missing, ref missing);
while (!documentPrinted)
Thread.Sleep(100);
ie.DocumentComplete -= ie_DocumentComplete;
ie.PrintTemplateTeardown -= ie_PrintTemplateTeardown;
ie.Quit();
}
}
}
You can access the SHDocVw namespace by adding a reference to 'Microsoft Internet Controls', found on the COM tab of the Add Reference dialog.
More information on the InternetExplorer object can be found on MSDN.
The Navigate() method will load the HTML file. The other parameters allow you to specify optional parameters, such as flags and headers.
We can't print until the document is loaded. Here, I enter a loop waiting until the DocumentComplete event is called, upon which a flag is set notifying us that navigation has completed. Note that DocumentComplete is called whenever navigation is finished - upon success or failure.
Once the documentLoaded flag is set, the printing status is queried via QueryStatusWB() until printing is enabled.
Printing is started with the ExecWB() call. The OLECMDID_PRINT command is specified, along with the option OLECMDEXECOPT_DONTPROMPTUSER to automatically print without user interaction. An important note is that this will print to the default printer. To specify a printer, you will have to set the default printer (in code, you could call SetDefaultPrinter()). The two final parameters allow optional input and output parameters.
We don't want to quit until printing is complete, so once again a loop is entered. After the PrintTemplateTeardown event is fired, the documentPrinted flag is set. The objects can then be cleaned up.

From this site http://www.ussbd.com/printhtm.html
using HtmlPrinter;
hpObj=new HtmlPrinter.HtmlPrinter();
hpObj.PrintUrlFromMemory(txtUrl.Text);
Now you add the code in your project to print html page from its source text:
HtmlPrinter.HtmlPrinter hpObj=new HtmlPrinter.HtmlPrinter();
hpObj.PrintHtml(txtString.Text, true);
If you want to print without the print dialog then use the following line:
hpObj.PrintHtml(txtString.Text, false);

Here's another way to print without a print dialog. You create a PrintDialog object, initialize it and then call the Print() method.
The function below is used to print a small 2"x0.75" barcode label. You'll need to figure out a way to get an Document object from the html file.
public void PrintToPrinter(string printerName)
{
PrintDialog pd = new PrintDialog();
pd.Document = userControl11.PrintDoc; // <--- Update this line with your doc
pd.PrinterSettings.PrinterName = printerName;
try
{
pd.Document.DocumentName = "My Label";
pd.Document.DefaultPageSettings.PaperSize = new System.Drawing.Printing.PaperSize("2-.75", 200, 75);
pd.Document.DefaultPageSettings.Margins = new System.Drawing.Printing.Margins(0, 0, 0, 0);
//pd.PrinterSettings.Copies = (short)mNumCopies;
pd.Document.PrinterSettings.Copies = (short) mNumCopies;
pd.Document.Print();
}
catch
{
MessageBox.Show("INVALID PRINTER SPECIFIED");
}
}

You can use the PrintDocument class in the System.Drawing.Printing namespace to give you more control over the printing, see here for more info.
For example you can do the following:
using (PrintDocument doc = new PrintDocument())
{
doc.PrintPage += this.Doc_PrintPage;
doc.DefaultPageSettings.Landscape = true;
doc.DocumentName = fileNameOfYourDocument;
doc.Print();
}
Then a function is raised for each page to be printed and you are given a Graphics area to draw to
private void Doc_PrintPage(object sender, PrintPageEventArgs ev)
{
....
ev.Graphics.DrawImage(image, x, y, newWidth, newHeight);
}
This does require you handle the actual drawing on the text/image to the page, see here for more info.

OLECMDEXECOPT_PROMPTUSER seems to force a prompt to the user to select printer and all associated stuff, which I am pretty sure is not allowed from a service. Can someone verify this?

Related

C# Set PageSize for Print using ProcessStartInfo [duplicate]

I am trying to print from a web browser control in a winform application.The matter is it sets letter as default paper size but I need A4. Also it automatically sets some margins wrong, I can set them to correct settings manually but I want to do it programmatically.
How is it possible?
Here is my code to print.
private void metroButton1_Click(object sender, EventArgs e)
{
loadprintData();
// Create a WebBrowser instance.
WebBrowser webBrowserForPrinting = new WebBrowser();
// Add an event handler that prints the document after it loads.
wa.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(ShowPrintDocument);
wa.ShowPrintPreviewDialog();
reloadpage();
}
private void ShowPrintDocument(object sender,WebBrowserDocumentCompletedEventArgs e)
{
// Print the document now that it is fully loaded.
((WebBrowser)sender).ShowPrintPreviewDialog();
// Dispose the WebBrowser now that the task is complete.
// ((WebBrowser)sender).Dispose();
reloadpage();
}
private void PrintDocument(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Print the document now that it is fully loaded.
((WebBrowser)sender).Print();
// Dispose the WebBrowser now that the task is complete.
// ((WebBrowser)sender).Dispose();
}
To change the Margin size you have to edit the (HKCU) registry before printing:
string pageSetupKey = "Software\\Microsoft\\Internet Explorer\\PageSetup";
bool isWritable = true;
RegistryKey rKey = Registry.CurrentUser.OpenSubKey(pageSetupKey, isWritable);
if (stringToPrint.Contains("something"))
{
rKey.SetValue("margin_bottom", 0.10);
rKey.SetValue("margin_top", 0.25);
}
else
{
//Reset old value
rKey.SetValue("margin_bottom", 0.75);
rKey.SetValue("margin_top", 0.75);
}
Dont forget to set it back to the default.
Ref Microsoft KB Article
To change the Paper size you have to edit the (HKCU) registry in another place before printing:
string pageSetupKey2 = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
isWritable = true;
rKey = Registry.CurrentUser.OpenSubKey(pageSetupKey2, isWritable);
// Use 1 for Portrait and 2 for Landccape
rKey.SetValue("PageOrientation", 2, RegistryValueKind.DWord);
// Specifies paper size. Valid settings are 1=letter, 5=Legal, 9=A4, 13=B5.Default setting is 1.
rKey.SetValue("PaperSize", 9, RegistryValueKind.DWord);
// Specifies print quality
rKey.SetValue("PrintQuality ", 1, RegistryValueKind.DWord);
Ref MSDN
Well i have tried so many things but at the end i found that it is not possible to program the printer setting from the code easily. but i could do the margin by the answer of #jeremy.
And i found out that For printing from WebBrowser control it uses internet explorer all we know but at the beginning it was using explorer 7 and i had to change it to explorer 11 as default.
Then i saw it explorer does not have his own print settings. it uses the default printers settings.
So you have to change the Default printers previews.You will see the preview will show that way.

Display MS Word document in window for editing

 Hello, I am building windows C# WPF application which communicates with Microsoft Office word document (.docx). The app should update .docx template file with user input and this step is achived successfuly using OpenXML. The other part of the app is to show the edited word document to the user inside of the applicaion window or using MS Word and allow him to add some more information if he wants to do it. The problem I am facing is:
I should disable my application controls while word document is opened and I should enable them once the word is closed, also I want to know if the word app was saved (if a user made changes).  The next code is button click event for openning word document:
using System.Windows;
using Microsoft.Office.Interop.Word;
using Application = Microsoft.Office.Interop.Word.Application;
public class MainWindowViewModel : BaseViewModel
{
...
... some view model initialization
...
public bool AreControlsEnabled { get; set; } = true;
private void OpenWord ()
{
AreControlsEnabled = false;
var app = new Application()
{
Visible = true
};
var doc = app.Documents.Open("pathtofile.docx");
var docClass = app.ActiveDocument as DocumentClass;
docClass.DocumentEvents2_Event_Close += DocClass_DocumentEvents2_Event_Close;
docClass.DocumentEvents_Event_Close += DocClass_DocumentEvents_Event_Close;
app.DocumentBeforeClose += new ApplicationEvents4_DocumentBeforeCloseEventHandler(DocBeforeClose);
app.DocumentBeforeSave += new ApplicationEvents4_DocumentBeforeSaveEventHandler(DocBeforeSave);
}
private void DocClass_DocumentEvents2_Event_Close ()
{
MessageBox.Show("DocClass_DocumentEvents2_Event_Close");
AreControlsEnabled = true;
}
private void DocClass_DocumentEvents_Event_Close ()
{
MessageBox.Show("DocClass_DocumentEvents_Event_Close");
AreControlsEnabled = true;
}
private void DocBeforeClose (Document doc, ref bool cancel)
{
MessageBox.Show("DocBeforeClose");
AreControlsEnabled = true;
}
private void DocBeforeSave (Document doc, ref bool SaveAsUI, ref bool cancel)
{
MessageBox.Show("DocBeforeSave");
AreControlsEnabled = true;
}
}
 When I run the code - I see opened MS Word document as expected, but when I close it or save - no one of events fired and I can't understand why. Also, I can use System.Diagnostics.Process to launch the Word and add exit event to it, but in this way I can't know if the user applied some changes. So, if someone solved this problem, help me please.   Thank you for reading and answers
You can:
Get the Current Changed Date of the File
Use System.Diagnostics.Process to start Word.
After The process ends you check the Changed Date again
If the user saved the file the Changed Date is updated
I don't know if the process is still running if the user just closes the document but not word. For this you could observe the Folder of the Dokument for thos ~... Temp Files Word creates while a document is open...

How to know if word document opened by form is successfully opened in c#

Background:
I am creating application to capture the screen and paste the screenshot in the word document one below other.
Technical Part:
When I run the application, a word document opens along with a form having 'Capture' button. The button when clicked captures the screen and an window is opened asking for the caption and then screenshot with the caption is pasted in currently open word doc.
My Question
When user clicks Capture button, I want to check whether the document opened previously is still open or not. If document is not open, I will prompt user to open a new blank document.
I searched many forums and internet, but mostly all suggested to get the filename from the currently running processes. Note that my word document is unsaved, so it will have names like 'Document 1' etc. which will be a bad way to check.
I have pasted my code below for reference.
Any inputs will be appreciated. Thanks in advance.
WordProcessing.cs
namespace WordProcessing
{
class MSWord
{
Word.Application wordApp = new Word.Application(); //Creates new Word Instance
public MSWord()
{
wordApp.Visible = true;
Word.Document oDoc = wordApp.Documents.Add(ref useDefaultValue, ref useDefaultValue, ref useDefaultValue, ref useDefaultValue);
}
}
}
Screencapture.cs
namespace Screencapture
{
public partial class form_capture : Form
{
MSWord word = new MSWord();
public void button1_Click(object sender, EventArgs e)
{
/* Here I want to check whether document opened by 'word' object is still open */
ScreenCapture screen = new ScreenCapture();
screen.CaptureScreenToFile("D:/image.png", System.Drawing.Imaging.ImageFormat.Png);
//Form to ask for caption
DataForm textarea = new DataForm();
textarea.ShowDialog();
textarea.Focus();
word.InsertText(DataForm.textarea_text);
word.InsertImage(#"D:\image.png");
}
}
}
PS: Ignore any syntax errors or missing function definitions. I have pasted shorter version for better understanding.
How about a try/catch on focusing the document?
try
{
oDoc.Activate();
//or on the application
wordApp.Activate();
}
catch
{
//Open a new document or ask
Messagebox.Show("Please open a new Word Document");
}
You could try using the File.Open() method. If the document is open, it should provide you with an exception which can print your custom prompt:
FileStream stream = null;
bool isOpen = false;
try
{
stream = File.Open(#"DFilePath&Name",FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch(IOException)
{
isOpen = true;
//Show your prompt here.
}
finally
{
if (stream != null)
stream.Close();
}
if(!isOpen)
Process.Start(#"FilePath&Name");

BHO only working in first IE window or tab open

I've been reading and following up on how to write a BHO in IE using C# and I can register it just fine and run it but it only works properly when in the first window\tab I've got open.
I know aspects of it are triggering in every new window but the changes don't "stick" or apply if they're affecting the DOM. So, for example, I load a page that displays some text in the top of the page, it will always be there in the first tab but all the others it may be there are first then disappear or not show up at all.
I'm using c# 4 on Win7x64 using IE11. Protected mode doesn't appear to affect this one way or the other.
My code is just a mix of what's up here tutorial wise, so nothing fancy.
namespace IEExtention
{
[
ComVisible(true),
Guid("e8483cfd-d208-45f7-837c-3cdca573d84a"),
ClassInterface(ClassInterfaceType.None)
]
public class BHO : IObjectWithSite
{
private WebBrowser webBrowser;
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private object mySite;
public int SetSite(object site)
{
if (site != null)
{
mySite = site;
webBrowser = (WebBrowser)site;
webBrowser.DocumentComplete +=
new DWebBrowserEvents2_DocumentCompleteEventHandler(
this.OnDocumentComplete);
}
else
{
webBrowser.DocumentComplete -=
new DWebBrowserEvents2_DocumentCompleteEventHandler(
this.OnDocumentComplete);
webBrowser = null;
}
return 0;
}
public int GetSite(ref Guid guid, out IntPtr ppvSite)
{
IntPtr punk = Marshal.GetIUnknownForObject(webBrowser);
int hr = Marshal.QueryInterface(punk, ref guid, out ppvSite);
Marshal.Release(punk);
return hr;
}
public void OnDocumentComplete(object pDisp, ref object URL)
{
log.Debug("test");
if (pDisp != mySite)
{
return;
}
HTMLDocument document = (HTMLDocument)this.webBrowser.Document;
document.title = "Hello, StackOverflow!";
try
{
IHTMLDOMNode greetings = document.createTextNode("Hi there!");
IHTMLDOMNode body = document.body as IHTMLDOMNode;
body.insertBefore(greetings, body.firstChild);
}
catch (Exception e)
{
//whoo!!
}
}
It's had me stumped for a few days as even something as changing the document.title doesn't always stay.
I was able to work around this issue by threading my BHO and sleeping it for about half a second. Interestingly enough I needed to up the sleep to about 1.5 seconds to deal with outside links (say something coming from outlook) to load up and get everything to display.
I'm not sure if this is the best way to do it but it solved my problem with it only working in the first tab.

How to use AxWebBrowser in console application

I wanna use AxWebBrowser on console application, but it give me following exception:
Exception of type 'System.Windows.Forms.AxHost+InvalidActiveXStateException' was thrown.
anybody please help me on this by any sample code for using AxWebBrowser in console application c# without any exeption ...
Yes, the [STAThread] attribute is required on your Main() method so that COM is initialized properly to make the main thread a Single Threaded Apartment. That's not all though, you will also need to pump a message loop. That's a requirement for an STA. Without one, WebBrowser cannot update its state or run its event handlers, you'll never get the DocumentCompleted event for example. You can get a message loop with Application.Run().
Your console application is now indistinguishable from a Windows Forms application. It is actually easier to get everything right by starting a new project with the Windows Forms application project template, then Project + Properties, Output type = Console Application. Edit the Application.Run() call in Program.cs so it doesn't create a form. It won't make dealing with Application.Run() any easier, consider a Timer to run code.
Add the STAThread attribute to your Main method.
However, you should not be using the "raw" ActiveX control.
Instead, add a reference to System.Windows.Forms.dll and use the WebBrowser class. (Yes, you can do that in a Console app)
Also, automating IE is not ideal. You should consider using the WebCLient class.
My class is as below but in the run time it gives me System.Windows.Forms.AxHost+InvalidActiveXStateException:
public class Browse
{
private static AxWebBrowser wBrowser;
public static Result StartBrowse(string url)
{
var validUri = (url.Contains("http://") ? url : "http://" + url);
wBrowser = new AxWebBrowser();
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(AxWebBrowser));
((ISupportInitialize) (wBrowser)).BeginInit();
wBrowser.OcxState = ((AxHost.State)(resources.GetObject("wBrowser.OcxState")));
wBrowser.NewWindow2 += wBrowser_NewWindow2;
wBrowser.NewWindow3 += wBrowser_NewWindow3;
wBrowser.DocumentComplete += wBrowser_DocumentComplete;
wBrowser.DownloadComplete += wBrowser_DownloadComplete;
if (string.IsNullOrEmpty(html) || validUri != url)
{
object empty = System.Reflection.Missing.Value;
wBrowser.Silent = true;
wBrowser.Navigate(validUri, ref empty, ref empty, ref empty, ref empty);
}
return null;
}
static void wBrowser_DownloadComplete(object sender, EventArgs e)
{
doAlgorithm();
}
static void wBrowser_DocumentComplete(object sender, DWebBrowserEvents2_DocumentCompleteEvent e)
{
doAlgorithm();
}
static void wBrowser_NewWindow3(object sender, DWebBrowserEvents2_NewWindow3Event e)
{
e.cancel = true;
}
static void wBrowser_NewWindow2(object sender, DWebBrowserEvents2_NewWindow2Event e)
{
e.cancel = true;
}
}
First, the thread in which the control is hosted must be in single-threaded apartment, you can either put the STAThread in your Main method, or create a separated Thread like this:
var thread = new Thread(() =>
{
//My code
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join(); //Wait for thread termination
Second, you must start a message loop:
while (true) //Put some exit condition
System.Windows.Forms.Application.DoEvents();
Third the control must be hosted in a visible form. The form must be visible just once, so to avoid "flickering", you can write this code:
var browser = new AxWebBrowser();
var hostForm = new Form();
//Set form 0 size, without any control box / title / icon
hostForm.Width = 0;
hostForm.Height = 0;
hostForm.ShowInTaskbar = false;
hostForm.ControlBox = false;
hostForm.ShowIcon = false;
hostForm.MinimizeBox = false;
hostForm.MaximizeBox = false;
//Add browser control
hostForm.Controls.Add(browser);
//Show and immediately hide
hostForm.Show();
hostForm.Hide();
Finally you might want to disable the "click" sound (How to disable click sound in WebBrowser Control)
The final code:
class Program
{
[STAThread]
static void Main(string[] args)
{
URLSecurityZoneAPI.InternetSetFeatureEnabled(URLSecurityZoneAPI.InternetFeaturelist.DISABLE_NAVIGATION_SOUNDS, URLSecurityZoneAPI.SetFeatureOn.PROCESS, true);
var browser = new AxWebBrowser();
var hostForm = new Form();
hostForm.Width = 0;
hostForm.Height = 0;
hostForm.ShowInTaskbar = false;
hostForm.ControlBox = false;
hostForm.ShowIcon = false;
hostForm.MinimizeBox = false;
hostForm.MaximizeBox = false;
hostForm.Controls.Add(browser);
hostForm.Show();
hostForm.Hide();
browser.DocumentComplete += delegate(object sender, DWebBrowserEvents2_DocumentCompleteEvent e)
{
var doc = (IHTMLDocument3)browser.Document;
Console.WriteLine(doc.documentElement.innerHTML);
};
browser.Navigate("www.google.com");
while (true)
System.Windows.Forms.Application.DoEvents();
}
}

Categories

Resources