//设计背景,用户在一个页面上定义打印格式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感谢!
用于显示报表的COM是客户端的,原先报表是用ACTIVEX 做的并使用正常,现在公司想换成DLL,在这儿就出现问题,有意者QQ联系:616485000
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
//单独打印任何条数据不会有问题
//但是我开两个或两个以上IE窗口,同时打印大量的数据(>4000条)时候出现out of memory
//如果你们需要windug分析的报告可以贴出来