SSRS レポートをプリンターに直接送信したいと考えています。そのために、レポートをバイト配列にレンダリングし、これらのバイト配列をプリンターに送信しました。
SSRS 印刷ボタンからレポートを印刷すると、印刷されるレポートのサイズはレポートのサイズとまったく同じになります。しかし、問題は次のとおりです。コードを印刷すると、レポートのサイズが正しくありません。
バイトを生成するコード:
Private Function ExporttoPrinter()
'Start : Code to Check the Page Count -- Binit
Dim deviceInfo As String
Dim format As String = "IMAGE"
Dim encoding As String = ""
Dim mimeType As String = ""
Dim extension As String = ""
Dim warnings As Warning() = Nothing
Dim streamids As String() = Nothing
Dim bytes As Byte() = New Byte(0) {&H0}
Dim numberOfPages As Integer = 1
Dim pages As Byte()() = New [Byte](-1)() {}
Dim currentPageStream As Byte() = New Byte(0) {&H0}
While currentPageStream.Length > 0
deviceInfo = String.Format("<DeviceInfo><OutputFormat>EMF</OutputFormat><PrintDpiX>200</PrintDpiX><PrintDpiY>200</PrintDpiY> <StartPage>{0}</StartPage><PageWidth>15in</PageWidth><PageHeight>12in</PageHeight><MarginTop>0.5in</MarginTop><MarginLeft>1in</MarginLeft><MarginRight>0in</MarginRight><MarginBottom>0.5in</MarginBottom></DeviceInfo>", numberOfPages)
currentPageStream = ReportViewer1.ServerReport.Render(format, deviceInfo, mimeType, encoding, extension, streamids, warnings)
If currentPageStream.Length = 0 AndAlso numberOfPages = 1 Then
'renderException = EnumRenderException.ZERO_LENGTH_STREAM;
Exit While
End If
'Add the byte stream of current page in pages[] array so that we can have complete report in pages[][] array
If currentPageStream.Length > 0 Then
Array.Resize(pages, pages.Length + 1)
pages(pages.Length - 1) = currentPageStream
numberOfPages += 1
End If
End While
numberOfPages = numberOfPages - 1
' new Checking End
Dim objPrint As New clsReportPrinting
objPrint.PrintReport(pages, "CutePDF Writer")
Return True
End Function
バイトをプリンターに送信するコード:
Public Class clsReportPrinting
Private byaPagesToPrint()() As Byte = Nothing, _
m_oMetafile As Metafile = Nothing, _
m_iNumberOfPages As Int32 = 0, _
m_iCurrentPrintingPage As Int32 = 0, _
m_iLastPrintingPage As Int32 = 0, _
m_oCurrentPageStream As MemoryStream = Nothing, _
m_oDelegate As Graphics.EnumerateMetafileProc = Nothing
Public Function PrinterExists(ByVal PrinterName As String) As Boolean
'Returns TRUE if the named printer is amongst installed printers, FALSE otherwise
Try
PrinterName = PrinterName.Trim.ToUpper
For Each sPrinter As String In PrinterSettings.InstalledPrinters
'Printers may have UNC names, so we use .EndsWith to deal with \\Server\SharedPrinter
'if we pass "SharedPrinter" as PrinterName
If sPrinter.Trim.ToUpper.EndsWith(PrinterName) Then
Return True
End If
Next
Return False
Catch oEx As Exception
Throw (oEx)
Return False
End Try
End Function
Public Function MetafileCallback(ByVal oRecType As EmfPlusRecordType, _
ByVal iFlags As Int32, _
ByVal iDataSize As Int32, _
ByVal dpData As IntPtr, _
ByVal oCallbackData As PlayRecordCallback _
) As Boolean
Dim byaDataArray() As Byte = Nothing
If dpData <> IntPtr.Zero Then
'Copy unmanaged data to managed array for PlayRecord call
Array.Resize(Of Byte)(byaDataArray, iDataSize)
Marshal.Copy(dpData, byaDataArray, 0, iDataSize)
End If
'Play the record
m_oMetafile.PlayRecord(oRecType, iFlags, iDataSize, byaDataArray)
Return True
End Function
Private Function MoveToPage(ByVal lPage As Int32) As Boolean
'Check current page does exist
If Me.byaPagesToPrint(m_iCurrentPrintingPage - 1) Is Nothing Then
Return False
End If
'Set current page stream to desired rendered page
m_oCurrentPageStream = New MemoryStream(Me.byaPagesToPrint(m_iCurrentPrintingPage - 1))
'Set curernt stream position to its start
m_oCurrentPageStream.Position = 0
'Get rid of any former metafile
If Not m_oMetafile Is Nothing Then
m_oMetafile.Dispose()
m_oMetafile = Nothing
End If
'Set local metafile to page
m_oMetafile = New Metafile(m_oCurrentPageStream)
'Must always return TRUE
Return True
End Function
Public Sub pd_PrintPage(ByVal oSender As Object, _
ByVal oEV As PrintPageEventArgs)
oEV.HasMorePages = False
If (m_iCurrentPrintingPage <= m_iLastPrintingPage) And _
(MoveToPage(m_iCurrentPrintingPage)) Then
'Draw the page
DrawPage(oEV.Graphics)
'Point to next page
m_iCurrentPrintingPage += 1
'If there are more pages, flag so.
oEV.HasMorePages = (m_iCurrentPrintingPage <= m_iLastPrintingPage)
End If
End Sub
'This draws the current selected stream into a metafile
Public Sub DrawPage(ByVal oGrx As Graphics)
If m_oCurrentPageStream Is Nothing Or _
m_oCurrentPageStream.Length = 0 Or _
m_oMetafile Is Nothing Then
Return
End If
'Critical section follows (no more than one thread a time)
SyncLock Me
Dim iWidth As Int32 = m_oMetafile.Width, _
iHeight As Int32 = m_oMetafile.Height, _
oDestPoint As Point = Nothing
'Prepare metafile delegate
m_oDelegate = New Graphics.EnumerateMetafileProc(AddressOf MetafileCallback)
'Draw in the rectangle
oDestPoint = New Point(0, 0)
oGrx.EnumerateMetafile(m_oMetafile, oDestPoint, m_oDelegate)
'Clean up
m_oDelegate = Nothing
End SyncLock
End Sub
Public Function PrintReport(ByVal byaReport()() As Byte, _
ByVal sPrinterName As String _
) As Boolean
'Report data is an array of pages. Each page in turn is another byte array.
Me.byaPagesToPrint = byaReport
m_iNumberOfPages = Me.byaPagesToPrint.Length
Try
Dim oPS As PrinterSettings = New PrinterSettings
oPS.MaximumPage = m_iNumberOfPages
oPS.MinimumPage = 1
oPS.PrintRange = PrintRange.SomePages
oPS.FromPage = 1
oPS.ToPage = m_iNumberOfPages
oPS.PrinterName = sPrinterName
'oPS.DefaultPageSettings.Landscape = False
'oPS.DefaultPageSettings.Margins.Top = 0.5
'oPS.DefaultPageSettings.Margins.Bottom = 0.5
'oPS.DefaultPageSettings.Margins.Left = 0.83
'oPS.DefaultPageSettings.Margins.Right = 0
'oPS.DefaultPageSettings.PaperSize.Kind = PaperKind.Custom
oPS.DefaultPageSettings.PaperSize = New PaperSize("Custom", 1500, 1200)
'Dim value As Boolean
'value = oPS.LandscapeAngle
'oPS.LandscapeAngle = value
Dim oPD As PrintDocument = New PrintDocument
m_iCurrentPrintingPage = 1
m_iLastPrintingPage = m_iNumberOfPages
oPD.PrinterSettings = oPS
'Do print the report
AddHandler oPD.PrintPage, AddressOf Me.pd_PrintPage
oPD.Print()
Return True
Catch oEx As Exception
Throw (oEx)
End Try
End Function
'Private Function RenderReport(ByVal reportPath As String, ByVal parameters As ExecutionService.ParameterValue()) As Byte()()
' ' Private variables for rendering
' Dim historyId As String = Nothing
' Dim execHeader As New ExecutionService.ExecutionHeader()
' Try
' rs.Timeout = 300000
' rs.ExecutionHeaderValue = execHeader
' rs.LoadReport(reportPath, historyId)
' If (parameters IsNot Nothing) Then
' rs.SetExecutionParameters(parameters, "en_us")
' End If
' Dim pages As Byte()() = New [Byte](-1)() {}
' Dim format As String = "IMAGE"
' Dim numberOfPages As Integer = 1
' Dim currentPageStream As Byte() = New Byte(0) {&H0}
' ' put a byte to get the loop started
' Dim extension As String = Nothing
' Dim encoding As String = Nothing
' Dim mimeType As String = Nothing
' Dim streamIDs As String() = Nothing
' Dim warnings As ExecutionService.Warning() = Nothing
' While currentPageStream.Length > 0
' Dim deviceInfo As String = [String].Format("<DeviceInfo><OutputFormat>EMF</OutputFormat><PrintDpiX>200</PrintDpiX><PrintDpiY>200</PrintDpiY>" & "<StartPage>{0}</StartPage></DeviceInfo>", numberOfPages)
' 'rs.Render will render the page defined by deviceInfo's <StartPage>{0}</StartPage> tag
' currentPageStream = rs.Render(format, deviceInfo, extension, encoding, mimeType, warnings, _
' streamIDs)
' If currentPageStream.Length = 0 AndAlso numberOfPages = 1 Then
' 'renderException = EnumRenderException.ZERO_LENGTH_STREAM;
' Exit While
' End If
' 'Add the byte stream of current page in pages[] array so that we can have complete report in pages[][] array
' If currentPageStream.Length > 0 Then
' Array.Resize(pages, pages.Length + 1)
' pages(pages.Length - 1) = currentPageStream
' numberOfPages += 1
' End If
' End While
' numberOfPages = numberOfPages - 1
' Return pages
' Catch ex As System.Web.Services.Protocols.SoapException
' Console.WriteLine(ex.Detail.InnerXml)
' Catch ex As Exception
' Console.WriteLine(ex.Message)
' ' Console.WriteLine("Number of pages: {0}", pages.Length);
' Finally
' End Try
' Return Nothing
'End Function
End Class