1

尝试导出为 pdf 时出现 InvalidComObjectException 错误。我认为这可能与连接到 oracle 有关,但不确定。SetDatabaseLogon 似乎偏爱 Sql Server。该报告调用数据的存储过程,并使用 Business Objects XIR2 服务工作。我也可以查看报告并在设计器内部进行连接。

'CrystalDecisions.CrystalReports.Engine 13.0.2000.0' .NET Framework 4.0 的水晶报告

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: 
4

4 回答 4

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
于 2012-08-21T17:46:04.110 回答
0
  1. 执行数据集以填充 oracle 存储过程中的数据。确保数据集中的表名与设计报表所基于的数据库对象的名称相同。(本例中为存储过程名称)

  2. 不要提供任何登录信息。这很重要

  3. 设置所有报表参数,但不提供任何数据过滤器,因为数据集包含已过滤的数据。

  4. 手动进行数据绑定。

    doc.SetDataSource=你的数据源;

现在像往常一样继续进行报告导出。

这是填充报告的推送模型方式。通常我使用 oledb dataadapter for oracle 来设计报告。但是如果你正在处理存储过程,那么推送模型是唯一的方法。设计人员可以访问 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
于 2012-04-10T02:29:56.397 回答
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

希望您以后可以使用它。

于 2012-04-09T21:45:51.327 回答
0

施耐德,

我怀疑问题不是由于您设置了连接详细信息或参数。要确认我的怀疑,您可以将代码放入一个简单的 Web 或 Windows 窗体/页面中,而不是导出,只需尝试通过将 CrystalReportViewer 对象拖放到该页面上来查看报告。(注意:这项工作有一些先决条件,但如果您在安装了完整 Crystal 的开发机器上,它应该很容易满足这些要求。)

假设您没有看到投诉(即它提示输入参数或数据库凭据),那么我将倾向于完全不同的理论。

线索在您的错误消息中:“无法使用已与其基础 RCW 分离的 COM 对象。” 此错误并非 Crystal Reports 独有。

我之前看到的这与垃圾收集(无论是自动化的还是由于您的代码而发生的处置/解构)或多线程相关的挑战有关。

我注意到您将其作为一个函数调用,该函数将 PDF 路径作为字符串返回。也许您已经将调用嵌套到一个独立于调用线程的线程中?也许您有其他代码会触发其他可能涉及对象处置或资源/锁定相关问题(如批处理)的事件?

避免推测的一种方法是将所有这些放入一个全新的、非常简单的基本 Windows 应用程序中。除了触发导出的绝对最小值之外什么都不做。确保 Windows 应用程序只是写入本地文件夹并从本地目录读取报告。我们不希望文件权限或网络问题(通过网络读取/写入)干扰。

祝你好运。

于 2012-04-10T03:17:16.207 回答