[MyBean-插件]MyBean通用报表免费无限制版本发布

 

【优点】

   1.开发时无需安装报表组件(可以直接用编译好的文件,注意版权说明,请自行编译一次相应的报表插件文件)。

   2.无带包烦恼所有版本Delphi都可以使用,不拖累Delphi版本的升级。

   3.可以实现单据的多种样式设计, 报表文件可以远程文件存储(网络共享)和本地文件存储。

   4.可以让每个用户设计自己的报表和设定自己的默认报表。

   5.支持多种报表组件(RM, FR, .. 可以扩展)

   6.调用简单,关联文件少。

 

【界面】

 

【关于版权】
  FastReport,RM的版权归原组件作者所有。请自行编译相关的报表插件,本DEMO中保留的FastReporter.dll,RMReporter.dll文件只能供学习使用,请不要用于商业用途。

【关于该插件
  该插件可以免费无限制使用,如果你觉得好用可以联系作者进行购买源码版本。也可以联系作者进行OEM。
  官方网站: www.diocp.org

 

【关于DEMO说明】
  ReporterDEMO.dpr包含三个文件
  Repoter-Common\MybeanReporterIntf.pas       MyBean报表插件的接口文件。
  Repoter-Common\MybeanReporterObjects.pas    MyBean报表插件的调用是需要使用到的一些基础类。
  Forms\ufrmPluginForm.pas                    演示窗体:如何调用使用插件直接预览,设计,打印。
 
  MyBeanSource                                是MyBean的源文件,编译DEMO需要用到MyBean核心文件,你可以设置工程的library路径,或者加入Delphi的Library Paths中
  编译出来的EXE请放置于BIN\文件夹中

【调用示例代码】
  // 报表对象
  FMyBeanReporter := TMyBeanReporter.Create();
  // 提供一个报表中使用的数据集
  FMyBeanReporter.ReporterDataProvider.AddDataSet(‘cdsMain’, self.cdsMain);

  // 报表归类ID(不同的ID可以有多个设计报表
  FMyBeanReporter.ReporterCatalogId := ‘1002579’; 
  // 当前用户,每个用户可以设置不同的默认报表
  FMyBeanReporter.UserName := cbbUser.Text;
  // 显示报表控制台(可以进行设计,管理报表)
  FMyBeanReporter.ShowConsole();   // DirectPreview(); 直接预览, // DirectPrint(); 直接打印

 

 

免费版下载地址

http://pan.baidu.com/s/1ntpBtBb

【杂谈接口】接口对象的生命周期-对象所占用的内存块清理

【概述】

相信经常使用接口的朋友们,经常碰到访问违规异常(Access violation),很多情况下无法理解,认为是编译器的Bug,然后去绕开它,不追其根源,把责任推给IDE,推给编译器(其实本人以前也经常这样想)。其实每个异常都是有原因的,碰到这种问题不要绕开,如果目前无法解决,至少要清楚的知道它出现的起因,不放过每一次追根到底的机会。这才是做程序员的应有的心态。(好像有点扯远了…)

 

【问题描述】

今天公司外包模块中,外包人员反应出现一个很奇怪的问题,说模块中无故出现了AV异常。调试果然如此,而且每次都能出现,每次都能出现的异常就好解决,

最初的代码如下:

一个点击按钮事件中包含如下一段代码:

 

begin
  ....
  (TmBeanFrameVars.GetBean('ef_pcy_frmTree'as INormalSelector).executeSelect(lvPass);
  ....
end;

这样程序在退出函数的时候引发了一个AV异常(end;运行之后),这时候一般对接口不了解的都无从下手。也无从下手进行调试。

 

【问题分析】

首先上面这句简单的访问其实会出现接口的临时变量,而这个变量在函数退出的时候会执行清理,因为executeSelect函数中释放了插件的实例,然后清理临时接口变量时会触发接口对象的__release方法。这个时候引发的一个异常。

我改造一下代码,让错误在函数退出之前出现,完整代码如下。

I`VNO]}GF`0}M_PHZR9C2{U

我用两个局部变量,这样改造后,在执行lvIntf := nil的时候就会出现AV错误。

image

我顺便把executeSelect代码贴一下,可以看到这个插件是一个窗体对象实例。在执行这个函数里面会把窗体显示,然后进行了释放,然后退出了函数。

 

大概的原因明白后,我们调整下代码,代码如下:

PFRPD@W3BOX1E[R2B~V[~K9

注意红色部分,选取完后(释放实例后),然后马上清理接口变量,这个时候,其实内存块应该还是完整的(个人推测),所以清理时不会出现访问违规异常。

 

下面我来做个调试证明我的推测

R7$@CSJ6K@)E74)1XGHER@V

看红色框出来部分,两个接口变量在释放完后,和之前的指向的内存块中值是一样的(我只获取了一个值,其实可以进行完整对比),然继续执行。

{8FA%_B][VZU%_SCWT7%V@U

在看看红色部分,这个时候(其实执行玩cdsOrgan.Append就出现了),lvIntf指向的内存块已经被清理了,因为有新的内存申请。所以后面在清理lvIntf := nil的时候出现访问违规错误。

 

好了到了这个时候,我们应该发现引发异常的真正原因了:在清理接口变量时,访问了一块不可预知的内存块,所以导致了访问违规错误。所以请大家在使用接口过程中注意接口的清理工作。

 

*认真阅读会收获更多。

 

==========================================

DIOCP官方社区|MyBean官方社区

http://diocp.wedelphi.com/

==========================================

【MyBean调试笔记】关于单元的释放顺序

【概述】

DEMO提交人:惠商软件  2508696439

问题描述:MDIConsole, DEMO如果Forms单元引用顺序放在mybean.console.pas文件之后如下图所示时:

image

创建同一EXE内的MDI子插件并显示,在不关闭MDI子窗体的情况下,关闭主EXE时,会造成关闭时产生访问违规错误。

image

【调试过程】

看了问题,能重现,能重新的问题就不算什么问题了,一定可以找到原因的,开启debug dcus后,发现错误停留产生时,停留在Screen.FSaveFocusedXXX这一句。调试发现果然Screen为nil了。

(PEV87O}1LU$O[ESGWQ_R_K

 

【问题分析】

mybean在创建插件TComponent子插件时会传入beanFactory.VclOwners, 这样在程序关闭时,清理类工厂时,会释放他,并清理他的子组件,达到自动清理的插件的目的,因为getBean的插件没有手动关闭,是等待清理beanFactory时进行清理的,清理的时候,Screen已经被清理,所以产生了该错误。

我们看看工程文件的引用顺序

program MDIConsole;

uses
  FastMM4,
  FastMM4Messages,

  mybean.console,
  mybean.core.beanFactory,

  Forms,

上面代码来看是会先清理Forms,然后再清理mybean.console,和mybean.core.beanFactory单元,但是因为mybean.core.beanFactory里面引用了Forms单元,所以清理顺序变成了

1.mybean.core.beanFactory,

2.Forms,

3.mybean.console,

 

mybean.console单元中管理了所由的类工厂插件接口,因为类工厂是通过接口来决定生命周期的,所以在清理mybean.console单元的时候,才会释放最后一个工厂接口的引用,也就是释放vclOwners和他的子插件,这个时候application和screen实例都已经被释放了。所以procedure TCustomForm.BeforeDestruction;中访问Screen才会引发异常。

现在来优化下mybean的核心类。

mybean.core.beanFactory和mybean.console单元中都引用Forms单元,这样不管你顺序怎么调整,都让Forms单元成为在这两个单元后面。然后在mybean.core.beanFactory被清理时,清理工厂接口资源。

使顺序变成这样

1.mybean.core.beanFactory,

2.mybean.console,

3.Forms。

【MyBean调试笔记】接口的使用和清理

【DEMO信息】

有问题的DEMO, 由芒果提交

【问题描述】

双击Tab页面关闭页面和插件的时候出现AV异常

image

【问题调试】

我们在调试的时候出现这个错误时断点停在这里

image

可以看到停留在这个位置@IntfClear,指针清理的位置

image

好我们来调试下这个过程,跟一下是什么时候出现的, 在end 处下个断点后切换到cpu页,我们看到在ret之前调用了一过程,这个地址应该是做一些清理工作后然后返回到调用者地址,

`TDZCGURW[(RGU7B72)5CNY

跟进去后,一会就跳到错误的界面,可以说明在清理时出现的,这个时候我们来看看这段代码

复制代码

procedure TfrmMain.pgcMainMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Index: Integer;
  lvPluginForm: IPluginForm;
  lvTabShtEx:TTabShtEx;
begin
  // 左键点击并且双击
  if (Button = mbLeft) and (ssDouble in Shift) then
  begin
    Index := pgcMain.IndexOfTabAt(X, Y);
    if Index >= 0 then
    begin
      lvTabShtEx := TTabShtEx(pgcMain.Pages[Index]);
      lvPluginForm := lvTabShtEx.PluginForm;
      if Application.MessageBox('确认要关闭画面吗?', '询问', MB_OKCANCEL + MB_ICONQUESTION) = IDCANCEL then
        Exit;
      lvPluginForm.freeObject;
      pgcMain.Pages[Index].Free;
    end;
  end;
end;

复制代码

这段代码中有一个lvPluginForm为接口IPluginForm变量, 过程在退出时会执行lvPluginForm := nil和其他一些资源的清理工作,清理的时候会触发对象的__release方法,但是我们看到这个对象已经释放掉了,然后在进行清理的时候出现了上面看到的访问违规的错误。

【问题解决】

找到出现问题的根本,解决起来就很快了,尽量不要等到过程清理时在去清理你的资源,特别是可能访问不存在的资源。在end;之前 加一句lvPluginForm := nil;这样就好了

分类: [MyBean说明书]