I have am writing a POS application, which requires to print invoice very often.
I need to send it directly to printer instead of viewing the print dialogue. Using Reportviewer_renderingcomplete, I can avoid seeing the report but I do not know how to avoid seeing the print dialogue box and print report without user intervention?
Thanks a lot.
Here is how you can do it:
Dim m_currentPageIndex As Integer
Private m_streams As IList(Of Stream)
Dim report As New LocalReport()
report.DataSources.Add(New ReportDataSource("testData", reportData.Tables(0)))
report.ReportEmbeddedResource = "ReportsLibrary.rptTestData.rdlc"
Dim deviceInfo As String = "<DeviceInfo><OutputFormat>EMF</OutputFormat><PageWidth>8.5in</PageWidth><PageHeight>11in</PageHeight><MarginTop>0.25in</MarginTop><MarginLeft>0.25in</MarginLeft><MarginRight>0.25in</MarginRight><MarginBottom>0.25in</MarginBottom></DeviceInfo>"
Dim warnings As Warning()
m_streams = New List(Of Stream)()
report.Render("Image", deviceInfo, CreateStream, warnings)
For Each stream As Stream In m_streams
stream.Position = 0
Next
Dim printDoc As New PrintDocument()
printDoc.PrinterSettings.PrinterName = "<your default printer name>"
Dim ps As New PrinterSettings()
ps.PrinterName = printDoc.PrinterSettings.PrinterName
printDoc.PrinterSettings = ps
printDoc.PrintPage += New PrintPageEventHandler(PrintPage)
m_currentPageIndex = 0
printDoc.Print()
Where PrintPage defined as follows:
' Handler for PrintPageEvents
Private Sub PrintPage(sender As Object, ev As PrintPageEventArgs)
Dim pageImage As New Metafile(m_streams(m_currentPageIndex))
' Adjust rectangular area with printer margins.
Dim adjustedRect As New Rectangle(ev.PageBounds.Left - CInt(ev.PageSettings.HardMarginX), ev.PageBounds.Top - CInt(ev.PageSettings.HardMarginY), ev.PageBounds.Width, ev.PageBounds.Height)
' Draw a white background for the report
ev.Graphics.FillRectangle(Brushes.White, adjustedRect)
' Draw the report content
ev.Graphics.DrawImage(pageImage, adjustedRect)
' Prepare for the next page. Make sure we haven't hit the end.
m_currentPageIndex += 1
ev.HasMorePages = (m_currentPageIndex < m_streams.Count)
End Sub
This is an interesting walkthrough by Microsoft: Printing a Local Report without Preview.
It's a different approach from yours because it prints directly a report without using ReportViewer and RenderingComplete event.
In order to not display PrintDialog box you must set printDoc.PrinterSettings.PrinterName with your default printer name.
Maybe you can store this value in a user configuration file.
It is actually far more simple than you would have imagined.
Within your form, include a "PrintDocument" component from the Toolbox.
Within your code behind, you will want to call the following method on your newly added component.
PrintDoc.Print()
The documentations state that the Print() "Starts the document's printing process". It will automatically begin printing the default set printer.
As tezzo mentioned, to set the Printer manually you can use the following snippet:
PrintDoc.PrinterSettings.PrinterName = "YourPrinterNameHere"
PrintDoc.PrinterSettings.PrinterName "gets or sets the name of the printer to use" as according to documentation. And if you need any further help, check out this video.
Please note however that video does not mention how to print "silently". It is just a good reference for beginners to see how the Print Components work together.
Related
I am trying to switch users to use a different printer for envelopes in Word. If they create the envelope, then print it, it works great using DocumentBeforePrint. However, this event is NOT fired when using the Print button on the dialog Mailings --> Envelopes. Is there any event fired when this happens that I can catch?
thanks,
Mike
There is no event, as such, however...
It is possible to Display, Execute or Show Word's built-in dialog boxes. A number of the controls in these dialog boxes are exposed so that they can be set or read. And the button used to dismiss the dialog box returns a value that can be evaluated.
The list of exposed controls is documented here. The WdWordDialog enumerator for envelopes is wdDialogToolsCreateEnvelope. The properties listed are for both envelopes and labels, keep that in mind when sorting through the possibilities. Note that there is no IntelliSense for these properties. (For .NET people reading this, the properties are accessed via late-binding, meaning C# must use PInvoke in order to work with them.)
To read the user's input, place the properties after the method; to make "default setting", place the properties before the method.
Dismissing this dialog box returns the following values:
0 Cancel (or the "X" button)
1 Print
2 Add to Document:
Since you need to do something before the print job is sent, you probably need to use Display rather than Show. Display does not execute the dialog box when the user dismisses it. Instead, it's necessary to capture the settings, do something with them, then Execute the the dialog box.
For example, the following code displays the dialog box to the user, capture's the delivery address typed into that box, then handles the various return values.
Sub PrintEnvelopes()
Dim dlg As Word.Dialog
Dim retVal As Long
Dim recipAddress As String
Set dlg = Application.Dialogs(wdDialogToolsCreateEnvelope)
With dlg
retVal = .Display
recipAddress = .envaddress
End With
Select Case retVal
Case 1 'Print
With dlg
'Change the printer here
.envaddress = recipAddress
.Execute
End With
Case 0 'Cancel
Case 2 'Add to document
With dlg
.envaddress = recipAddress
.Execute
End With
End Select
End Sub
Turns out, there are events you can place in a module to intercept the Envelope tool launch (h/t http://www.gmayor.com/fax_from_word.htm). As such, I added the following to one of my modules, and it runs when Mailings-->Envelopes is selected, so I can switch the printer, load the dialog, then switch the printer back after the dialog is finished:
Sub ToolsCreateEnvelope()
Dim DoChangePrinter As Boolean
Dim OriginalPrinterName As String
DoChangePrinter = False
OriginalPrinterName = Application.ActivePrinter
CurrentPrinterName = OriginalPrinterName
//Change to use color if on B&W printer
If InStr(1, LCase(CurrentPrinterName), "b&w") Then
CurrentPrinterName = Replace(CurrentPrinterName, "B&W", "COLOR")
DoChangePrinter = True
End If
If (DoChangePrinter) Then ChangePrinter
Application.ActiveDocument.Envelope.DefaultOmitReturnAddress = True
//Show dialog
Dim oDlg As Dialog
Set oDlg = Dialogs(wdDialogToolsCreateEnvelope)
With oDlg 'Pop up the envelopes dialog
.extractaddress = True
.Show
End With
ActivePrinter = OriginalPrinterName 'Restore the original printer
End Sub
I know my question is not focused on a precise problem but Google ran out of results. I'm trying to make a little app in Visual Basic .Net and have a HTML string which needs to be printed to a specific printer, and the problem is that i've tried to:
write out to a HTML file then print it with a WebBrowser: the problem is that i can't print to a specific printer, only to the default one.
convert it to a PDF with htmlToPdf package but: (1) it needs Acrobat Reader AND file association in Windows, (2) it opens the Acrobat Reader which is not quite professional.
EDIT
Thanks to a solution provided by the first commenter, i've made it partially. The problem is that the first document is printed perfectly, but the next ones are printed to the first specified printer (in Devices and Printers the default printer changes but the target printer remains the first one) Here is the code:
Public Sub PrintHTML(ByVal text As String, ByVal printer As String)
Try
LogData("Changing default printer to " & printer)
Dim wtype = Type.GetTypeFromProgID("WScript.Network")
Dim instance = Activator.CreateInstance(wtype)
wtype.InvokeMember("SetDefaultPrinter", System.Reflection.BindingFlags.InvokeMethod, Nothing, instance, New Object() {printer})
Catch ex As Exception
LogData("Changing failed...")
LogData(ex.ToString)
Finally
LogData("PrintHTML Init with " & printer)
Me.wbForPrint.Navigate("about:blank")
If Not WebBrowserReadyState.Interactive = WebBrowserReadyState.Complete Then
Me.wbForPrint.Stop()
End If
Me.wbForPrint.DocumentText = text
AddHandler (Me.wbForPrint.DocumentCompleted), AddressOf HTMLDocumentCompleted
End Try
End Sub
If the printing needs to be automatic with any user input then you could use this code to change the default printer, and then restore the default printer back to what it was once you have done the printing (source: http://codesnippets.fesslersoft.de/how-to-set-the-default-printer-in-c-and-vb-net/)
Public Shared Sub SetDefaultPrinter(ByVal printername As String)
Dim type As var = Type.GetTypeFromProgID("WScript.Network")
Dim instance As var = Activator.CreateInstance(type)
type.InvokeMember("SetDefaultPrinter", System.Reflection.BindingFlags.InvokeMethod, Nothing, instance, New Object() {printername})
End Sub
Or if you want the user to choose which printer to send to, you could try:
WebBrowser1.ShowPrintPreviewDialog()
or
WebBrowser1.ShowPrintDialog()
I've got a Crystal Report which I made in CR2008, which I'm printing from my vb.net application. In this report, I have an image and a formula field.
The image formula (Under Format Graphic > Picture > Graphic Location is set to be the formula field called #imgLocation.
In my vb.net code, I have the following block to select the saved file path from the database, then fill #imgLocation with this value, to set the image that is being shown.
Try
Dim logoPath As String = ds.Tables(0).Rows(0).Item("reportLogoPath") & ""
If logoPath = "" Then
MessageBox.Show("No logo path has been defined in the System Settings. Please set " & _
"one and try again.", "Load Report Failed", MessageBoxButtons.OK)
Exit Sub
Else
cReport.DataDefinition.FormulaFields.Item(2).Text = Chr(34) & logoPath & Chr(34)
End If
Catch ex As Exception
errorLog(ex)
End Try
I've seen this working twice. The image I want replaced the placeholder image when I had FormulaFields.Item(2), but then I resized the image and it didn't work. I then changed the value of the index, and it worked with FormulaFields.Item(4), but again stopped working when I resized the image.
Why is the index changing, and what is the way around it?
I tried using the named parameter option, but FormulaFields.Item("#imgLocation") gave me an error of
Invalid Index
EDIT
As per #Bugs request, this is the report showing the correct string and image
Then, after deleting and re-saving the image (But in a slightly bigger size), the parameter was passed correctly still, but the placeholder image was shown instead.
This makes me think now that it's to do with image size, however, re-sizing it back to the original size still didn't show it again.
EDIT 2
Could it be do to with the fact that I'm loading a new form which contains the report viewer, rather than opening it from the same form?
cReport.RecordSelectionFormula = selectionFormula
Me.Cursor = Cursors.Default
Dim f As New frmReportViewer(con, cReport, 0)
f.Show()
Private Sub frmReportViewer_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
setFormSizes(Me, con)
Me.Location = New Point((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2), 10)
Me.Text = "Report Viewer"
Dim logOnInfo As New TableLogOnInfo()
Dim i As Integer
For i = 0 To cReport.Database.Tables.Count - 1
logOnInfo.ConnectionInfo.DatabaseName = "comm_db"
logOnInfo.ConnectionInfo.Password = "Acplus2016!"
cReport.Database.Tables.Item(i).ApplyLogOnInfo(logOnInfo)
Next i
cReport.VerifyDatabase()
crViewer.ReportSource = cReport
crViewer.ToolPanelView = CrystalDecisions.Windows.Forms.ToolPanelViewType.None
crViewer.Zoom(87)
Catch ex As Exception
errorLog(ex)
End Try
End Sub
Please note my answer is addressing the part regarding adding parameters. For the moment the no image available placeholder is proving difficult to resolve on my side.
To add a parameter please follow these steps:
Add a parameter within Crystal Reports called imageLocation:
After pressing OK you should have a parameter in your list like this:
The following code will pass a value to the parameter:
Dim cReport As New ReportDocument
cReport.Load("C:\Report.rpt")
If cReport.ParameterFields.Item("imageLocation") IsNot Nothing Then
cReport.SetParameterValue("imageLocation", "\\SAGE200FS\Sage\StockImages\sc002.jpg")
End If
reportViewer.ReportSource = cReport
This is the output (I have added the parameter onto the report):
Note that if you are passing parameters and they are shown on the report, make sure you don't have cReport.VerifyDatabase() in place. This often throws up a dialog box asking for the parameter values.
Screenshot of dialog box:
By not calling cReport.VerifyDatabase() this will stop the dialog box from showing.
Now through Crystal Reports you can set the Graphic Location using a parameter. To do this, add the parameter to the report and suppress the field (as you don't want to see it). Then you can add the Report Field as the location.
Add parameter to report and suppress:
Add Report Field as the Graphic Location for the OLE Object:~=
Run the report and input the parameter. This will change the image accordingly. See both screenshots:
SC001::
INT4303:
This however does not seem to work through VB. The ReportViewer does not handle the change of images. Instead you are left with the default image. I'm unsure why this is the case and I'm guessing it's a bug with Crystal. If anyone knows of why this happens, feel free to comment.
EDIT
After discussing the smaller points in chat, we seem to have worked out that the issue arose because of the file path. Saving it to the database as \\server\...\...\image.png was not displaying, but after changing it to Z:\...\...\image.png it has worked fine every time. It was because of the file path, all along.
I’m getting unwanted results in Adobe Reader DC when generating or regenerating a multi-selection list box with iTextSharp in an Acroform PDF document.
Problem: The PDF form is missing deselected display items at the beginning of the list box when viewing the modified PDF in Adobe Reader DC. For example: “One“,“Two“,“Three“,“Four“,“Five“ are list items; and “Two“ and “Four“ are selected; then the previous items such as “One” are missing the top of the list box. And the first item displayed in the list box starts with the first selection, in this case “Two”. (See Adobe Reader DC Screenshot)
FYI: Using Adobe Reader DC, when I select different field selections in the list box, and then click outside the list box, the list box field reverts back to normal appearance with all the items shown. I can’t reproduce this behavior when opening the modified PDF in Adobe Acrobat Professional 8 and all the field items are visible and correctly selected. This missing list items behavior can also be reproduced in GhostScript when converting PDF to BMP or PNG.
Please answer my question: Can you please provide me with a resolution to this issue if this is an iTextSharp problem or if my syntax is incorrect. Would you also please let me know if this behavior can reproduced using your Adobe Reader DC?
Thank you for your support!
Modified Acroform PDF Document with issue:
http://www.nk-inc.com/listbox-error.pdf
Adobe Reader DC Screenshot:
(source: nk-inc.com)
ADDITIONAL INFORMATION:
iTextSharp.dll Version: 5.5.6.0
Adobe Reader DC Version: 2015.008.20082
Adobe Acrobat Pro Version: 8.x
Form Type: Acroform PDF
VB.NET CODE (v3.5 – Windows Application):
Imports iTextSharp.text.pdf
Imports iTextSharp.text
Imports System.IO
Public Class listboxTest
Private Sub RunTest()
Dim cList As New listboxTest()
Dim fn As String = Application.StartupPath.ToString.TrimEnd("\") & "\listbox-error.pdf"
Dim b() As Byte = cList.addListBox(System.IO.File.ReadAllBytes(fn), New iTextSharp.text.Rectangle(231.67, 108.0, 395.67, 197.0), "ListBox1", "ListBox1", 1)
File.WriteAllBytes(fn, b)
Process.Start(fn)
End Sub
Public Function addListBox(ByVal pdfBytes() As Byte, ByVal newRect As Rectangle, ByVal newFldName As String, ByVal oldfldname As String, ByVal pg As Integer) As Byte()
Dim pdfReaderDoc As New PdfReader(pdfBytes)
Dim m As New System.IO.MemoryStream
Dim b() As Byte = Nothing
Try
With New PdfStamper(pdfReaderDoc, m)
Dim txtField As iTextSharp.text.pdf.TextField
txtField = New iTextSharp.text.pdf.TextField(.Writer, newRect, newFldName)
txtField.TextColor = BaseColor.BLACK
txtField.BackgroundColor = BaseColor.WHITE
txtField.BorderColor = BaseColor.BLACK
txtField.FieldName = newFldName 'ListBox1
txtField.Alignment = 0 'LEFT
txtField.BorderStyle = 0 'SOLID
txtField.BorderWidth = 1.0F 'THIN
txtField.Visibility = TextField.VISIBLE
txtField.Rotation = 0 'None
txtField.Box = newRect '231.67, 108.0, 395.67, 197.0
Dim opt As New PdfArray
Dim ListBox_ItemDisplay As New List(Of String)
ListBox_ItemDisplay.Add("One")
ListBox_ItemDisplay.Add("Two")
ListBox_ItemDisplay.Add("Three")
ListBox_ItemDisplay.Add("Four")
ListBox_ItemDisplay.Add("Five")
Dim ListBox_ItemValue As New List(Of String)
ListBox_ItemValue.Add("1X")
ListBox_ItemValue.Add("2X")
ListBox_ItemValue.Add("3X")
ListBox_ItemValue.Add("4X")
ListBox_ItemValue.Add("5X")
txtField.Options += iTextSharp.text.pdf.TextField.MULTISELECT
Dim selIndex As New List(Of Integer)
Dim selValues As New List(Of String)
selIndex.Add(CInt(1)) ' SELECT #1 (index)
selIndex.Add(CInt(3)) ' SELECT #3 (index)
txtField.Choices = ListBox_ItemDisplay.ToArray
txtField.ChoiceExports = ListBox_ItemValue.ToArray
txtField.ChoiceSelections = selIndex
Dim listField As PdfFormField = txtField.GetListField
If Not String.IsNullOrEmpty(oldfldname & "") Then
.AcroFields.RemoveField(oldfldname, pg)
End If
.AddAnnotation(listField, pg)
.Writer.CloseStream = False
.Close()
If m.CanSeek Then
m.Position = 0
End If
b = m.ToArray
m.Close()
m.Dispose()
pdfReaderDoc.Close()
End With
Return b.ToArray
Catch ex As Exception
Err.Clear()
Finally
b = Nothing
End Try
Return Nothing
End Function
End Class
The reason why the visible list starts with the second entry is that iTextSharp starts drawing the list at the first selected entry.
This is an optimization for lists which have more (probably many more) entries than can be displayed in the fixed text box area, so that the displayed entries contain at least one interesting, i.e. selected, one.
Unfortunately this optimization does not consider whether this means leaving some lines empty at the bottom, and in case of lists which fit completely into the text box, there even aren't scroll bars or anything.
But iTextSharp also offers a way to disable this optimization: You can explicitly set the first visible item manually:
txtField.ChoiceSelections = selIndex
txtField.VisibleTopChoice = 0 ' Top visible choice is start of list!
Dim listField As PdfFormField = txtField.GetListField
Adding this middle line makes the generated appearance start at the first list value.
I am writing a FedEx API in vb.net to work with our universe database. So far everything is about done but i'm stuck on the printing label part. The code FedEx gave me saves the label image as a pdf and prints from acrobat. Problem is you can't really do anything with a pdf image, or so i'm sure of at least, meaning i can't line the image up correctly on a 4 x 6 thermal label. How would i do this or is there a good way to just use the image and assign x and y coordinates without messing up the FedEx label? here is the code from where it saves the label down to print:
Sub ShowShipmentLabels(ByRef CompletedShipmentDetail As CompletedShipmentDetail, ByRef packageDetail As CompletedPackageDetail, ByVal isCodShipment As Boolean)
If (packageDetail.Label.Parts(0).Image IsNot Nothing) Then
' Save outbound shipping label
Dim FileName As String = getProperty("labelpath") + packageDetail.TrackingIds(0).TrackingNumber + ".pdf"
SaveLabel(FileName, packageDetail.Label.Parts(0).Image)
Mylabel.Print()
' Save COD Return label
If (isCodShipment) Then
FileName = getProperty("labelpath") + CompletedShipmentDetail.CompletedPackageDetails(0).TrackingIds(0).TrackingNumber + "CR.pdf"
SaveLabel(FileName, CompletedShipmentDetail.CompletedPackageDetails(0).CodReturnDetail.Label.Parts(0).Image)
End If
End If
End Sub
Sub SaveLabel(ByRef labelFileName As String, ByRef labelBuffer() As Byte)
' Save label buffer to file
Dim LabelFile As FileStream = New FileStream(labelFileName, FileMode.Create)
LabelFile.Write(labelBuffer, 0, labelBuffer.Length)
LabelFile.Close()
' Display label in Acrobat
DisplayLabel(labelFileName)
End Sub
Sub DisplayLabel(ByRef labelFileName As String)
Dim info As System.Diagnostics.ProcessStartInfo = New System.Diagnostics.ProcessStartInfo(labelFileName)
info.UseShellExecute = True
info.CreateNoWindow = True
info.WindowStyle = ProcessWindowStyle.Hidden
info.Verb = "Print"
System.Diagnostics.Process.Start(info)
End Sub
If it looks fine on the screen, but is not aligning correctly on the printer then you should probably look to the printer settings either on the device itself or in the driver. I would with the driver, you probably need to specificy the media and maybe adjust the margins.
Chris, if this hasn't been solved yet, check out this FAQ from our database at Shippo: http://support.goshippo.com/hc/en-us/articles/203804319-My-labels-are-not-printing-correctly-How-can-I-fix-this-
Printing 4x6 can be a bit of a headache at first. If it's not yet working for you, feel free to comment with more details what printer you use and your printer settings. This would help to debug further.
You have the option to save the image in ZPLII format. Do it and save it as tracking_id.zpl.
Share the Zebra printer as FedexThermal.
Then create a print.cmd script on he fly from vb to execute...
COPY /B tracking_id.zpl \\localhost\FedexThermal
Then in vb create a process to run that script,
Works for me.