//设计背景,用户在一个页面上定义打印格式XML,点击打印预览按钮,服务器通过定义的样式组织成带数据的XML,返回给客户端的COM组建显示
//当前打印的数据在页面的一个类中,所以在DLL中要取当前页面类中有哪些数据,通过回调函数将取数据的过程传入DLL中。
//报表类,单元名ReportComDLL_Type
type
  TOnGtReportCom = Function(const FunName: PChar; const Param1: PChar; const Param2: PChar;
                            out Value1: PChar;out Value2: PChar):Boolean;StdCall;
type
  TReportCom = class(TObject)
    private
      IOnGtReportCom: TOnGtReportCom;
      gtReportBuilder: TgtReportBuilder;
      repDoc: TgtReportDocument;
      XMLBB: IXMLDocument;
    public
      constructor Create;
      destructor Destroy;override;
      procedure Initialize;
      procedure RepObjectAdd(sDefaultTempXML: string);
      procedure OnGetDataSet(Sender: TObject; const DataSetName: string; var DataSet: TDataSet);
      procedure OnDataSetRead(Sender: TObject; const DataSetName, FieldName: string; var ValueType:   TFieldType; var Value: Variant);
      procedure OnDataSetEOF(Sender: TObject; const DataSetName: string; var EOF: Boolean);
      procedure OnDataSetFirst(Sender: TObject; const DataSetName: string);
      procedure OnDataSetNext(Sender: TObject;  const DataSetName: string);
      Function OnUnknownVariable(Sender: TObject; const OP, Name: string): Variant;
      Function OnUnknownFunction(Sender: TObject; const Name: string; const Params: Variant): Variant;
      Function OnDocUnknownFunction(Sender: TObject; const Name: string; const Params: Variant): Variant;      procedure Set_Template(const Value: string);
      Function Get_Template: string;
      //函数回调,回调函数在.net中定义
      procedure Set_GtReportCom(FunOnGtReportCom: TOnGtReportCom);
      Function Get_DocReport(out Value: string): string;
      procedure Set_DocReport(const Value: string);
      procedure DocReCalc;
      procedure Set_DocAutoCalc(const Value: string);
      procedure Set_DocShowFormula(const Value: string);
      procedure Set_DefaultTemplate(const Value: string);
      Function Get_WFCompareReport(const oldReport, newReport: string): string;
      Function Get_Report: string;
      Function CompressAndToBase64(const sValue: string): string;
      Function FromBase64AndDeCompress(const sValue: string): string;
end;
//单元ReportDLLFun
interface
uses ReportComDLL_Type,Windows, SysUtils,SyncObjs;
//----------------------------------------------------------------------------------------------------------------------
//报表打印预览函数
Function Report(FunOnGtReportCom: TOnGtReportCom;const Template: PChar;var RetValue: PChar;var RetValueLen: Integer): Boolean;StdCall;
implementationimplementationFunction Report(FunOnGtReportCom: TOnGtReportCom;const Template: PChar;var RetValue: PChar;var RetValueLen: Integer): Boolean;StdCall;
var
  sWideBuf: string;
  //类
  ReportCom: TReportCom;
begin
  try
    try
      ReportCom := TReportCom.Create;
      RetValue := '';
      RetValueLen := 0;
      with ReportCom do
      begin
        Set_GtReportCom(FunOnGtReportCom);
        Set_Template(StrPas(Template));
        sWideBuf := Get_Report();//组织带数据的XML,其中调用了传入的FunOnGtReportCom函数
        RetValue := StrAlloc(Length(sWideBuf));//给外部参数分配空间
        CopyMemory(RetValue,PChar(sWideBuf),Length(sWideBuf));
        RetValueLen := Length(sWideBuf);
      end;
    except
    end;
  finally
    Result := True;
    FreeAndNil(ReportCom);
  end;
end;
//这样调用方通过RetValue返回值得到数据
//asp.net中如果多个用户同时打印预览将同时调用Report函数就会产生错误。
//以前采用信号量做但是在sWideBuf := Get_Report();函数执行比较浪费时间,如果一个打印数据比较多,令一个打印数据只有1,2条还要等他们处理完才处理。
//前提是不采用COM技术做。不知道是我哪边写错了,还是怎么搞的?望有这方面经验的人站出来指点指点,RMB感谢!

解决方案 »

  1.   

    做这个之前你搞清楚什么是服务端什么是客户端,哪些代码在服务端运行,哪些在客户端运行。客户端的js代码的执行权限是什么,都可以运行什么,非com的dll放在客户端,js是否有权限运行它。
      

  2.   

    DLL是否在服务器上的。
    用于显示报表的COM是客户端的,原先报表是用ACTIVEX 做的并使用正常,现在公司想换成DLL,在这儿就出现问题,有意者QQ联系:616485000
      

  3.   

    同志们都进来看看,解决了RMB感谢!!~
      

  4.   

    服务端上运行的东西,你直接用c#写个类库asp.net调用一下不就行了,activex和你服务器上的dll完全就是两个东西,一个是运行在客户端的,一个是运行在服务器上的
      

  5.   

    DLL是服务器上的吧,COM是服务器和客户端都可以的
      

  6.   


        public class TReportComClass 
        {
     private string _DLLPath = HttpContext.Current.Server.MapPath(@"~/N_MODEL/images/ReportComDLL.dll");
            [DllImport("kernel32.dll", SetLastError = true)]
            static extern IntPtr LoadLibrary(string lpFileName);        [DllImport("kernel32.dll", SetLastError = true)]
            static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);        [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
            static extern bool FreeLibrary(IntPtr hModule);        //将要执行的函数转换为委托
            public Delegate LinkFunction(IntPtr hLib, String APIName, Type t)
            {
                IntPtr api = GetProcAddress(hLib, APIName);
                return (Delegate)Marshal.GetDelegateForFunctionPointer(api, t);
            }        #region DLL函数模型        public delegate bool TOnGtReportCom(string FunName, string Param1, string Param2, ref string Value1, ref string Value2);
            public delegate bool Report(TOnGtReportCom FunOnGtReportCom, string Template, ref IntPtr RetValue, ref int RetValueLen);
    #endregion
     ///<summary>
            ///委托事件处理过程
            ///</summary>
            bool ReportCom_OnGtReportCom(string FunName, string Param1, string Param2, ref string Value1, ref string Value2)
            {
                if (FunName.ToUpper() == "ONDATASETREAD")
                { 
                    ReportOnDataSetRead(Param1, Param2, ref Value1, ref Value2);
                    return true;
                }            if (FunName.ToUpper() == "ONUNKNOWNFUNCTION")
                { 
                    ReportOnUnknownFunction(Param1, Param2, ref Value1, ref Value2);
                    return true;
                }            if (FunName.ToUpper() == "ONUNKNOWNVARIABLE")
                {
                    ReportOnUnknownVariable(Param1, Param2, ref Value1, ref Value2);
                    return true;
                }
       }
          /// <summary>
            /// 获取打印或预览数据,返回XML
            /// </summary>
            /// <param name="ChooseTemplate">是否已存在样式</param>
            /// <param name="ReportXMLDataSets">XML样式字符串</param>
            public string GetPrintOrPreviewReport(bool ChooseTemplate, string ReportXMLDataSets)
            {
                IntPtr Buf = IntPtr.Zero;
                IntPtr DllAdr = LoadLibrary(_DLLPath);
                StringBuilder sRep = new StringBuilder("");
                if (DllAdr == IntPtr.Zero)
                {
                    
                }
                try
                {
                    ClearMemory();
                    int length = 0;
                    if (ChooseTemplate)
                    {
                        Report report = (Report)LinkFunction(DllAdr, "Report", typeof(Report));
                        report(ReportCom_OnGtReportCom, CompressXMLString(ReportXMLDataSets), ref Buf, ref length);
                        if (length > 0)
                        {
                            sRep.Append(Marshal.PtrToStringAnsi(Buf));
                        }
                    }
                    else
                    {
                        ReportDef reportDef = (ReportDef)LinkFunction(DllAdr, "ReportDef", typeof(ReportDef));
                        reportDef(ReportCom_OnGtReportCom, CompressXMLString(ReportXMLDataSets), ref Buf, ref length);
                        if (length > 0)
                        {
                            sRep.Append(Marshal.PtrToStringAnsi(Buf, length));
                        }
                    }
                }
                catch
                { }
                finally
                {
                    Buf = IntPtr.Zero;
                    FreeLibrary(DllAdr);
                }
                return sRep.ToString();
            }
    //我是这样写的,但是打印量大的数据时候,直接out of memeory,但是aspwp.exe此时只有300M
      

  7.   


    //单独打印任何条数据不会有问题
    //但是我开两个或两个以上IE窗口,同时打印大量的数据(>4000条)时候出现out of memory
    //如果你们需要windug分析的报告可以贴出来