RMReport3.51破解手札㈡

本文深入解析了RMReport软件中打印限制的实现原理,并通过代码分析揭示了试用版与正式版之间的差异。针对这些限制,文章提出了具体的破解步骤,包括代码分析与修改,最终实现了去除打印限制的目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前文再续,书接上一回。

破解步骤二——代码分析:
  在跟踪过程发现,RMReport对打印的限制来自于rm_class.dcu文件,通过Dcu2Pas对rm_class.dcu反翻译得到_DoPrintReport函数的汇编源码,再结合D6对汇编代码的跟踪,得到如下的关键源码段:

  1. procedure_DoPrintReport;
  2. var
  3. i:Integer;
  4. j:Integer;
  5. lipgList:TStringList;
  6. lPrinter:TRMPrinter;
  7. liNeedNewPage:Boolean;
  8. lFactorX:Double;
  9. lFactorY:Double;
  10. lSavePrintInfo:TRMPageInfo;
  11. lOldPageNumber:Integer;
  12. lPageWidth:Integer;
  13. lPageHeight:Integer;
  14. asm
  15. @@474:{8D5358}leaedx,[ebx+$58]
  16. @@477:{8B45F0}moveax,[ebp-$10]
  17. @@480:{E800000000}callTRMPrinter.FillPrinterInfo
  18. @@485:{8B45F0}moveax,[ebp-$10]
  19. @@488:{E800000000}callTRMCustomPrinter.BeginDoc
  20. @@493:{8B4508}moveax,[ebp+$08]
  21. @@496:{80780C00}cmpbyteptr[eax+$0C],$00
  22. @@500:{744D}jz@@579
  23. ---------------------------------------------------------------------好戏开场,逐份打印方式
  24. @@502:{33DB}xorebx,ebx
  25. @@504:{EB33}jmp@@557
  26. @@506:{55}pushebp -----12F56C
  27. @@507:{33C0}xoreax,eax
  28. @@509:{E800000000}call_CanPrint ------EAX=1,EBX=0,ECX=0,EDX=12F504
  29. @@514:{59}popecx
  30. @@515:{84C0}testal,al -----if_CanPrintthen_PrintOnePage(....)
  31. @@517:{7409}jz@@528
  32. @@519:{55}pushebp
  33. @@520:{33C0}xoreax,eax
  34. @@522:{E800000000}call_PrintOnePage -----EAX=12F56C,ECX=64,EDX=0
  35. @@527:{59}popecx
  36. @@528:{55}pushebp
  37. @@529:{B801000000}moveax,$00000001 ----打印份数
  38. @@534:{E800000000}call_CanPrint ------EAX=1,EBX=1,ECX=0,EDX=12F504
  39. @@539:{59}popecx
  40. @@540:{84C0}testal,al -----if_CanPrintthen_PrintOnePage(....)
  41. @@542:{740C}jz@@556
  42. @@544:{55}pushebp
  43. @@545:{B801000000}moveax,$00000001
  44. @@550:{E800000000}call_PrintOnePage
  45. @@555:{59}popecx
  46. @@556:{43}incebx ----i++?/j++?
  47. @@557:{8B4508}moveax,[ebp+$08]
  48. @@560:{3B58F4}cmpebx,[eax-$0C]
  49. @@563:{7D72}jnl@@679 -----while(i<??)
  50. @@565:{8B4508}moveax,[ebp+$08]
  51. @@568:{8B40F8}moveax,[eax-$08]
  52. @@571:{80783000}cmpbyteptr[eax+$30],$00 ------此处判断了一个Cancel或Terminate标记,用户点击ProgressForm的Cancel按钮时终止打印
  53. @@575:{74B9}jz@@506
  54. @@577:{EB64}jmp@@679
  55. ----------------------------------------------------------------逐页打印方式
  56. @@579:{55}pushebp
  57. @@580:{33C0}xoreax,eax
  58. @@582:{E800000000}call_CanPrint
  59. @@587:{59}popecx
  60. @@588:{84C0}testal,al
  61. @@590:{7422}jz@@626
  62. @@592:{33DB}xorebx,ebx
  63. @@594:{EB0A}jmp@@606
  64. @@596:{55}pushebp
  65. @@597:{33C0}xoreax,eax
  66. @@599:{E800000000}call_PrintOnePage
  67. @@604:{59}popecx
  68. @@605:{43}incebx
  69. @@606:{8B4508}moveax,[ebp+$08]
  70. @@609:{3B58F4}cmpebx,[eax-$0C]
  71. @@612:{7D0C}jnl@@626
  72. @@614:{8B4508}moveax,[ebp+$08]
  73. @@617:{8B40F8}moveax,[eax-$08]
  74. @@620:{80783000}cmpbyteptr[eax+$30],$00
  75. @@624:{74E2}jz@@596
  76. @@626:{55}pushebp
  77. @@627:{B801000000}moveax,$00000001
  78. @@632:{E800000000}call_CanPrint
  79. @@637:{59}popecx
  80. @@638:{84C0}testal,al
  81. @@640:{7425}jz@@679
  82. @@642:{33DB}xorebx,ebx
  83. @@644:{EB0D}jmp@@659
  84. @@646:{55}pushebp
  85. @@647:{B801000000}moveax,$00000001
  86. @@652:{E800000000}call_PrintOnePage
  87. @@657:{59}popecx
  88. @@658:{43}incebx
  89. @@659:{8B4508}moveax,[ebp+$08]
  90. @@662:{3B58F4}cmpebx,[eax-$0C]
  91. @@665:{7D0C}jnl@@679
  92. @@667:{8B4508}moveax,[ebp+$08]
  93. @@670:{8B40F8}moveax,[eax-$08]
  94. @@673:{80783000}cmpbyteptr[eax+$30],$00
  95. @@677:{74DF}jz@@646
  96. @@679:---------------------------------------以下是清场代码,略过。
<!-- google_ad_client = "pub-5395599807454886"; /* 468x60, 创建于 08-12-15 */ google_ad_slot = "2456405239"; google_ad_width = 468; google_ad_height = 60; //-->
从上面的源码段中可以联想到原来的Delphi代码类似于:
文章出自:《编程手札》http://blog.youkuaiyun.com/nhconch
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。

  1. procedure_DoPrintReport;
  2. var
  3. i:Integer;
  4. begin
  5. if逐份打印then
  6. begin
  7. while(notUserCancel)do
  8. begin
  9. ifCanPrint(0)thenPrintOnePage(0);
  10. ifCanPrint(1)thenPrintOnePage(1);
  11. break;
  12. end;
  13. end
  14. elsebegin
  15. //逐页打印略……
  16. end;
  17. end;

  经过分析其中的CanPrint函数,是用于对用户在打印对话框中设定的页码打印范围作判断,以决定指定页码是否能打印的,而在循环中的那两句连续的PrintOnePage才是限制所在,很明显在一次循环内连续调用两次打印功能输出两页纸是比较反常的做法,由此可以推测控件作者在正式版和试用版中使用的是同一套代码,只是在试用版中注释掉一部分代码又加了几段限制代码,而主体的功能并没作删剪,这就为破解提供了可能。

破解步骤三——代码重建:
  在此需要将限制的代码恢复(改变)成原来正常的代码,正常打印的Pascal代码应该如下所示:

  1. procedure_DoPrintReport;
  2. var
  3. i,j:integer;
  4. begin
  5. if逐份打印then
  6. begin
  7. i:=0;
  8. repeat
  9. ifCanPrint(i)thenPrintOnePage(i);
  10. i:=i+1;
  11. until((i>=TRMEndPages.GetCount-1)or(UserCancel));
  12. end
  13. elsebegin
  14. //逐页打印
  15. fori:=0toTRMEndPages.GetCount-1do
  16. forj:=0tocopies{打印份数}do
  17. begin
  18. ifCanPrint(i)thenPrintOnePage(i);
  19. ifUserCancelthenBreak;
  20. end;
  21. end;
  22. end;
RMReport3.51破解手札㈠    RMReport3.51破解手札㈢

VB控件 RMReport7 转:RMReport的使用方法及详解 1、不打印特定的MemoView,套打常用 a.页面设置-->其它-->不打印背景图 b.设置MemoView属性printable=False 2、 如何打印wwDBGrid? 修改rm.inc,如果想支持RX,GIF,JPEG,DimandAccess,Halcyon,DBISAM, EHLib,也需要修改rm.inc //{$DEFINE InfoPower} //修改这行,去掉"//" //{$Ehlib} 3.试用版安装方法(以下假设将文件释放到c:/rm目录中) (1)Tools->Environments Option->Libary->Libary Path中增加: c:/rm/souce c:/rm/bpl $(DELPHI)/Lib $(DELPHI)/Bin $(DELPHI)/Imports $(DELPHI)/Projects/Bpl (2)Component->Install Packages->Add,选bpl/rm_d70.bpl 4.Delphi IDE中卸载以前的Report Machine版本,然后打开rm_r50.dpk,选"compile", 在打开rm_d50.dpk,选"Install". 包分成了Runtime package和Designer package,所以要安装顺序安装 5、单元格的变量格式用代码设置 t = TRMGridReportPage(RMGridReport1.Pages[0]).Grid.Cells[1, 1].View t = TRMMemoView(RMReport1.FindObject(&#39;memo1&#39;)); t.DisplayFormat := &#39;N0.001&#39; //数字型 t.DisplayFormat := &#39;Dyyyy/mm/dd&#39; //日期型 6、两遍报表如何用代码设置 GridReport1.DoublePass := True 7、用代码写数据字典: RMReport1.Dictionary.FieldAliases.Clear; RMReport1.Dictionary.FieldAliases[&#39;RMDBDataSet1&#39;] := &#39;动物&#39;; RMReport1.Dictionary.FieldAliases[&#39;RMDBDataSet1."Name"&#39;] := &#39;姓名&#39;; 这样在RM的设计器显示为自定义名称,为最终用户提供友好的显示 8、在报表中如何使用变量(或者如何给某个memoview赋值) a.RMVariables在RM_Class.pas中定义,是全局变量,这样定义后就可以在报表中使用变量"var1",例如: RMVariables[&#39;变量名称&#39;] := Edit1.Text; b.用报表中数据字典,TRMReport.Dictionary.Variables,需要注意的是,如果变量是字符型的需要用AsString赋值,其他类型的用RMReport.Dictionary.Variables[&#39;var1&#39;] := 1234,例如: RMReport1.LoadFromFile(&#39;1.rls&#39;); RMReport1.Dictionary.Variables.AsString[&#39;变量名称&#39;] := Edit1.Text; c. 直接对某个单元格赋值,例如: RMGridReport1.LoadFromFile(&#39;1.rls&#39;); TRMGridReportPage(RMGridReport1.Pages[0]).Grid.Cells[1,1].Text := &#39;值&#39;; 如果是RMReportRMReport1.LoadFromFile(&#39;1.rmf&#39;); t := RMReport1.FindObject(&#39;Memo1&#39;); if t nil then // var t: TRMView t.Memo.Text := &#39;dsdsdsds&#39;; d.脚本中直接引用Form的值 procedure Main; begin Memo1.Memo.Text := Form1.Edit1.Text; end; 9、自动换行 主项数据栏Stretched = true 文本框 Stretched = true WordWrap = true 10、RM内置变量(Script),增加中.... a.属性PrintAtAppendBlank=True CurReport.AppendBlanking=True时代表增加空行 在RM中,打印设置只能保存页面边距及打印份数、是否两遍打印以及
delphi2-delphi2010 全支持 dcu 装换 pas -------------------------------------------------------------------------------- Project Dcu2Pas Version 1.3 Purpose Decompile a D2-D7, K1-K3&#39;s dcu(dpu) file to Delphi source as origin as possible, without or with minimal modifications, then recompile to new one under other Delphi versions Author Nengwen Zhuo(卓能文) Homes http://soarowl.uhome.net, http://www.websamba.com/soarowl, http://soarowl.0catch.com Emails soarowl@yeah.net, soarowl@sina.com.cn Released 2003-02-10 Lastest home/dl/Dcu2Pas.rar(zip) FOR RESTORE YOUR LOST SOURCES AND OPTIMIZE YOUR CODES ONLY!!! -------------------------------------------------------------------------------- This project is in very early stage, no document yet. To see some features, reference my test cases file -- test.pas and the output file test.int, please. The output maybe more clear organised than source files!!! For further development, any suggestions and ideas are welcome. I have no time to update my homepages for a long time ;-) -------------------------------------------------------------------------------- Usage Run Dcu2pas, set properly options, select a desired dcu file double click to decompile it -------------------------------------------------------------------------------- Features - Supports the following type declarations and their typed consts: * Type redeclarations, for example: type MyTypeString = type String; * All integer types(Byte, Cardinal, Int64, Integer, Longint, Longword, Shortint, Smallint, Word) * All char types(AnsiChar, Char, WideChar) * All boolean types(Boolean, ByteBool, LongBool, WordBool) * Enumerated type, subrange of enumerated type and set of enumerated type For examples: type Size = (Small = 5, Medium = 10, Large = Small + Medium); TMySize = Medium..Large; type TEnumSet = set of (Club, Diamond, Heart, Spade); const vcSet4: TEnumSet = [Club,Spade]; * All real types(Comp, Currency, Double, Extended, Real, Real48, Single) * All string types(AnsiString, ShortString, String, String[XX], WideString) * Array type(with/without packed keyword), dynamic array and multidimensional dynamic array * Set type * Record type, with any variant parts in records. But if a record has any variant parts in it, the typed const may can&#39;t correctly decompile * Function/procedure type declaration - Support threadvar - Support resourcestring - Support class type, interface inheritation - Support object type - Support interface - Code decompiler to BASM, then a decpompiled file can recompile under other Delphi versions... - Code decompiler to Object-Pascal. I have some ideas, but I have no time, maybe in near future, I will code for it! -------------------------------------------------------------------------------- Update history Legend: - Bug fixed * Algorithm enhanced + New featuer added Ver2.0 Ver1.3 2003-02-10 * Code decompiler redesigned * Partly support D7 Ver1.2 2002-07-28 + Delete procedure, contructor, destructor frame 2002-07-18 + Procedure variable const + Now can distinguish: vc1: PChar =&#39;test&#39;; vc2: PChar = @vc1; 2002-05-28(Ver1.1) + Now correctly process interface properties and argument default values + Support resources, for example: {%R *.dfm}, {$R *.res} 2002-05-26 + Support default arguments + Support interface 2002-05-25 + Support object type + Support resourcestring + Support threadvar + Support function/procedure type 2002-05-24 + Support file type + Support set of enumerated type const decompiler + Support enumerated type const decompiler + Support subrange of enumerated type + Support dynamic array type - Array [enumerted type] of ... - Bugs in [packed] array fixed - Bugs in [packed] record fixed - Bugs in enumerated type fixed - Bugs in classify interface and implement declarations fixed
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值