尝试导出为pdf时出现InvalidComObjectException错误。我认为它可能与连接到oracle有关,但不确定。 SetDatabaseLogon似乎更喜欢Sql Server。该报告调用数据的存储过程,并使用Business Objects XIR2服务。我也可以查看报告并连接设计师。
'CrystalDecisions.CrystalReports.Engine 13.0.2000.0 '.NET Framework 4.0的Crystal Reports
Imports CrystalDecisions.CrystalReports.Engine
Imports CrystalDecisions.ReportAppServer.DataDefModel
Imports CrystalDecisions.Shared
Imports CrystalDecisions.ReportSource
Public Overloads Function CreateReport(ByVal reportFileName As String, ByVal reportTitle As String, ByVal outputDirectory As String, _
ByVal isFullPath As Boolean, ByVal outputFormat As OutputFormat, ByVal crystalParameter As CrystalParameter) As String
Dim baseReportsSourcePath As String = "C:\ADSTAX\SUITES\RFL\Letters\"
Dim baseReportsOutputPath As String = "C:\PDF_Exports\"
Dim fullFilepath As String = baseReportsSourcePath + reportFileName
'check report exists
If File.Exists(fullFilepath) = False Then Throw New FileNotFoundException("File:" + fullFilepath + " does not exist", fullFilepath)
Dim doc As ReportDocument = New ReportDocument()
doc.Load(fullFilepath)
'set parameters
If crystalParameter.Name = CrystalParameterName.DistributionKey Then
doc.SetParameterValue("DISTRIBUTIONKEY", crystalParameter.Value)
ElseIf crystalParameter.Name = CrystalParameterName.RequestKey Then
doc.SetParameterValue("REQUESTKEY", crystalParameter.Value)
End If
'user, pass, server, database
doc.SetDatabaseLogon("user", "pass")
'build full output filename
Dim exportFileName As String = Path.GetFileNameWithoutExtension(reportFileName)
exportFileName += Guid.NewGuid.ToString + ".pdf"
Dim fullOuputFilePath As String = baseReportsOutputPath + exportFileName
'export to pdf
doc.ExportToDisk(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat, fullOuputFilePath)
'check report created
If File.Exists(fullFilepath) = False Then
Return String.Empty
End If
Return fullOuputFilePath
End Function
以下错误:
System.Runtime.InteropServices.InvalidComObjectException was unhandled
Message=COM object that has been separated from its underlying RCW cannot be used.
Source=mscorlib
StackTrace:
at System.StubHelpers.StubHelpers.StubRegisterRCW(Object pThis, IntPtr pThread)
at System.Runtime.InteropServices.ComTypes.IConnectionPoint.Unadvise(Int32 dwCookie)
at CrystalDecisions.ReportAppServer.ISCDClientDocumentEvents_EventProvider.RemoveOnClosed(_ISCDClientDocumentEvents_OnClosedEventHandler handler)
at CrystalDecisions.ReportAppServer.ISCDClientDocumentEvents_EventProvider.remove_OnClosed(_ISCDClientDocumentEvents_OnClosedEventHandler value)
at CrystalDecisions.ReportAppServer.ReportClientDocumentWrapper.DisconnectEventRelay()
at CrystalDecisions.ReportAppServer.ReportClientDocumentWrapper.InternalClose(Boolean bSetupForNextReport, Boolean bAutoClose)
at CrystalDecisions.ReportAppServer.ReportClientDocumentWrapper.Dispose(Boolean bDisposeManaged)
at System.ComponentModel.Component.Dispose()
at CrystalDecisions.CrystalReports.Engine.ReportDocument.ClearCache(Boolean clearDocument)
at CrystalDecisions.CrystalReports.Engine.ReportDocument.InternalClose(Boolean bSetupForNextReport)
at CrystalDecisions.CrystalReports.Engine.ReportDocument.Close()
at CrystalDecisions.CrystalReports.Engine.ReportDocument.ExitHandler(Object sender, EventArgs e)
InnerException:
答案 0 :(得分:1)
在经历了许多水晶问题之后,这最终会起作用。 其他许多人都有信用。我主要发现了所需要的东西,拼凑在一起,其他人也在寻找解决方案。
您还需要添加一个引用:CrystalDecisions.ReportAppServer.DataDefModel.dll
Imports CrystalDecisions.ReportAppServer.DataDefModel
Public Overloads Function CreateReport(ByVal reportFileName As String, ByVal reportTitle As String, ByVal outputDirectory As String, _
ByVal isFullPath As Boolean, ByVal outputFormat As OutputFormat, ByVal crystalParameter As CrystalParameter) As String
Dim baseReportsSourcePath As String = "C:\data\ReportTemplates\Correspondence\" '"C:\ADSTAX\SUITES\RFL\Letters\"
Dim baseReportsOutputPath As String = "C:\PDF_Exports\"
Dim fullFilepath As String = baseReportsSourcePath + reportFileName
'check report exists
If File.Exists(fullFilepath) = False Then Throw New FileNotFoundException("File:" + fullFilepath + " does not exist", fullFilepath)
'build crystal
Dim startCreateDoc As Long = DateTime.Now.Ticks
Dim doc As ReportDocument = New ReportDocument()
Dim tsc As New TimeSpan(startCreateDoc - DateTime.Now.Ticks)
Trace.WriteLine(fullFilepath + " Report create time:" + tsc.ToString)
Dim startLoad As Long = DateTime.Now.Ticks
doc.Load(fullFilepath)
Dim ts As New TimeSpan(startLoad - DateTime.Now.Ticks)
Trace.WriteLine(fullFilepath + " Report Load time:" + ts.ToString)
CrystalLogin(doc, "service", "user", "password")
'set parameters
If crystalParameter.Name = CrystalParameterName.DistributionKey Then
doc.ApplyParameters("DISTRIBUTIONKEY=" + crystalParameter.Value)
ElseIf crystalParameter.Name = CrystalParameterName.RequestKey Then
doc.ApplyParameters("REQUESTKEY=" + crystalParameter.Value)
End If
'build full output filename
Dim exportFileName As String = Path.GetFileNameWithoutExtension(reportFileName)
exportFileName += "_"
exportFileName += Guid.NewGuid.ToString + ".pdf"
Dim fullOuputFilePath As String = baseReportsOutputPath + exportFileName
'export to pdf
'doc.ExportToDisk(ExportFormatType.PortableDocFormat, fullOuputFilePath)
Dim pdfOps As CrystalDecisions.Shared.PdfFormatOptions = CrystalDecisions.Shared.ExportOptions.CreatePdfFormatOptions
Dim eo As New CrystalDecisions.Shared.ExportOptions
eo.ExportFormatType = ExportFormatType.PortableDocFormat
eo.ExportDestinationType = ExportDestinationType.DiskFile
eo.ExportFormatOptions = pdfOps
'Dim htmlOps As CrystalDecisions.Shared.HTMLFormatOptions = CrystalDecisions.Shared.ExportOptions.CreateHTMLFormatOptions
'htmlOps.HTMLFileName = fullOuputFilePath
'eo.ExportFormatOptions = htmlOps
Dim dop As DiskFileDestinationOptions = CrystalDecisions.Shared.ExportOptions.CreateDiskFileDestinationOptions
dop.DiskFileName = fullOuputFilePath
eo.ExportDestinationOptions = dop
doc.Export(eo)
doc.Close()
'check report created
If File.Exists(fullFilepath) = False Then
Return String.Empty
End If
Return fullOuputFilePath
End Function
Public Shared Sub CrystalLogin(mainInRD As ReportDocument, dataSource As String, userId As String, pwd As String)
Try
'now update logon info for all sub-reports
If Not mainInRD.IsSubreport AndAlso mainInRD.Subreports IsNot Nothing AndAlso mainInRD.Subreports.Count > 0 Then
For Each rd As ReportDocument In mainInRD.Subreports
CrystalLogin(rd, dataSource, userId, pwd)
Next
End If
Catch
End Try
'do the main reports database
Dim logonInfo As TableLogOnInfo = Nothing
For Each table As CrystalDecisions.CrystalReports.Engine.Table In mainInRD.Database.Tables
logonInfo = table.LogOnInfo
logonInfo.ConnectionInfo.ServerName = dataSource
logonInfo.ConnectionInfo.DatabaseName = ""
logonInfo.ConnectionInfo.UserID = userId
logonInfo.ConnectionInfo.Password = pwd
table.ApplyLogOnInfo(logonInfo)
'This part was needed to support the oracle store procs we use to obtain the data
Dim prop As PropertyInfo = Nothing
prop = table.[GetType]().GetProperty("RasTable", BindingFlags.NonPublic Or BindingFlags.Instance)
Dim rasTable As ISCRTable = Nothing
rasTable = DirectCast(prop.GetValue(table, Nothing), ISCRTable)
table.Location = rasTable.QualifiedName
'Console.Out.WriteLine(table.Name)
'Console.Out.WriteLine(rasTable.QualifiedName)
Next
End Sub
答案 1 :(得分:0)
我建议看一下这段代码:
Imports CrystalDecisions.CrystalReports.Engine
Imports CrystalDecisions.Shared
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim cryRpt As New ReportDocument
Dim crtableLogoninfos As New TableLogOnInfos
Dim crtableLogoninfo As New TableLogOnInfo
Dim crConnectionInfo As New ConnectionInfo
Dim CrTables As Tables
Dim CrTable As Table
cryRpt.Load("PUT CRYSTAL REPORT PATH HERE\CrystalReport1.rpt")
With crConnectionInfo
.ServerName = "YOUR SERVER NAME"
.DatabaseName = "YOUR DATABASE NAME"
.UserID = "YOUR DATABASE USERNAME"
.Password = "YOUR DATABASE PASSWORD"
End With
CrTables = cryRpt.Database.Tables
For Each CrTable In CrTables
crtableLogoninfo = CrTable.LogOnInfo
crtableLogoninfo.ConnectionInfo = crConnectionInfo
CrTable.ApplyLogOnInfo(crtableLogoninfo)
Next
CrystalReportViewer1.ReportSource = cryRpt
CrystalReportViewer1.Refresh()
End Sub
End Class
来自http://vb.net-informations.com/crystal-report/vb.net_crystal_report_load_dynamically.htm
我可能会在星号所在的位置加上一个断点:
For Each CrTable In CrTables
*crtableLogoninfo = CrTable.LogOnInfo
crtableLogoninfo.ConnectionInfo = crConnectionInfo
CrTable.ApplyLogOnInfo(crtableLogoninfo)
Next
然后分析现有的CrTable.TableLogonInfo
希望你可以继续使用它。
答案 2 :(得分:0)
执行数据集以填充oracle storedprocedure中的数据。确保数据集中的表名与设计报表的数据库对象的名称相同。(在这种情况下为存储过程名称)
不提供任何logoninfo。 这很重要。
设置所有报告参数,但不提供任何数据过滤器,因为数据集包含已过滤的数据。
手动执行数据绑定。
doc.SetDataSource = yourdatasource;
现在像往常一样继续报告导出。
这是填充报告的推送模型方式。通常我使用oledb dataadapter为oracle设计报告。但是,如果您正在处理存储过程,那么Push模型是唯一的方法。设计人员可以访问oracle SP并填充报告,但在应用程序中您必须处理它,否则您将看到恼人的弹出窗口,询问存储过程参数值。
这是一些代码
OracleConnection cn = new OracleConnection("Data Source=yourdbname;User ID=someid;password=somepw;Pooling=true;Connection Lifetime=30;Min Pool Size=5;Max Pool Size=100");
OracleParameter DETAILS = new OracleParameter();
DETAILS.ParameterName = "DETAILS";
DETAILS.Direction = ParameterDirection.Output;
OracleParameter NN = new OracleParameter();
NN.ParameterName = "PRODUCT";
NN.Direction = ParameterDirection.Input;
NN.Value = 1000; // Some product id
OracleParameter DD = new OracleParameter();
DD.ParameterName = "TRDATE";
DD.Direction = ParameterDirection.Input;
DD.Value = “09-DEC-2008”; // Some Date
// for Oracle.DataAccess.Client use the following
DETAILS.OracleDbType = OracleDbType.RefCursor;
NN.OracleDbType = OracleDbType.Varchar2;
DD.OracleDbType = OracleDbType.Date;
// for System.Data.OracleClient use the following
//DETAILS.OracleType = OracleType.Cursor;
//NN.OracleType = OracleType.VarChar;
//DD.OracleType = OracleType.DateTime;
OracleCommand cmd = new OracleCommand("Myschemaname.GETSTOCK", cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(NN);
cmd.Parameters.Add(DD);
cmd.Parameters.Add(DETAILS);
OracleDataAdapter da = new OracleDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds,"GETSTOCK"); //Name must be same as Procedure
ReportDocument rptDoc = new ReportDocument();
rptDoc.Load(Server.MapPath("FINC//abc.rpt"));
rptDoc.SetDataSource(ds);
CRT.ReportSource = rptDoc; // CRT is the name of Crystal report viewer control
// your export routine goes here
答案 3 :(得分:0)
ESchneider,
我怀疑问题不是由于您设置了连接细节或参数。为了确认我的怀疑,您可以将代码放入一个简单的Web或Windows窗体/页面,而不是导出只是尝试通过将CrystalReportViewer对象放到该页面上来查看报告。 (注意:这有一些先决条件,但是如果你在安装了完整Crystal的开发机器上,它应该很容易满足这些要求。)
假设您没有看到投诉(即它提示输入参数或数据库凭证),那么我将倾向于完全不同的理论。
线索在您的错误消息中:“无法使用已与其基础RCW分离的COM对象。”此错误不是Crystal Reports独有的。
我之前看到过这与垃圾收集有关(无论是自动化还是由于您的代码导致的处理/解构)或多线程相关的挑战。
我注意到你将此称为一个函数,它将PDF路径作为字符串返回。也许你已经将调用嵌套到一个独立于调用线程的线程中?也许您有其他代码可以触发其他可能导致对象处理或资源/锁定相关问题的事件,如批处理?
避免推测的一种方法是将所有这些放入一个全新的,简单的基本Windows应用程序中。除触发导出的绝对最小值外什么都不做。确保Windows应用程序只是写入本地文件夹并从本地目录中读取报表。我们不希望文件权限或网络问题(通过网络读/写)发生干扰。
祝你好运。