root/Cheat Engine/Structuresfrm.pas @ 313

Revision 313, 75.3 kB (checked in by dark_byte, 7 months ago)

Release candidate 1 for 5.6

Line 
1unit Structuresfrm;
2
3interface
4
5uses
6  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7  Dialogs, Menus, StdCtrls, ExtCtrls, ComCtrls,cefuncproc,newkernelhandler,
8  symbolhandler, XMLDoc, XMLIntf, byteinterpreter, underc;
9
10const structureversion=1;
11
12
13type TStructElement=record
14                      offset: dword;
15                      description:string;
16                      pointerto: boolean;  //determines if it's a pointer to a structure, or the structure itself
17                      pointertosize: dword;
18                      structurenr: integer; //-1 and lower=base element   (they can't be both -1)
19                      bytesize: dword; //size in bytes of how big this element is. (also for base elements)
20                    end;
21
22
23type TbaseStructure=record
24  name: string;
25  structelement: array of TStructElement;
26  end;
27
28  //TfrmStructures = class;
29  Tstructure=class
30  private
31    //frmStructures: TfrmStructures; //obsolete
32    treeviewused: ttreeview;
33    addresses: array of dword;
34    basestructure: integer;
35    parentnode: ttreenode; //owner of this object
36    objects: array of record //same size as the structelement of the base object
37                        nodetoupdate: ttreenode; //same size as the structelement of the base object
38                        child: tstructure; //if it is a pointer then this points to the structure that defines it
39                        //currentvalue: string; //obsolete, just get it on request
40                      end;
41  public
42    procedure refresh;
43    procedure removeAddress(i: integer);
44    procedure setaddress(i: integer; x:dword);
45    constructor create(treeviewused: ttreeview;parentnode: ttreenode; addresses: array of dword; basestructure: integer);
46    destructor destroy; override;
47  end;
48
49  TfrmStructures = class(TForm)
50    MainMenu1: TMainMenu;
51    File1: TMenuItem;
52    Open1: TMenuItem;
53    Save1: TMenuItem;
54    Structures1: TMenuItem;
55    Definenewstructure1: TMenuItem;
56    N1: TMenuItem;
57    Panel1: TPanel;
58    PopupMenu1: TPopupMenu;
59    Addelement1: TMenuItem;
60    updatetimer: TTimer;
61    Deleteelement1: TMenuItem;
62    OpenDialog1: TOpenDialog;
63    SaveDialog1: TSaveDialog;
64    ChangeElement1: TMenuItem;
65    N2: TMenuItem;
66    Addtoaddresslist1: TMenuItem;
67    Recalculateaddress1: TMenuItem;
68    N3: TMenuItem;
69    Addextraaddress1: TMenuItem;
70    edtAddress: TEdit;
71    PopupMenu2: TPopupMenu;
72    Paste1: TMenuItem;
73    Copy1: TMenuItem;
74    Cut1: TMenuItem;
75    N4: TMenuItem;
76    Remove1: TMenuItem;
77    N5: TMenuItem;
78    SelectAll1: TMenuItem;
79    N6: TMenuItem;
80    Undo1: TMenuItem;
81    N7: TMenuItem;
82    N8: TMenuItem;
83    Newwindow1: TMenuItem;
84    Commands1: TMenuItem;
85    Deletecurrentstructure1: TMenuItem;
86    Renamestructure1: TMenuItem;
87    ScrollBox1: TScrollBox;
88    tvStructureView: TTreeView;
89    HeaderControl1: THeaderControl;
90    Memorybrowsepointer1: TMenuItem;
91    Memorybrowsethisaddress1: TMenuItem;
92    Autoguessoffsets1: TMenuItem;
93    Setgroup1: TMenuItem;
94    procedure Definenewstructure1Click(Sender: TObject);
95    procedure Addelement1Click(Sender: TObject);
96    procedure updatetimerTimer(Sender: TObject);
97    procedure tvStructureViewCollapsing(Sender: TObject; Node: TTreeNode;
98      var AllowCollapse: Boolean);
99    procedure edtAddressChange(Sender: TObject);
100    procedure tvStructureViewExpanding(Sender: TObject; Node: TTreeNode;
101      var AllowExpansion: Boolean);
102    procedure tvStructureViewMouseDown(Sender: TObject; Button: TMouseButton;
103      Shift: TShiftState; X, Y: Integer);
104    procedure PopupMenu1Popup(Sender: TObject);
105    procedure Deleteelement1Click(Sender: TObject);
106    procedure Save1Click(Sender: TObject);
107    procedure Open1Click(Sender: TObject);
108    procedure New1Click(Sender: TObject);
109    procedure ChangeElement1Click(Sender: TObject);
110    procedure tvStructureViewDblClick(Sender: TObject);
111    procedure Addtoaddresslist1Click(Sender: TObject);
112    procedure Recalculateaddress1Click(Sender: TObject);
113    procedure FormClose(Sender: TObject; var Action: TCloseAction);
114    procedure HeaderControl1SectionResize(HeaderControl: THeaderControl;
115      Section: THeaderSection);
116    procedure Addextraaddress1Click(Sender: TObject);
117    procedure Undo1Click(Sender: TObject);
118    procedure Cut1Click(Sender: TObject);
119    procedure FormCreate(Sender: TObject);
120    procedure Copy1Click(Sender: TObject);
121    procedure Paste1Click(Sender: TObject);
122    procedure SelectAll1Click(Sender: TObject);
123    procedure Remove1Click(Sender: TObject);
124    procedure tvStructureViewAdvancedCustomDrawItem(
125      Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState;
126      Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean);
127    procedure FormDestroy(Sender: TObject);
128    procedure PopupMenu2Popup(Sender: TObject);
129    procedure Renamestructure1Click(Sender: TObject);
130    procedure Deletecurrentstructure1Click(Sender: TObject);
131    procedure Newwindow1Click(Sender: TObject);
132    procedure Memorybrowsepointer1Click(Sender: TObject);
133    procedure Memorybrowsethisaddress1Click(Sender: TObject);
134    procedure Autoguessoffsets1Click(Sender: TObject);
135    procedure Setgroup1Click(Sender: TObject);
136  private
137    { Private declarations }
138    currentstructure: tstructure;
139
140
141    addresses: array of dword;  //first address (old compat)
142
143    groupindex: array of integer; //e.g 1,3,9,10000000
144    groups: array of dword;               //the grouplist holds the groupnumbers provided by the user
145    internalgrouplist: array of dword;    //where as the internelgrouplist holds the entrypoints into the groupindex for each specific address
146    edits: array of tedit;
147    lastnewedit: TEdit;
148
149
150
151    procedure refreshmenuitems;
152    procedure definedstructureselect(sender:tobject);
153    function convertVariableTypeTostructnr(d: TVariableType): integer;
154//    function RawToType(address: dword; const buf: array of byte; size: integer):integer;
155    procedure ExtraEnter(Sender: TObject);
156    procedure automaticallyGuessOffsets(baseOffset: dword; structsize: integer);
157    procedure UpdateGroupIndex;
158  public
159    { Public declarations }
160    procedure setaddress(i: integer; x:dword);
161    procedure update(doOthers: boolean);
162  end;
163
164var
165  frmStructures: array of TfrmStructures;
166  definedstructures: array of TbaseStructure;
167
168procedure sortStructure(struct: TbaseStructure);
169
170implementation
171
172{$R *.dfm}
173
174uses StructuresAddElementfrm,valuechange,mainunit, MemoryBrowserFormUnit, opensave;
175
176destructor TStructure.destroy;
177var i: integer;
178begin
179  for i:=0 to length(objects)-1 do
180    if objects[i].child<>nil then objects[i].child.Free;
181
182  inherited destroy;
183end;
184
185constructor TStructure.create(treeviewused: ttreeview;parentnode: ttreenode; addresses: array of dword; basestructure: integer);
186var elementnr: integer;
187    s: tstructure;
188    i: integer;
189begin
190
191  setlength(self.addresses,length(addresses));
192  for i:=0 to length(addresses)-1 do
193    self.addresses[i]:=addresses[i];
194   
195  self.basestructure:=basestructure;
196  self.treeviewused:=treeviewused;
197  self.parentnode:=parentnode;
198  inherited create;
199end;
200
201procedure TStructure.removeAddress(i: integer);
202var j: integer;
203begin
204  for j:=i to length(addresses)-2 do
205    addresses[j]:=addresses[j+1];
206
207  if i<length(addresses) then //just in case it didn't get the previous add...
208    setlength(addresses,length(addresses)-1);
209
210  for j:=0 to length(objects)-1 do
211    if objects[j].child<>nil then
212      objects[j].child.removeAddress(i);
213  refresh;
214end;
215
216
217procedure TStructure.setaddress(i: integer; x:dword);
218var j: integer;
219begin
220  if i>=length(addresses) then
221    setlength(addresses,i+1);
222
223  //update children
224  for j:=0 to length(objects)-1 do
225  begin
226    if objects[j].child<>nil then
227      objects[j].child.setaddress(i,x);
228  end;
229
230  addresses[i]:=x;
231  refresh;
232end;
233
234procedure TStructure.refresh;
235var c,i,j,k: integer;
236    newtext,typename: string;
237    snr: integer;
238    elementoffset: dword;
239    buf: array of byte;
240    x: dword;
241
242    defaultwidth: integer;
243
244    ws: widestring;
245    pc: pchar;
246    pwc: pwidechar;
247    newaddress: dword;
248
249    s: tstructure;
250
251    elementnr: integer;
252    currentvalues: array of string;
253
254begin
255  //check if all nodes are present and remove those not needed anymore
256  //and adjust the text when needed
257 // treeviewused.Items.BeginUpdate;
258  setlength(buf,32);
259
260  if basestructure<0 then
261  begin
262    //this is a base type, it has to be a child. (and pointer type)
263    if length(objects)=0 then setlength(objects,1);
264  end
265  else
266  begin
267    if length(objects)<length(definedstructures[basestructure].structelement) then
268      setlength(objects,length(definedstructures[basestructure].structelement));
269
270    if length(objects)>length(definedstructures[basestructure].structelement) then
271    begin
272      //delete the extra ones
273      for i:=length(definedstructures[basestructure].structelement) to length(objects)-1 do
274      begin
275        if objects[i].nodetoupdate<>nil then objects[i].nodetoupdate.Delete;
276        if objects[i].child<>nil then objects[i].child.Free;
277      end;
278
279      setlength(objects,length(definedstructures[basestructure].structelement));
280
281
282    end;
283    treeviewused.Items.GetFirstNode.Text:=definedstructures[basestructure].name+#13;
284  end;
285
286  setlength(currentvalues,length(addresses));
287
288  for i:=0 to length(objects)-1 do
289  begin
290
291   
292    //define the text for this element
293    if basestructure<0 then
294    begin
295      snr:=basestructure;
296      elementoffset:=0;
297    end
298    else
299    begin
300      elementoffset:=definedstructures[basestructure].structelement[i].offset;
301     
302      if definedstructures[basestructure].structelement[i].pointerto then
303        typename:='pointer to '
304      else
305        typename:='';
306
307      snr:=definedstructures[basestructure].structelement[i].structurenr;
308    end;
309
310    for c:=0 to length(addresses)-1 do
311    begin
312      if snr<0 then
313      begin
314        if basestructure>=0 then
315        begin
316          if definedstructures[basestructure].structelement[i].pointerto then
317          begin
318            currentvalues[c]:='->';
319
320            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],4,x) then
321              currentvalues[c]:=currentvalues[c]+inttohex(PDWORD(@buf[0])^,8)
322            else
323              currentvalues[c]:=currentvalues[c]+'???';
324
325          end;
326        end;
327
328        if (basestructure<0) or (not definedstructures[basestructure].structelement[i].pointerto) then
329        case snr of
330          -1:
331          begin
332            if c=0 then typename:=typename+'Byte';
333
334            //read the value
335            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],1,x) then
336              currentvalues[c]:=inttostr(byte(buf[0]))
337            else
338              currentvalues[c]:='???';
339          end;
340          -2:
341          begin
342            if c=0 then typename:=typename+'Byte Signed';
343
344            //read the value
345            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],1,x) then
346              currentvalues[c]:=inttostr(Shortint(buf[0]))
347            else
348              currentvalues[c]:='???';
349          end;
350          -3:
351          begin
352            if c=0 then typename:=typename+'Byte Hexadecimal';
353            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],1,x) then
354              currentvalues[c]:=inttohex(buf[0],2)
355            else
356              currentvalues[c]:='???';
357          end;
358          -4:
359          begin
360            if c=0 then typename:=typename+'2 Bytes';
361            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],2,x) then
362              currentvalues[c]:=inttostr(PWORD(@buf[0])^)
363            else
364              currentvalues[c]:='???';
365          end;
366          -5:
367          begin
368            if c=0 then typename:=typename+'2 Bytes Signed';
369            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],2,x) then
370              currentvalues[c]:=inttostr(PSmallint(@buf[0])^)
371            else
372              currentvalues[c]:='???';
373          end;
374          -6:
375          begin
376            if c=0 then typename:=typename+'2 Bytes Hexadecimal';
377            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],2,x) then
378              currentvalues[c]:=inttohex(PWORD(@buf[0])^,4)
379            else
380              currentvalues[c]:='???';
381          end;
382          -7:
383          begin
384            if c=0 then typename:=typename+'4 Bytes';
385            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],4,x) then
386              currentvalues[c]:=inttostr(PDWORD(@buf[0])^)
387            else
388              currentvalues[c]:='???';
389          end;
390
391          -8:
392          begin
393            if c=0 then typename:=typename+'4 Bytes Signed';
394            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],4,x) then
395              currentvalues[c]:=inttostr(pinteger(@buf[0])^)
396            else
397              currentvalues[c]:='???';
398          end;
399
400          -9:
401          begin
402            if c=0 then typename:=typename+'4 Bytes Hexadecimal';
403            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],4,x) then
404              currentvalues[c]:=inttohex(PDWORD(@buf[0])^,8)
405            else
406              currentvalues[c]:='???';
407          end;
408          -10:
409          begin
410            if c=0 then typename:=typename+'8 Bytes';
411            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],8,x) then
412              currentvalues[c]:=inttostr(pint64(@buf[0])^)
413            else
414              currentvalues[c]:='???';
415          end;
416          -11:
417          begin
418            if c=0 then typename:=typename+'8 Bytes Hexadecimal';
419            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],8,x) then
420              currentvalues[c]:=inttohex(pint64(@buf[0])^,16)
421            else
422              currentvalues[c]:='???';
423          end;
424          -12:
425          begin
426            if c=0 then typename:=typename+'Float';
427            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],4,x) then
428              currentvalues[c]:=floattostr(psingle(@buf[0])^)
429            else
430              currentvalues[c]:='???';
431          end;
432          -13:
433          begin
434            if c=0 then typename:=typename+'Double';
435            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],8,x) then
436              currentvalues[c]:=floattostr(pdouble(@buf[0])^)
437            else
438              currentvalues[c]:='???';
439          end;
440          -14:
441          begin
442            if c=0 then typename:=typename+'String';
443
444            if basestructure>=0 then
445              k:=definedstructures[basestructure].structelement[i].bytesize
446            else
447            begin
448              elementnr:=parentnode.Index;
449              s:=parentnode.data;
450              k:=definedstructures[s.basestructure].structelement[elementnr].pointertosize;
451            end;
452
453            if length(buf)<=k then
454              setlength(buf,k+1);
455
456            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],k,x) then
457            begin
458              buf[k]:=0;
459              for j:=0 to k-1 do
460                if (buf[j]>0) and (buf[j]<32) then buf[j]:=ord('?');
461
462              pc:=@buf[0];
463              currentvalues[c]:=pc;
464            end
465            else
466              currentvalues[c]:='???';
467          end;
468          -15:
469          begin
470            if c=0 then typename:=typename+'String Unicode';
471            if basestructure>=0 then
472              k:=definedstructures[basestructure].structelement[i].bytesize
473            else
474            begin
475              elementnr:=parentnode.Index;
476              s:=parentnode.data;
477              k:=definedstructures[s.basestructure].structelement[elementnr].pointertosize;
478            end;
479            if length(buf)<=k then
480              setlength(buf,k+1);
481
482
483            if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],k,x) then
484            begin
485              buf[k]:=0;
486              buf[k-1]:=0;
487              for j:=0 to k-1 do
488                if (buf[j]>0) and (buf[j]<32) then buf[j]:=ord('?');
489              pwc:=@buf[0];
490              ws:=pwc;
491              currentvalues[c]:=ws;
492            end
493            else
494              currentvalues[c]:='???';
495          end;
496        end;
497      end else
498      begin
499        //it's a defined structure (has to be a pointer)
500        if c=0 then typename:=definedstructures[snr].name;
501
502        if readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@buf[0],8,x) then
503          currentvalues[c]:='->'+inttohex(pdword(@buf[0])^,8)
504        else
505          currentvalues[c]:='->???';
506      end;
507
508    end;
509
510    if basestructure<0 then
511    begin
512      newtext:=inttohex(elementoffset,4)+' - '+'('+typename+')';
513    end
514    else
515    begin
516      newtext:=inttohex(elementoffset,4)+' - '+definedstructures[basestructure].structelement[i].description;//+'('+typename+')';
517    end;
518    newtext:=newtext+#13;
519
520    for c:=0 to length(addresses)-1 do
521      newtext:=newtext+{inttohex(addresses[c]+elementoffset,8)+' : '+}currentvalues[c]+#13;
522
523    //see if a node exists or not, if not create it.
524    if objects[i].nodetoupdate=nil then
525    begin
526      objects[i].nodetoupdate:=treeviewused.Items.AddChild(self.parentnode,newtext);
527      objects[i].nodetoupdate.Data:=self;
528    end
529    else
530    begin
531      if newtext<>objects[i].nodetoupdate.Text then
532        objects[i].nodetoupdate.Text:=newtext;
533    end;
534
535    if basestructure>=0 then
536    begin
537      if objects[i].nodetoupdate.HasChildren <> definedstructures[basestructure].structelement[i].pointerto then
538        objects[i].nodetoupdate.HasChildren:=definedstructures[basestructure].structelement[i].pointerto;
539
540      if objects[i].child<>nil then
541      begin
542        //do the same for the children
543        //pointer
544
545        for c:=0 to length(addresses)-1 do
546        begin
547          newaddress:=0;
548          readprocessmemory(processhandle,pointer(addresses[c]+elementoffset),@newaddress,4,x);
549
550          objects[i].child.addresses[c]:=newaddress;
551        end;
552        objects[i].child.refresh;
553      end;
554
555    end;
556  end;
557
558
559  if treeviewused.Items.GetFirstNode<>nil then
560    treeviewused.Items.GetFirstNode.Expand(false);
561
562  //treeviewused.Items.endupdate;
563end;
564
565procedure sortStructure(struct: TbaseStructure);
566var
567  i,j: integer;
568  l: integer;
569  temp: TStructElement;
570begin
571  //bubblesort
572  i:=1;
573  l:=length(struct.structelement);
574  for i:=1 to l-1 do
575  begin
576    if struct.structelement[i-1].offset>struct.structelement[i].offset then
577    begin
578      //the previous entry is bigger than the current entry
579
580      //find a entry that's smaller
581      for j:=i to l-1 do
582      begin
583        if struct.structelement[j-1].offset>struct.structelement[j].offset then
584        begin
585          //swap
586          temp:=struct.structelement[j-1];
587          struct.structelement[j-1]:=struct.structelement[j];
588          struct.structelement[j]:=temp;
589        end;
590
591      end;
592    end;
593  end;
594
595
596end;
597
598procedure TfrmStructures.update(doOthers: boolean);
599{Called twice, first time true, 2nd time false. Only on false actually update}
600var i: integer;
601begin
602  if DoOthers then
603  begin
604    for i:=0 to length(frmStructures)-1 do
605      frmStructures[i].update(false);
606  end
607  else
608  begin
609    RefreshMenuItems;
610    if currentstructure<>nil then
611    begin
612      if currentstructure.basestructure < length(definedstructures) then
613        currentstructure.refresh
614      else
615        freeandnil(currentstructure);
616 
617    end;
618  end;
619
620  if currentstructure=nil then
621    tvStructureView.Items.Clear;
622end;
623
624procedure TfrmStructures.setaddress(i: integer; x: dword);
625begin
626  addresses[i]:=x;
627     
628  if currentstructure<>nil then
629  begin
630    currentstructure.setAddress(i,x);
631 {
632    if length(currentstructure.addresses)<=i then
633      setlength(currentstructure.addresses,i+1);
634    currentstructure.addresses[i]:=x;
635    currentstructure.parentnode.Text:=edtaddress.text+'-'+definedstructures[currentstructure.basestructure].name;
636    currentstructure.refresh;  }
637  end;
638end;
639
640
641function TfrmStructures.convertVariableTypeTostructnr(d: TVariableType): integer;
642begin
643  result:=-1;
644  case d of
645    vtByte: result:=-1;
646    vtWord: result:=-4;
647    vtDword: result:=-7;
648    vtQword: result:=-7;
649    vtSingle: result:=-12;
650    vtDouble: result:=-13;
651    vtString: result:=-14;
652    vtUnicodeString: result:=-7; //currently not implemented
653    vtByteArray: result:=-7; //FindTypeOfData should never return this
654    vtBinary: result:=-7; //nor this
655    vtAll: result:=-7; //also not this
656    vtCustom: result:=-7; //certainly not this
657    vtPointer: result:=-7; //currently not handled, but can be used to speed up things...
658  end;
659end;
660
661{
662function TfrmStructures.RawToType(address: dword; const buf: array of byte; size: integer):integer;
663//returns: -1,-4,-7,-12,-13,-14
664var x: string;
665    i: integer;
666    isstring: boolean;
667begin
668  result:=0;
669
670  i:=address mod 4;
671  case i of
672    1: //1 byte
673    begin
674      result:=-1;
675      exit;
676    end;
677
678    2,3: //2 byte
679    begin
680      result:=-4;
681      exit;
682    end;
683  end;
684
685
686
687  if size>=8 then  //check if a double can be used
688  begin
689    if pdouble(@buf[0])^<>0 then
690    begin
691      x:=floattostr(pdouble(@buf[0])^);
692      if (pos('E',x)=0) then  //no exponent
693      begin
694        //check if the value isn't bigger or smaller than 1000000 or smaller than -1000000
695        if (pdouble(@buf[0])^<1000000) and (pdouble(@buf[0])^>-1000000) then
696        begin
697          result:=-13;
698          exit;
699        end;
700      end;
701    end;
702  end;
703
704  if (size>=2) and (size<4) then
705  begin
706    result:=-4;
707    exit;
708  end;
709
710  if (size=1) then
711  begin
712    result:=-1;
713    exit;
714  end;
715
716  //still here so either 4, or not a double
717  //check if it confirms to a single float
718  if psingle(@buf[0])^<>0 then
719  begin
720    x:=floattostr(psingle(@buf[0])^);
721    if (pos('E',x)=0) then  //no exponent
722    begin
723      //check if the value isn't bigger or smaller than 1000000 or smaller than -1000000
724      if (psingle(@buf[0])^<1000000) and (psingle(@buf[0])^>-1000000) then
725      begin
726        result:=-12;
727        exit;
728      end;
729    end;
730  end;
731
732  //still here, so check if it matches a string
733  isstring:=true;
734  i:=0;
735  while i<4 do
736  begin
737    //check if the first 4 characters match with a standard ascii values (32 to 127)
738    if (buf[i]<32) or (buf[i]>127) then
739    begin
740      isstring:=false;
741      break;
742    end;
743    inc(i);
744  end;
745
746  if isstring then
747  begin
748    result:=-14;
749    exit;
750  end;
751
752  //none of the above, so....
753  result:=-7;
754end;
755}
756
757procedure TfrmStructures.Definenewstructure1Click(Sender: TObject);
758var sstructsize:string;
759    autofillin,structsize: integer;
760    structname: string;
761
762begin
763  structname:='unnamed structure';
764  if not inputquery('Structure define','Give the name for this structure',structname) then exit;
765 
766  autofillin:=messagedlg('Do you want Cheat Engine to try and fill in the most basic types of the struct using the current address?',mtconfirmation,[mbyes,mbno,mbcancel],0);
767  if autofillin=mrcancel then exit;
768
769  setlength(definedstructures,length(definedstructures)+1);
770  definedstructures[length(definedstructures)-1].name:=structname;
771
772  refreshmenuitems;
773  structures1.Items[structures1.Count-1].Click;
774
775  if autofillin=mryes then
776  begin
777
778    sstructsize:='4096';
779    if not inputquery('Structure define','Please give a starting size of the struct (You can change this later if needed)',Sstructsize) then exit;
780    structsize:=strtoint(sstructsize);
781
782    automaticallyGuessOffsets(0, structsize);
783  end;
784  update(true);
785end;
786
787procedure TfrmStructures.definedstructureselect(sender:tobject);
788var name: string;
789begin
790  caption:='Memory dissect - '+StripHotkey((sender as tmenuitem).Caption);
791  if currentstructure<>nil then
792    freeandnil(currentstructure);
793
794  tvStructureView.Items.Clear;
795
796  currentstructure:=tstructure.create(tvStructureView,tvStructureView.Items.Add(nil,definedstructures[(sender as tmenuitem).Tag].name+#13),addresses,(sender as tmenuitem).Tag);
797  update(false);
798
799  commands1.enabled:=true;
800end;
801
802procedure TfrmStructures.refreshmenuitems;
803var i: integer;
804    mi: tmenuitem;
805begin
806  //go through the definedstructures array and see if they are in the list or not
807
808  //delete the ones that are too many
809  while (structures1.Count-2)>length(definedstructures) do
810    structures1.Delete(structures1.Count-1); //delete the last one
811
812   
813  for i:=0 to length(definedstructures)-1 do
814  begin
815    if i<structures1.Count-2 then
816    begin
817      //check the name, and update if needed
818      if structures1.Items[i+2].Caption<>definedstructures[i].name then
819        structures1.Items[i+2].Caption:=definedstructures[i].name;
820    end
821    else //add it
822    begin
823      mi:=tmenuitem.Create(self);
824      mi.Caption:=definedstructures[i].name;
825      mi.OnClick:=definedstructureselect;
826      mi.Tag:=i;
827      structures1.Add(mi);
828    end;
829
830    if (currentstructure<>nil) and (currentstructure.basestructure=i) then
831      structures1.Items[i+2].Checked:=true
832    else
833      structures1.Items[i+2].Checked:=false;
834
835  end;
836end;
837
838
839procedure TfrmStructures.Addelement1Click(Sender: TObject);
840var d,i,j,k,l:integer;
841    size: dword;
842    structtype: string;
843    selectedstructure: tstructure;
844    selectedelement: integer;
845    selectednode: ttreenode;
846    base: dword;
847begin
848  if currentstructure=nil then exit;
849
850  selectednode:=tvStructureView.Selected;
851  if selectednode=nil then
852    selectedstructure:=currentstructure
853  else
854    selectedstructure:=tstructure(selectednode.Data);
855
856  if selectedstructure=nil then
857    selectedstructure:=currentstructure;
858
859  if selectedstructure.basestructure<0 then
860  begin
861    selectedstructure:=tstructure(selectednode.parent);
862    selectednode:=selectednode.Parent;
863  end;
864
865  if selectednode=nil then //lastnode
866    selectedelement:=length(definedstructures[selectedstructure.basestructure].structelement)-1
867  else
868  begin
869    selectedelement:=selectednode.index-1;
870  end;
871
872
873  if currentstructure=nil then raise exception.Create('First select a structure you want to modify or define one first');
874  with tfrmstructuresaddelement.create(self) do
875  begin
876    //fill the combobox with possible types
877    //the base types, and defined types
878    cbtype.Items.AddObject('Byte',pointer(1));
879    cbtype.Items.AddObject('Byte Signed',pointer(1));
880    cbtype.Items.AddObject('Byte Hexadecimal',pointer(1));
881    cbtype.Items.AddObject('2 Bytes',pointer(2));
882    cbtype.Items.AddObject('2 Bytes Signed',pointer(2));
883    cbtype.Items.AddObject('2 Bytes Hexadecimal',pointer(2));
884    cbtype.Items.AddObject('4 Bytes',pointer(4));
885    cbtype.Items.AddObject('4 Bytes Signed',pointer(4));
886    cbtype.Items.AddObject('4 Bytes Hexadecimal',pointer(4));
887    cbtype.Items.AddObject('8 Bytes',pointer(8));
888    cbtype.Items.AddObject('8 Bytes Hexadecimal',pointer(8));
889    cbtype.Items.AddObject('Float',pointer(4));
890    cbtype.Items.AddObject('Double',pointer(8));
891    cbtype.Items.AddObject('String',pointer(10));
892    cbtype.Items.AddObject('String Unicode',pointer(10));
893
894    cbtype.ItemIndex:=8;
895    cbType.OnChange(cbType);
896
897    cbtype.DropDownCount:=17;
898
899    //and add the other defined structures as well
900    for i:=0 to length(definedstructures)-1 do
901    begin
902      size:=0;
903      for j:=0 to length(definedstructures[i].structelement)-1 do
904        inc(size,definedstructures[i].structelement[j].bytesize);
905
906      cbtype.Items.AddObject(definedstructures[i].name,pointer(size));
907    end;
908
909
910    if selectedstructure.basestructure>=0 then
911    begin
912      if selectednode.index>=0 then
913        edtOffset.text:=inttohex(definedstructures[selectedstructure.basestructure].structelement[selectednode.index].offset-1,1)
914      else
915      begin
916        if length(definedstructures[selectedstructure.basestructure].structelement)>0 then
917          edtOffset.text:=inttohex(definedstructures[selectedstructure.basestructure].structelement[length(definedstructures[selectedstructure.basestructure].structelement)-1].offset+definedstructures[selectedstructure.basestructure].structelement[length(definedstructures[selectedstructure.basestructure].structelement)-1].bytesize,1);
918      end;
919    end;
920
921
922    if showmodal=mrok then
923    begin
924      if cbtype.ItemIndex=-1 then exit;
925
926      //allocate a spot for the new element
927      i:=length(definedstructures[selectedstructure.basestructure].structelement);
928      setlength(definedstructures[selectedstructure.basestructure].structelement,i+1);
929
930      //move the elements after selectedelement
931      for j:=i-1 downto selectedelement+1 do
932        definedstructures[selectedstructure.basestructure].structelement[j+1]:=definedstructures[selectedstructure.basestructure].structelement[j];
933
934      i:=selectedelement+1;
935
936      definedstructures[selectedstructure.basestructure].structelement[i].pointerto:=cbpointerto.checked;
937      definedstructures[selectedstructure.basestructure].structelement[i].description:=edtDescription.text;
938      base:=strToInt('$'+edtOffset.text);
939
940      if definedstructures[selectedstructure.basestructure].structelement[i].pointerto then
941      begin
942        if cbtype.itemindex<=14 then
943          definedstructures[selectedstructure.basestructure].structelement[i].structurenr:=-(cbtype.ItemIndex+1)
944        else
945          definedstructures[selectedstructure.basestructure].structelement[i].structurenr:=cbtype.ItemIndex-15;
946
947        definedstructures[selectedstructure.basestructure].structelement[i].bytesize:=4;
948        definedstructures[selectedstructure.basestructure].structelement[i].pointertosize:=bytesize;
949      end
950      else
951      begin
952        if cbtype.ItemIndex<=14 then //basetype
953        begin
954          definedstructures[selectedstructure.basestructure].structelement[i].offset:=base;
955          definedstructures[selectedstructure.basestructure].structelement[i].structurenr:=-(cbtype.ItemIndex+1);
956          definedstructures[selectedstructure.basestructure].structelement[i].bytesize:=bytesize;
957        end
958        else
959        begin
960          //not a pointer, but also no base type, so just append the selected structure
961          j:=cbtype.ItemIndex-15;  //j now contains the structure number
962
963          d:=length(definedstructures[j].structelement);
964          setlength(definedstructures[selectedstructure.basestructure].structelement,length(definedstructures[currentstructure.basestructure].structelement)+d-1);
965
966          //move the other elements as well
967          for k:=length(definedstructures[selectedstructure.basestructure].structelement)-1 downto selectedelement+d+1 do
968            definedstructures[selectedstructure.basestructure].structelement[k]:=definedstructures[selectedstructure.basestructure].structelement[k-d+1];
969
970          for k:=0 to length(definedstructures[j].structelement)-1 do
971          begin
972            definedstructures[selectedstructure.basestructure].structelement[i]:=definedstructures[j].structelement[k];
973            definedstructures[selectedstructure.basestructure].structelement[i].description:=edtDescription.text+'_'+definedstructures[j].structelement[k].description;
974            inc(definedstructures[selectedstructure.basestructure].structelement[i].offset, base);
975            inc(i);
976          end;
977        end;
978      end;
979
980      sortStructure(definedstructures[selectedstructure.basestructure]);
981      self.update(true);
982      mainform.itemshavechanged:=true;
983
984      if not tvStructureView.Items.GetFirstNode.Expanded then
985        tvStructureView.Items.GetFirstNode.Expand(false);
986    end;
987  end;
988end;
989
990
991
992procedure TfrmStructures.updatetimerTimer(Sender: TObject);
993begin
994  if currentstructure<>nil then currentstructure.refresh;
995end;
996
997procedure TfrmStructures.tvStructureViewCollapsing(Sender: TObject;
998  Node: TTreeNode; var AllowCollapse: Boolean);
999begin
1000  allowcollapse:=not (node=tvStructureView.Items.GetFirstNode);
1001
1002
1003  currentstructure.refresh;
1004end;
1005
1006procedure TfrmStructures.edtAddressChange(Sender: TObject);
1007begin
1008  try
1009    setaddress((sender as TEdit).tag, symhandler.getAddressFromName((sender as TEdit).text));
1010  except
1011
1012  end;
1013end;
1014
1015procedure TfrmStructures.tvStructureViewExpanding(Sender: TObject;
1016  Node: TTreeNode; var AllowExpansion: Boolean);
1017var s: tstructure;
1018    elementnr: integer;
1019    basestruct: integer;
1020    elementaddress: array of dword;
1021    i,j: integer;
1022begin
1023  AllowExpansion:=true;
1024
1025  s:=tstructure(node.Data);
1026  if s=nil then exit;
1027  if node.getFirstChild<>nil then exit;
1028
1029  elementnr:=node.Index;
1030
1031  //structure and element nr are known, so lets see what it is
1032
1033  basestruct:=s.basestructure;
1034
1035  setlength(elementaddress,length(addresses));
1036  for i:=0 to length(addresses)-1 do
1037  begin
1038    elementaddress[i]:=addresses[i];
1039    for j:=0 to elementnr-2 do
1040      inc(elementaddress[i],definedstructures[basestruct].structelement[j].bytesize);
1041  end;
1042
1043  //make sure it's a pointer
1044  if definedstructures[basestruct].structelement[elementnr].pointerto then
1045  begin
1046    s.objects[elementnr].child:=tstructure.create(tvStructureView,node,elementaddress,definedstructures[basestruct].structelement[elementnr].structurenr);
1047
1048    setlength(s.objects[elementnr].child.addresses,length(currentstructure.addresses));
1049    for i:=0 to length(currentstructure.addresses)-1 do
1050      s.objects[elementnr].child.addresses[i]:=currentstructure.addresses[i];
1051  end;
1052
1053  currentstructure.refresh;
1054end;
1055
1056procedure TfrmStructures.tvStructureViewMouseDown(Sender: TObject;
1057  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
1058var tn: ttreenode;
1059begin
1060  if button in [mbright, mbleft] then
1061  begin
1062    tn:=tvStructureView.GetNodeAt(x,y);
1063    tvStructureView.Selected:=tn;
1064
1065   
1066  end;
1067end;
1068
1069procedure TfrmStructures.PopupMenu1Popup(Sender: TObject);
1070var
1071  i: integer;
1072  s: Tstructure;
1073  elementnr: integer;
1074begin
1075  for i:=0 to popupmenu1.Items.Count-1 do
1076    popupmenu1.Items[i].Visible:=currentstructure<>nil;
1077
1078
1079  n3.Visible:=(tvStructureView.selected<>nil) and (tvStructureView.selected.Level=1);
1080
1081
1082  if (tvStructureView.selected<>nil) then
1083  begin
1084    s:=tstructure(tvStructureView.Selected.Data);
1085    if (s<>nil) and (s.basestructure>=0) then
1086    begin
1087      Addtoaddresslist1.Visible:=true;
1088      Deleteelement1.Visible:=true;
1089      n2.Visible:=true;
1090      Memorybrowsethisaddress1.Visible:=true;
1091      elementnr:=tvStructureView.Selected.Index;
1092
1093      Memorybrowsepointer1.Visible:=(elementnr>=0) and definedstructures[s.basestructure].structelement[elementnr].pointerto;
1094    end else
1095    begin
1096      Deleteelement1.Visible:=false;
1097      n2.Visible:=false;
1098      Memorybrowsepointer1.Visible:=false;
1099      Addtoaddresslist1.Visible:=false;
1100      Memorybrowsethisaddress1.Visible:=false;
1101
1102      if (s<>nil) and (s.basestructure<0) then
1103      begin
1104        Addelement1.Visible:=false;
1105        ChangeElement1.Visible:=false;
1106      end;
1107       
1108    end;
1109  end;
1110
1111
1112  Recalculateaddress1.visible:=n3.Visible;
1113end;
1114
1115procedure TfrmStructures.Deleteelement1Click(Sender: TObject);
1116var s: tstructure;
1117    elementnr: integer;
1118    i: integer;
1119begin
1120  if currentstructure=nil then exit;
1121
1122  if tvStructureView.Selected<>nil then
1123  begin
1124    elementnr:=tvStructureView.Selected.Index;
1125    s:=tstructure(tvStructureView.Selected.Data);
1126
1127    if s=nil then exit;
1128    if s.basestructure<0 then exit;
1129
1130    if messagedlg('Are you sure you want to delete '+definedstructures[s.basestructure].structelement[elementnr].description+'?', mtconfirmation, [mbyes,mbno], 0) <>mryes then exit;
1131
1132    if tvStructureView.Selected.HasChildren then
1133      tvStructureView.Selected.Collapse(true);
1134
1135    for i:=elementnr to length(definedstructures[s.basestructure].structelement)-2 do
1136      definedstructures[s.basestructure].structelement[i]:=definedstructures[s.basestructure].structelement[i+1];
1137
1138    setlength(definedstructures[s.basestructure].structelement,length(definedstructures[s.basestructure].structelement)-1);
1139    mainform.itemshavechanged:=true;
1140  end;
1141
1142  update(true);
1143end;
1144
1145procedure TfrmStructures.Save1Click(Sender: TObject);
1146var f: tfilestream;
1147    i,j: integer;
1148    x: dword;
1149    cemarker: string;
1150
1151    doc: TXMLDocument;
1152    CheatTable: IXMLNode;
1153    Structures: IXMLNode;
1154begin
1155  if savedialog1.Execute then
1156  begin
1157    if uppercase(ExtractFileExt(savedialog1.FileName))='.CSX' then
1158    begin
1159      //save as xml
1160      doc:=TXMLDocument.Create(application);
1161      try
1162        doc.Options:=doc.Options+[doNodeAutoIndent];
1163        doc.Active:=true;
1164
1165        CheatTable:=doc.AddChild('CheatTable');
1166        if length(definedstructures)>0 then
1167        begin
1168          Structures:=CheatTable.AddChild('Structures');
1169          for i:=0 to length(definedstructures)-1 do
1170            SaveStructToXMLNode(definedstructures[i],Structures);
1171        end;
1172
1173        doc.SaveToFile(savedialog1.filename);
1174      finally
1175        doc.Free;
1176      end;
1177    end;
1178
1179    if uppercase(ExtractFileExt(savedialog1.FileName))='.CES' then
1180    begin
1181      f:=tfilestream.Create(savedialog1.FileName,fmcreate);
1182      try
1183        cemarker:='CHEATENGINE';
1184        f.WriteBuffer(cemarker[1],length(cemarker));
1185
1186        x:=structureversion;
1187        f.writebuffer(x,4);
1188
1189        x:=length(definedstructures);
1190        f.WriteBuffer(x,4);
1191        for i:=0 to length(definedstructures)-1 do
1192        begin
1193          x:=length(definedstructures[i].name);
1194          f.WriteBuffer(x,4); //namelength
1195          if x>0 then f.WriteBuffer(definedstructures[i].name[1],x);
1196
1197          x:=length(definedstructures[i].structelement);
1198          f.WriteBuffer(x,4);
1199
1200          for j:=0 to length(definedstructures[i].structelement)-1 do
1201          begin
1202            x:=length(definedstructures[i].structelement[j].description);
1203            f.WriteBuffer(x,4);
1204            if x>0 then f.Write(definedstructures[i].structelement[j].description[1],x);
1205
1206
1207            f.WriteBuffer(definedstructures[i].structelement[j].pointerto,sizeof(definedstructures[i].structelement[j].pointerto));
1208            f.WriteBuffer(definedstructures[i].structelement[j].pointertoSize,sizeof(definedstructures[i].structelement[j].pointerto));
1209            f.WriteBuffer(definedstructures[i].structelement[j].structurenr,sizeof(definedstructures[i].structelement[j].structurenr));
1210            f.WriteBuffer(definedstructures[i].structelement[j].bytesize,sizeof(definedstructures[i].structelement[j].bytesize));
1211          end;
1212
1213        end;
1214      finally
1215        f.free;
1216      end;
1217    end;   
1218  end;
1219end;
1220
1221procedure TfrmStructures.Open1Click(Sender: TObject);
1222var f: tfilestream;
1223    i,j: integer;
1224    startindex: integer;
1225    x: dword;
1226    cemarker: string;
1227    c: pchar;
1228    s: string;
1229    oldsize: integer;
1230    structures, structure: IXMLNode;
1231    CheatTable: IXMLNode;
1232    doc: TXMLDocument;
1233begin
1234  if opendialog1.Execute then
1235  begin
1236    if (uppercase(ExtractFileExt(OpenDialog1.FileName))='.CSX') or (uppercase(ExtractFileExt(OpenDialog1.FileName))='.XML') then
1237    begin
1238      oldsize:=length(definedstructures);
1239      doc:=TXMLDocument.Create(application);
1240      try
1241        doc.FileName:=opendialog1.filename;
1242        doc.active:=true;
1243        CheatTable:=doc.ChildNodes.FindNode('CheatTable'); //because I made it compatible with a ct
1244        if cheattable<>nil then
1245        begin
1246          Structures:=cheattable.ChildNodes.FindNode('Structures');
1247          if Structures<>nil then
1248          begin
1249
1250            setlength(definedstructures,length(definedstructures)+Structures.ChildNodes.Count);
1251            try
1252              for i:=0 to Structures.ChildNodes.Count-1 do
1253              begin
1254                Structure:=Structures.ChildNodes[i];
1255                LoadStructFromXMLNode(definedstructures[oldsize+i], structure);
1256              end;
1257            except
1258              setlength(definedstructures,oldsize);
1259              raise exception.Create('This is not a valid structure file');
1260            end;
1261          end;
1262        end;
1263        update(true);
1264      finally
1265        doc.free;
1266      end;
1267    end
1268    else
1269    if uppercase(ExtractFileExt(OpenDialog1.FileName))='.CES' then
1270    begin
1271      //old 5.4 CES
1272      f:=tfilestream.Create(opendialog1.FileName,fmopenread);
1273      try
1274        cemarker:='CHEATENGINE';
1275
1276        getmem(c,12);
1277        try
1278          f.ReadBuffer(c^,11);
1279          c[11]:=#0;
1280          s:=c;
1281        finally
1282          freemem(c);
1283        end;
1284
1285        if s<>cemarker then raise exception.Create('This is not a valid structure file');
1286
1287        f.ReadBuffer(x,4);
1288        if x<>structureversion then raise exception.Create('This structure fils was generated with a newer version of Cheat Engine. (That means there''s more than likely a new version so please update....)');
1289
1290        startindex:=length(definedstructures);
1291
1292        f.ReadBuffer(x,4);
1293        setlength(definedstructures,length(definedstructures)+x);
1294
1295        for i:=startindex to length(definedstructures)-1 do
1296        begin
1297          f.readbuffer(x,4);
1298          getmem(c,x+1);
1299          try
1300            f.ReadBuffer(c^,x);
1301            c[x]:=#0;
1302            definedstructures[i].name:=c;
1303          finally
1304            freemem(c);
1305          end;
1306
1307          f.readbuffer(x,4);
1308          setlength(definedstructures[i].structelement,x);
1309
1310          for j:=0 to length(definedstructures[i].structelement)-1 do
1311          begin
1312            f.readbuffer(x,4);
1313            getmem(c,x+1);
1314            try
1315              f.ReadBuffer(c^,x);
1316              c[x]:=#0;
1317              definedstructures[i].structelement[j].description:=c;
1318            finally
1319              freemem(c);
1320            end;
1321
1322            f.ReadBuffer(definedstructures[i].structelement[j].pointerto,sizeof(definedstructures[i].structelement[j].pointerto));
1323            f.ReadBuffer(definedstructures[i].structelement[j].pointertoSize,sizeof(definedstructures[i].structelement[j].pointerto));
1324            f.ReadBuffer(definedstructures[i].structelement[j].structurenr,sizeof(definedstructures[i].structelement[j].structurenr));
1325            f.ReadBuffer(definedstructures[i].structelement[j].bytesize,sizeof(definedstructures[i].structelement[j].bytesize));
1326          end;
1327
1328        end;
1329      finally
1330        f.free;
1331      end;
1332
1333      TMenuItem.Create(self);
1334
1335
1336      update(true);
1337    end else raise exception.create('Unkown file extension');
1338  end;
1339end;
1340
1341procedure TfrmStructures.New1Click(Sender: TObject);
1342begin
1343  if (length(definedstructures)>0) and (messagedlg('Are you sure you want to remove all structures?',mtconfirmation,[mbyes,mbno],0)=mryes) then
1344  begin
1345    currentstructure.Free;
1346    currentstructure:=nil;
1347   
1348    setlength(definedstructures,0);
1349    refreshmenuitems;
1350  end;
1351
1352  Definenewstructure1.Click;
1353end;
1354
1355procedure TfrmStructures.ChangeElement1Click(Sender: TObject);
1356var i,j: integer;
1357    size: dword;
1358    structtype: string;
1359    ts,selectedstructure: tstructure;
1360    selectedelement: integer;
1361    selectednode: ttreenode;
1362begin
1363  if currentstructure=nil then exit;
1364 
1365  if tvStructureView.Selected=tvStructureView.Items.GetFirstNode then
1366  begin
1367    renamestructure1.Click;
1368    exit;
1369  end;
1370
1371
1372  selectednode:=tvStructureView.Selected;
1373  if selectednode=nil then exit;
1374
1375  selectedstructure:=tstructure(selectednode.Data);
1376  if selectedstructure=nil then exit;
1377
1378  selectedelement:=selectednode.Index;
1379
1380  i:=selectedstructure.basestructure;
1381  if i<0 then exit;
1382 
1383  size:=definedstructures[i].structelement[selectedelement].bytesize;
1384
1385  with tfrmstructuresaddelement.create(self) do
1386  begin
1387    //fill the combobox with possible types
1388    //the base types, and defined types
1389    cbtype.Items.AddObject('Byte',pointer(1));
1390    cbtype.Items.AddObject('Byte Signed',pointer(1));
1391    cbtype.Items.AddObject('Byte Hexadecimal',pointer(1));
1392    cbtype.Items.AddObject('2 Bytes',pointer(2));
1393    cbtype.Items.AddObject('2 Bytes Signed',pointer(2));
1394    cbtype.Items.AddObject('2 Bytes Hexadecimal',pointer(2));
1395    cbtype.Items.AddObject('4 Bytes',pointer(4));
1396    cbtype.Items.AddObject('4 Bytes Signed',pointer(4));
1397    cbtype.Items.AddObject('4 Bytes Hexadecimal',pointer(4));
1398    cbtype.Items.AddObject('8 Bytes',pointer(8));
1399    cbtype.Items.AddObject('8 Bytes Hexadecimal',pointer(8));
1400    cbtype.Items.AddObject('Float',pointer(4));
1401    cbtype.Items.AddObject('Double',pointer(8));
1402    cbtype.Items.AddObject('String',pointer(size));
1403    cbtype.Items.AddObject('String Unicode',pointer(size));
1404
1405    cbtype.DropDownCount:=17;
1406
1407    //and add the other defined structures as well
1408    for i:=0 to length(definedstructures)-1 do
1409    begin
1410      size:=0;
1411      for j:=0 to length(definedstructures[i].structelement)-1 do
1412        inc(size,definedstructures[i].structelement[j].bytesize);
1413
1414      cbtype.Items.AddObject(definedstructures[i].name,pointer(size));
1415    end;
1416
1417    if definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr<0 then
1418      cbtype.ItemIndex:=-definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr-1
1419    else
1420      cbtype.itemindex:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr+15;
1421
1422
1423    edtDescription.text:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].description;
1424    cbpointerto.checked:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointerto;
1425    if cbpointerto.Checked then
1426      edtByteSize.Text:=inttostr(definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointertosize);
1427//    else
1428//      edtByteSize.Text
1429
1430    edtOffset.Text:=inttohex(definedstructures[selectedstructure.basestructure].structelement[selectedelement].offset,1);
1431
1432    cbType.OnChange(cbType);
1433
1434    if showmodal=mrok then
1435    begin
1436      definedstructures[selectedstructure.basestructure].structelement[selectedelement].description:=edtDescription.text;
1437      definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointerto:=cbpointerto.checked;
1438      definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointertosize:=bytesize;
1439      definedstructures[selectedstructure.basestructure].structelement[selectedelement].offset:=strtoint('$'+edtOffset.text);
1440
1441      if cbtype.itemindex<=14 then
1442        definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr:=-(cbtype.ItemIndex+1)
1443      else
1444        definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr:=cbtype.ItemIndex-15;
1445
1446      if definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointerto then
1447        definedstructures[selectedstructure.basestructure].structelement[selectedelement].bytesize:=4
1448      else
1449        definedstructures[selectedstructure.basestructure].structelement[selectedelement].bytesize:=bytesize;
1450
1451      if tvStructureView.Selected.HasChildren then
1452      begin
1453        tvStructureView.Selected.DeleteChildren;
1454        freeandnil(selectedstructure.objects[selectedelement].child);
1455      end;
1456
1457      tvStructureView.Selected.Collapse(true);
1458
1459      currentstructure.refresh;
1460
1461      sortstructure(definedstructures[selectedstructure.basestructure]);
1462
1463      self.update(true);
1464      mainform.itemshavechanged:=true;
1465
1466
1467    end;
1468  end;
1469
1470end;
1471
1472procedure TfrmStructures.tvStructureViewDblClick(Sender: TObject);
1473var
1474  selectedstructure: tstructure;
1475  selectednode: ttreenode;
1476  selectedelement: integer;
1477  i: integer;
1478  a: dword;
1479  cursorpos: tpoint;
1480  tvrect: trect;
1481  selectedsection: integer;
1482begin
1483  //find out what part is doubleclicked
1484
1485  //find the position that is clicked
1486  cursorpos:=mouse.CursorPos;
1487  GetWindowRect(TTreeview(sender).Handle, tvrect);
1488
1489  cursorpos.X:=cursorpos.X-tvrect.Left;
1490  cursorpos.Y:=cursorpos.Y-tvrect.Top;
1491  //now find out which section this X belongs to
1492
1493  selectedsection:=headercontrol1.Sections.Count-1; //default pick the last one
1494  for i:=0 to headercontrol1.Sections.Count-1 do
1495    if (cursorpos.X>headercontrol1.Sections[i].Left) and (cursorpos.X<(headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width)) then
1496    begin
1497      selectedsection:=i;
1498      break;
1499    end;
1500
1501  if selectedsection=0 then
1502  begin
1503    ChangeElement1.Click;
1504    exit;
1505  end;
1506
1507 
1508
1509  selectednode:=tvStructureView.Selected;
1510  if selectednode<>nil then
1511  begin
1512    selectedstructure:=tstructure(selectednode.Data);
1513    if (selectedstructure<>nil) and (selectedstructure.basestructure>=0) then
1514    begin
1515      selectedelement:=selectednode.Index;
1516      a:=selectedstructure.addresses[selectedsection-1];
1517      for i:=0 to selectedelement-1 do
1518        inc(a,definedstructures[selectedstructure.basestructure].structelement[i].bytesize);
1519
1520      with Tvaluechangeform.Create(application) do
1521      begin
1522        address:=a;
1523
1524        case definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr of
1525          -1,-2,-3: vtype:=0;
1526          -4,-5,-6: vtype:=1;
1527          -7,-8,-9: vtype:=2;
1528          -10,-11: vtype:=6;
1529          -12: vtype:=4;
1530          -13: vtype:=5;
1531          -14:
1532            begin
1533              slength:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].bytesize;
1534              unicode:=false;
1535              vtype:=7;
1536            end;
1537
1538          -15:
1539            begin
1540              unicode:=true;
1541              slength:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].bytesize div 2;
1542              vtype:=7;
1543            end;
1544
1545          else vtype:=0;
1546        end;
1547
1548
1549        ShowModal;
1550        self.update(true);
1551      end;
1552    end;
1553  end;
1554end;
1555
1556procedure TfrmStructures.Addtoaddresslist1Click(Sender: TObject);
1557var
1558  selectedstructure: tstructure;
1559  selectednode: ttreenode;
1560  selectedelement: integer;
1561  offsets: array of dword;
1562
1563  objectname: string;
1564
1565  snr: integer;
1566  vtype: integer;
1567  vlength: integer;
1568  unicode,ispointer,showashex: boolean;
1569
1570  i: integer;
1571
1572  tvrect: trect;
1573  clickpos: tpoint;
1574  section: integer;
1575begin
1576  if currentstructure=nil then exit;
1577
1578  GetWindowRect(tvStructureView.Handle, tvrect);
1579
1580  clickpos.X:=popupmenu1.PopupPoint.X-tvrect.Left;
1581  clickpos.Y:=popupmenu1.PopupPoint.Y-tvrect.Top;
1582
1583  section:=headercontrol1.Sections.Count-1;
1584  for i:=0 to headercontrol1.Sections.Count-1 do
1585  begin
1586    if (clickpos.x>=headercontrol1.Sections[i].Left)
1587      and
1588       (clickpos.x<headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width) then
1589    begin
1590      //found it
1591      section:=i;
1592      break;
1593    end;
1594  end;
1595
1596  if section>0 then
1597    section:=section-1; //count starts from 1, so decrease
1598
1599 
1600  showashex:=false;
1601  selectednode:=tvStructureView.Selected;
1602  if selectednode<>nil then
1603  begin
1604    selectedstructure:=tstructure(selectednode.Data);
1605
1606    if selectedstructure<>nil then
1607    begin
1608      if selectedstructure.basestructure>=0 then
1609      case definedstructures[selectedstructure.basestructure].structelement[selectednode.Index].structurenr of
1610        -1,-2,-3: vtype:=0;
1611        -4,-5,-6: vtype:=1;
1612        -7,-8,-9: vtype:=2;
1613        -10,-11: vtype:=6;
1614        -12: vtype:=3;
1615        -13: vtype:=4;
1616        -14: begin
1617               vtype:=7;
1618               vlength:=definedstructures[selectedstructure.basestructure].structelement[selectednode.Index].bytesize;
1619               unicode:=false;
1620             end;
1621
1622        -15: begin
1623               vtype:=8;
1624               vlength:=definedstructures[selectedstructure.basestructure].structelement[selectednode.Index].bytesize div 2;
1625               unicode:=true;
1626             end;
1627
1628        0..maxint :
1629             begin
1630               vtype:=2;
1631               showashex:=true;
1632             end;
1633      end else
1634      case selectedstructure.basestructure of
1635        -1,-2,-3: vtype:=0;
1636        -4,-5,-6: vtype:=1;
1637        -7,-8,-9: vtype:=2;
1638        -10,-11: vtype:=6;
1639        -12: vtype:=3;
1640        -13: vtype:=4;
1641        -14: begin
1642               vtype:=7;
1643               vlength:=4;
1644               unicode:=false;
1645             end;
1646
1647        -15: begin
1648               vtype:=8;
1649               vlength:=4;
1650               unicode:=true;
1651             end;
1652
1653        0..maxint : exit;
1654      end
1655
1656    end else exit;
1657
1658    objectname:='';
1659    setlength(offsets,0);
1660    while (selectedstructure<>nil) do
1661    begin
1662      //get the offsets for each structure till you get to the base address
1663      selectedelement:=selectednode.Index;
1664      snr:=selectedstructure.basestructure;
1665
1666      setlength(offsets,length(offsets)+1);
1667      offsets[length(offsets)-1]:=0;
1668
1669      if snr>=0 then
1670      begin
1671        for i:=0 to selectedelement-1 do
1672          inc(offsets[length(offsets)-1],definedstructures[snr].structelement[i].bytesize);
1673      end;
1674
1675      selectednode:=selectednode.Parent;
1676      if selectednode<>nil then
1677        selectedstructure:=tstructure(selectednode.data)
1678      else
1679        break;
1680    end;
1681
1682
1683    //now add it to the list
1684    mainform.addaddress('bla',addresses[section]+offsets[length(offsets)-1],offsets[0],length(offsets)-1,length(offsets)>1,vtype,vlength,0,unicode,showashex);
1685    mainform.itemshavechanged:=true;
1686  end;
1687end;
1688
1689procedure TfrmStructures.Recalculateaddress1Click(Sender: TObject);
1690var a: string;
1691    oldaddress,newaddress: dword;
1692
1693    selectedstructure: tstructure;
1694    selectednode: ttreenode;
1695    selectedelement,snr: integer;
1696    i: integer;
1697    delta: integer;
1698    tvrect: trect;
1699    clickpos: tpoint;
1700    section: integer;
1701begin
1702  if currentstructure=nil then exit;
1703
1704  GetWindowRect(tvStructureView.Handle, tvrect);
1705
1706  clickpos.X:=popupmenu1.PopupPoint.X-tvrect.Left;
1707  clickpos.Y:=popupmenu1.PopupPoint.Y-tvrect.Top;
1708
1709  section:=headercontrol1.Sections.Count-1;
1710  for i:=0 to headercontrol1.Sections.Count-1 do
1711  begin
1712    if (clickpos.x>=headercontrol1.Sections[i].Left)
1713      and
1714       (clickpos.x<headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width) then
1715    begin
1716      //found it
1717      section:=i;
1718      break;
1719    end;
1720  end;
1721
1722  if section>0 then
1723    section:=section-1; //count starts from 1, so decrease
1724
1725     
1726  selectednode:=tvStructureView.Selected;
1727  if selectednode<>nil then
1728  begin
1729    selectedstructure:=tstructure(selectednode.Data);
1730    selectedelement:=selectednode.Index;
1731    snr:=selectedstructure.basestructure;
1732
1733    oldaddress:=addresses[section];
1734
1735    inc(oldaddress,definedstructures[snr].structelement[selectedelement].offset);
1736
1737    a:=inttohex(memorybrowser.memoryaddress,8);
1738    if inputquery('Recalculate base of structure','Give the address of this element',a) then
1739    begin
1740      try
1741        newaddress:=strtoint('$'+a);
1742      except
1743        raise exception.Create('I have no idea what '+a+' means');
1744      end;
1745
1746      delta:=newaddress-oldaddress;
1747      addresses[section]:=addresses[section]+delta;
1748      edits[section].text:=inttohex(addresses[section],8);
1749      update(true);
1750
1751      mainform.itemshavechanged:=true;
1752    end;
1753  end;
1754end;
1755
1756procedure TfrmStructures.FormClose(Sender: TObject;
1757  var Action: TCloseAction);
1758begin
1759  action:=cafree;
1760end;
1761
1762procedure TfrmStructures.HeaderControl1SectionResize(
1763  HeaderControl: THeaderControl; Section: THeaderSection);
1764var x: integer;
1765begin
1766  x:=(HeaderControl1.Sections[HeaderControl1.Sections.Count-1].Left+HeaderControl1.Sections[HeaderControl1.Sections.Count-1].Width);
1767  scrollbox1.HorzScrollBar.Range:=x;
1768
1769  tvStructureView.refresh;
1770  ShowScrollBar(tvStructureView.Handle,SB_HORZ          , false);
1771end;
1772
1773procedure TfrmStructures.FormCreate(Sender: TObject);
1774begin
1775  setlength(groups,1);
1776  setlength(addresses,1);
1777  setlength(edits,1);
1778  edits[0]:=edtAddress;
1779  groups[0]:=0;
1780  lastnewedit:=edtaddress;
1781  edtAddress.OnEnter:=extraenter;
1782
1783  setlength(frmStructures,length(frmStructures)+1);
1784  frmStructures[length(frmStructures)-1]:=self;
1785
1786  UpdateGroupIndex;
1787end;
1788
1789procedure TfrmStructures.ExtraEnter(Sender: TObject);
1790begin
1791  popupmenu2.PopupComponent:=TComponent(sender);
1792end;
1793
1794procedure TfrmStructures.Addextraaddress1Click(Sender: TObject);
1795var x: tedit;
1796    newsection: THeadersection;
1797begin
1798  x:=tedit.Create(self);
1799  with x do
1800  begin
1801    left:=lastnewedit.Left+lastnewedit.Width+16;
1802    top:=lastnewedit.Top;
1803    width:=lastnewedit.Width;
1804    text:=lastnewedit.Text;
1805    parent:=lastnewedit.Parent;
1806
1807    x.PopupMenu:=PopupMenu2;
1808    x.OnEnter:=extraenter;
1809    x.OnChange:=edtAddressChange;
1810    x.Tag:=lastnewedit.Tag+1;
1811
1812  end;
1813
1814  setlength(addresses,length(addresses)+1);
1815  addresses[length(addresses)-1]:=addresses[x.tag-1];
1816
1817  setlength(groups,length(groups)+1);
1818  groups[length(groups)-1]:=0;
1819  UpdateGroupIndex;
1820
1821
1822   
1823  setlength(edits,length(edits)+1);
1824
1825  edits[length(edits)-1]:=x;
1826  lastnewedit:=x;
1827
1828  newsection:=headercontrol1.Sections.Add;
1829  newsection.Text:='Address: Value';
1830  newsection.Width:=200;
1831  newsection.MinWidth:=20;
1832  edtAddressChange(x); 
1833end;
1834
1835procedure TfrmStructures.Remove1Click(Sender: TObject);
1836var x: tedit;
1837    i: integer;
1838begin
1839  x:=TEdit(popupmenu2.PopupComponent);
1840  if x.tag=0 then exit; //can't remove the first one
1841
1842  for i:=x.tag to length(edits)-2 do
1843  begin
1844    groups[i]:=groups[i+1];
1845    edits[i]:=edits[i+1];
1846    edits[i].Left:=edits[i].Left-edits[i].Width-16;
1847    edits[i].Tag:=i;
1848  end;
1849  setlength(edits,length(edits)-1);
1850
1851  lastnewedit:=edits[length(edits)-1];
1852
1853  if currentstructure<>nil then
1854    currentstructure.removeAddress(x.tag);
1855
1856  UpdateGroupIndex;
1857 
1858  x.free;
1859end;
1860
1861procedure TfrmStructures.Undo1Click(Sender: TObject);
1862begin
1863  TEdit(popupmenu2.PopupComponent).Undo;
1864end;
1865
1866procedure TfrmStructures.Cut1Click(Sender: TObject);
1867begin
1868  TEdit(popupmenu2.PopupComponent).CutToClipboard;
1869end;
1870
1871
1872
1873procedure TfrmStructures.Copy1Click(Sender: TObject);
1874begin
1875  TEdit(popupmenu2.PopupComponent).CopyToClipboard;
1876end;
1877
1878procedure TfrmStructures.Paste1Click(Sender: TObject);
1879begin
1880  TEdit(popupmenu2.PopupComponent).PasteFromClipboard;
1881end;
1882
1883procedure TfrmStructures.SelectAll1Click(Sender: TObject);
1884begin
1885  TEdit(popupmenu2.PopupComponent).SelectAll;
1886end;
1887
1888
1889
1890
1891procedure TfrmStructures.tvStructureViewAdvancedCustomDrawItem(
1892  Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState;
1893  Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean);
1894{
1895multigroup usage:
1896If all entries of the same group are the same, mark them green, otherwhise red
1897If the value of another group does not match the value of the first group, mark it red
1898}
1899var 
1900  i,j: integer;
1901  laststart: integer;
1902  textrect: trect;
1903  linerect: trect;
1904  textlinerect: trect;
1905  fulltextline: trect;
1906  totalsections: integer;
1907  sections: array of string;
1908  sections2: array of string;
1909  currentsection: integer;
1910  oldcolor: tcolor;
1911
1912  clip: trect;
1913
1914  currentGroup: integer;
1915  groupmatches: array of boolean;
1916  groupcolors: array of tcolor;
1917  groupvalues: array of string;
1918begin
1919  //looks like it's even called before create is done...
1920  if stage=cdPostPaint then
1921  begin
1922    textrect:=node.DisplayRect(true);
1923    linerect:=node.DisplayRect(false);
1924
1925    fulltextline:=linerect;
1926    fulltextline.Left:=textrect.Left;
1927    oldcolor:=sender.Canvas.Brush.Color;
1928    sender.Canvas.Brush.color:=tvStructureView.color;
1929    sender.Canvas.FillRect(fulltextline); //whipe the original text
1930
1931    if headercontrol1=nil then exit;
1932    totalsections:=headercontrol1.Sections.Count;
1933    setlength(sections,totalsections);
1934    setlength(sections2,totalsections);
1935    currentsection:=0;
1936
1937
1938    setlength(groupvalues,length(groupindex));
1939    setlength(groupcolors,length(groupindex));
1940    setlength(groupmatches,length(groupindex));
1941    for i:=0 to length(groupcolors)-1 do
1942    begin
1943      groupcolors[i]:=clGreen;
1944      groupmatches[i]:=true;
1945    end;
1946
1947    laststart:=1;
1948    //search for seperators (#13)
1949    for i:=1 to length(node.Text) do
1950      if node.Text[i]=#13 then
1951      begin
1952        //found one
1953        sections[currentsection]:=copy(node.text,laststart,i-laststart);
1954        sections2[currentsection]:= copy(sections[currentsection],pos(':',sections[currentsection]),length(sections[currentsection]));
1955        laststart:=i+1;
1956        inc(currentsection);
1957        if (currentsection>=totalsections) then
1958          break; //enough, if there is a rest, it has to be a bug
1959      end;
1960
1961    //go through the values
1962    for i:=1 to length(sections2)-1 do
1963    begin
1964      currentGroup:=internalgrouplist[i-1];
1965
1966      if groupvalues[currentGroup]='' then
1967        groupvalues[currentGroup]:=sections2[i]
1968      else
1969      begin
1970        if groupvalues[currentGroup]<>sections2[i] then
1971        begin
1972          groupcolors[currentGroup]:=clred;
1973          groupmatches[currentGroup]:=false;
1974        end;
1975      end;
1976    end;
1977
1978    for i:=1 to length(groupvalues)-1 do
1979    begin
1980      if (groupmatches[i]) and (groupmatches[i-1]) then //both groups match
1981      begin
1982        if groupvalues[i-1]<>groupvalues[i] then  //but the values don't match with the previous group
1983          groupcolors[i]:=clBlue;
1984      end;
1985    end;
1986
1987
1988    //if laststart=1 then
1989    //  sections[currentsection]:=node.text;
1990
1991    textlinerect.left:=textrect.left;
1992    textlinerect.Top:=linerect.Top;
1993    textlinerect.Right:=headercontrol1.Sections.Items[headercontrol1.Sections.Count-1].Left+sender.Canvas.textwidth(sections[totalsections-1]);
1994    textlinerect.Bottom:=linerect.Bottom;
1995    if textlinerect.right<textlinerect.left then
1996      textlinerect.right:=textlinerect.left;
1997
1998    sender.Canvas.Refresh;
1999    if not (cdsSelected in State) then
2000    begin
2001      sender.Canvas.Brush.Style:=bsSolid;
2002      sender.Canvas.Brush.Color:=tvStructureView.Color;
2003      sender.Canvas.FillRect(textlinerect);
2004//      if different then
2005//        tvStructureView.canvas.Font.Color:=clRed
2006//      else
2007//        tvStructureView.canvas.Font.Color:=clWindowText;
2008
2009    end
2010    else
2011    begin
2012      sender.Canvas.Brush.Style:=bsSolid;
2013      sender.Canvas.Brush.Color:=clHighlight;
2014      sender.Canvas.FillRect(textlinerect);
2015      sender.Canvas.DrawFocusRect(textlinerect);
2016//      if different then
2017//      begin
2018//        tvStructureView.canvas.Font.Color:=clRed;
2019//        tvStructureView.canvas.Font.Style:=[fsBold];
2020//      end
2021//      else
2022//        tvStructureView.canvas.Font.Color:=clHighlightText;
2023
2024    end;
2025
2026    sender.Canvas.Refresh;
2027
2028    clip:=textrect;
2029    clip.Right:=headercontrol1.Sections[0].Left+headercontrol1.Sections[0].Width;
2030    sender.Canvas.TextRect(clip,textrect.Left,textrect.Top,sections[0]);
2031
2032
2033    sender.Canvas.Refresh;
2034    for i:=1 to totalsections-1 do
2035    begin
2036      currentGroup:=internalgrouplist[i-1];
2037      tvStructureView.canvas.Font.Color:=groupcolors[currentgroup];
2038
2039      if (cdsSelected in State) then
2040      begin
2041        case groupcolors[currentgroup] of
2042          clGreen: sender.Canvas.font.Color:=clBlack;
2043          clRed: sender.Canvas.font.Color:=clMaroon;
2044          clBlue: sender.Canvas.font.Color:=clNavy;
2045        end;
2046
2047      end;
2048
2049      clip.Left:=headercontrol1.Sections[i].Left;
2050      clip.Right:=headercontrol1.Sections[i].Left+headercontrol1.Sections[i].Width;
2051      sender.Canvas.TextRect(clip, headercontrol1.Sections[i].Left+(node.Level-1)*tvStructureView.Indent,textrect.Top,sections[i]);
2052      sender.Canvas.Refresh;
2053    end;
2054  end;
2055
2056  DefaultDraw:=true;
2057  ShowScrollBar(tvStructureView.Handle,SB_HORZ          , false);
2058end;
2059
2060procedure TfrmStructures.FormDestroy(Sender: TObject);
2061var i,j: integer;
2062begin
2063  //remove from the list
2064  for i:=0 to length(frmStructures)-1 do
2065    if frmStructures[i]=self then
2066    begin
2067      //found it, now move the rest and shink the array
2068      for j:=i to length(frmStructures)-2 do
2069        frmStructures[j]:=frmStructures[j+1];
2070
2071      setlength(frmStructures,length(frmStructures)-1);
2072      exit;
2073    end;
2074end;
2075
2076procedure TfrmStructures.PopupMenu2Popup(Sender: TObject);
2077var x: tedit;
2078begin
2079  x:=TEdit(popupmenu2.PopupComponent);
2080  Remove1.Visible:=(x<>nil) and (x.tag<>0);
2081  n6.Visible:=remove1.Visible;
2082
2083  setgroup1.Caption:='Change group ('+inttostr(groups[x.tag])+')';
2084end;
2085
2086procedure TfrmStructures.Renamestructure1Click(Sender: TObject);
2087begin
2088  if currentstructure<>nil then
2089  begin
2090    inputquery('Rename structure','Give the new name of this structure',definedstructures[currentstructure.basestructure].name);
2091    update(true);
2092  end;
2093end;
2094
2095procedure TfrmStructures.Deletecurrentstructure1Click(Sender: TObject);
2096var i,j: integer;
2097begin
2098  if MessageDlg('Are you sure you want to delete '+definedstructures[currentstructure.basestructure].name+'?',mtConfirmation, [mbyes,mbno],0)=mryes then
2099  begin
2100    //remove all children that make use of this structnr
2101    //and move all children that point to higher numbered ones
2102    for i:=0 to length(definedstructures)-1 do
2103      for j:=0 to length(definedstructures[i].structelement)-1 do
2104      begin
2105        if definedstructures[i].structelement[j].structurenr=currentstructure.basestructure then
2106          definedstructures[i].structelement[j].structurenr:=-7;
2107
2108        if definedstructures[i].structelement[j].structurenr>currentstructure.basestructure then
2109          dec(definedstructures[i].structelement[j].structurenr);
2110
2111        if definedstructures[i].structelement[j].structurenr=0 then
2112          definedstructures[i].structelement[j].structurenr:=-7;
2113      end;
2114
2115    for i:=currentstructure.basestructure to length(definedstructures)-2 do
2116      definedstructures[i]:=definedstructures[i+1];
2117
2118    setlength(definedstructures,length(definedstructures)-1);
2119    freeandnil(currentstructure);
2120
2121    update(true);
2122  end;
2123end;
2124
2125procedure TfrmStructures.Newwindow1Click(Sender: TObject);
2126begin
2127  with tfrmstructures.create(application) do
2128  begin
2129    edtAddress.Text:=inttohex(memorybrowser.memoryaddress,8);
2130    update(false);
2131    show;
2132  end;
2133end;
2134
2135procedure TfrmStructures.Memorybrowsepointer1Click(Sender: TObject);
2136var
2137  i: integer;
2138  s: Tstructure;
2139  elementnr: integer;
2140  tvrect: trect;
2141  clickpos: tpoint;
2142  section: integer;
2143  address: dword;
2144  x: dword;
2145begin
2146  if (tvStructureView.selected<>nil) then
2147  begin
2148    s:=tstructure(tvStructureView.Selected.Data);
2149    if s=nil then exit;
2150    if s.basestructure<0 then exit;
2151
2152    elementnr:=tvStructureView.Selected.Index;
2153
2154    if (elementnr>=0) then
2155    begin
2156      //find the position that is clicked
2157      GetWindowRect(tvStructureView.Handle, tvrect);
2158
2159      clickpos.X:=popupmenu1.PopupPoint.X-tvrect.Left;
2160      clickpos.Y:=popupmenu1.PopupPoint.Y-tvrect.Top;
2161
2162      section:=headercontrol1.Sections.Count-1;
2163      for i:=0 to headercontrol1.Sections.Count-1 do
2164      begin
2165        if (clickpos.x>=headercontrol1.Sections[i].Left)
2166          and
2167           (clickpos.x<headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width) then
2168        begin
2169          //found it
2170          section:=i;
2171          break;
2172        end;
2173      end;
2174
2175      if section>0 then
2176        section:=section-1; //count starts from 1, so decrease
2177
2178      if readprocessmemory(processhandle, pointer(s.addresses[section]+definedstructures[s.basestructure].structelement[elementnr].offset), @address,4,x) then
2179      begin
2180        memorybrowser.memoryaddress:=address;
2181        memorybrowser.RefreshMB;
2182      end;
2183
2184    end;
2185   // definedstructures[s.basestructure].structelement[elementnr].
2186  end;
2187end;
2188
2189procedure TfrmStructures.Memorybrowsethisaddress1Click(Sender: TObject);
2190var
2191  i: integer;
2192  s: Tstructure;
2193  elementnr: integer;
2194  tvrect: trect;
2195  clickpos: tpoint;
2196  section: integer;
2197  address: dword;
2198  x: dword;
2199begin
2200  if (tvStructureView.selected<>nil) then
2201  begin
2202    s:=tstructure(tvStructureView.Selected.Data);
2203    elementnr:=tvStructureView.Selected.Index;
2204    if s=nil then exit;
2205
2206
2207    if (elementnr>=0) then
2208    begin
2209      //find the position that is clicked
2210      GetWindowRect(tvStructureView.Handle, tvrect);
2211
2212      clickpos.X:=popupmenu1.PopupPoint.X-tvrect.Left;
2213      clickpos.Y:=popupmenu1.PopupPoint.Y-tvrect.Top;
2214
2215      section:=headercontrol1.Sections.Count-1;
2216      for i:=0 to headercontrol1.Sections.Count-1 do
2217      begin
2218        if (clickpos.x>=headercontrol1.Sections[i].Left)
2219          and
2220           (clickpos.x<headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width) then
2221        begin
2222          //found it
2223          section:=i;
2224          break;
2225        end;
2226      end;
2227
2228      if section>0 then
2229        section:=section-1; //count starts from 1, so decrease
2230
2231      if s.basestructure>=0 then
2232      begin
2233        memorybrowser.memoryaddress:=s.addresses[section]+definedstructures[s.basestructure].structelement[elementnr].offset;
2234        memorybrowser.RefreshMB;
2235      end;
2236    end;
2237   // definedstructures[s.basestructure].structelement[elementnr].
2238  end;
2239
2240
2241end;
2242
2243procedure TfrmStructures.automaticallyGuessOffsets(baseOffset: dword; structsize: integer);
2244var
2245  buf: array of byte;
2246  buf2: array of byte;
2247  i,j,t: integer;
2248  t2: TVariableType;
2249  x,y: dword;
2250begin
2251    setlength(buf,structsize);
2252    setlength(buf2,8);
2253    //now read the memory
2254    if readprocessmemory(processhandle,pointer(addresses[0]+baseOffset),@buf[0],structsize,x) then
2255    begin
2256      x:=0;
2257      while x<structsize do
2258      begin
2259        i:=length(definedstructures[length(definedstructures)-1].structelement);
2260        setlength(definedstructures[length(definedstructures)-1].structelement,i+1);
2261        definedstructures[length(definedstructures)-1].structelement[i].offset:=baseoffset+x;
2262        definedstructures[length(definedstructures)-1].structelement[i].pointerto:=false;
2263
2264        //value
2265        //check what type it is
2266        t2:=FindTypeOfData(addresses[0]+baseoffset+x,@buf[x],structsize-x);
2267        if t2=vtPointer then
2268        begin
2269          //pointer
2270
2271
2272          definedstructures[length(definedstructures)-1].structelement[i].pointerto:=true;
2273          definedstructures[length(definedstructures)-1].structelement[i].pointertoSize:=8;
2274          definedstructures[length(definedstructures)-1].structelement[i].bytesize:=4;
2275          definedstructures[length(definedstructures)-1].structelement[i].description:='pointer to ';
2276
2277          if readprocessmemory(processhandle,pointer(pdword(@buf[x])^),@buf2[0],8,y) then
2278          begin
2279            t2:=FindTypeOfData(pdword(@buf[x])^,@buf2[0],8);
2280            t:=convertVariableTypeTostructnr(t2);
2281            definedstructures[length(definedstructures)-1].structelement[i].structurenr:=t;
2282          end
2283          else definedstructures[length(definedstructures)-1].structelement[i].structurenr:=-9;
2284
2285          inc(x,4);
2286          continue;
2287        end;
2288
2289
2290        t:=convertVariableTypeTostructnr(t2);
2291
2292
2293
2294        definedstructures[length(definedstructures)-1].structelement[i].structurenr:=t;
2295
2296
2297
2298        case t of
2299          -1: //byte
2300          begin
2301            definedstructures[length(definedstructures)-1].structelement[i].description:='Byte';
2302            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=1;
2303            inc(x,1);
2304          end;
2305
2306          -4: //word
2307          begin
2308            definedstructures[length(definedstructures)-1].structelement[i].description:='Word';
2309            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=2;
2310            inc(x,2);
2311          end;
2312
2313          -7: //dword
2314          begin
2315            definedstructures[length(definedstructures)-1].structelement[i].description:='Dword';
2316            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=4;
2317            inc(x,4);
2318          end;
2319
2320          -12: //single
2321          begin
2322            definedstructures[length(definedstructures)-1].structelement[i].description:='Float';
2323            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=4;
2324            inc(x,4);
2325          end;
2326
2327          -13: //double
2328          begin
2329            definedstructures[length(definedstructures)-1].structelement[i].description:='Double';
2330            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=8;
2331            inc(x,8);
2332          end;
2333
2334          -14: //string
2335          begin
2336            definedstructures[length(definedstructures)-1].structelement[i].description:='String';
2337
2338            //find out how long this string is:
2339            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=0;
2340            while (x<structsize) and (buf[x]>=32) and (buf[x]<=127) do
2341            begin
2342              inc(x);
2343              inc(definedstructures[length(definedstructures)-1].structelement[i].bytesize);
2344            end;
2345
2346            if (x<structsize-1) then
2347            begin
2348              //add the zero terminator if one exists
2349              if buf[x]=0 then
2350              begin
2351                inc(x);
2352                inc(definedstructures[length(definedstructures)-1].structelement[i].bytesize);
2353              end;
2354            end;
2355          end;
2356
2357
2358        end;
2359      end;
2360
2361    end;
2362end;
2363
2364procedure TfrmStructures.Autoguessoffsets1Click(Sender: TObject);
2365var
2366  sStartOffset: string;
2367  sStructSize: string;
2368  base: TbaseStructure;
2369  startOffset: integer;
2370  structSize: integer;
2371begin
2372  if currentstructure<>nil then
2373  begin
2374    base:=definedstructures[currentstructure.basestructure];
2375    if length(base.structelement)>0 then
2376      sStartOffset:=inttohex(base.structelement[length(base.structelement)-1].offset+base.structelement[length(base.structelement)-1].bytesize,1)
2377    else
2378      sStartOffset:='0';
2379
2380    if not inputquery('Structure define','Please give a starting offset to evaluate',sStartOffset) then exit;
2381    startOffset:=StrToInt('$'+sStartOffset);
2382
2383    sStructSize:='4096';
2384    if not inputquery('Structure define','Please give the size of the block to evaluate',sStructSize) then exit;
2385    structSize:=StrToInt(sStructSize);
2386
2387    automaticallyGuessOffsets(startOffset, structsize);
2388  end;
2389end;
2390
2391procedure  TfrmStructures.UpdateGroupIndex;
2392var i,j: integer;
2393    alreadyIndexed: boolean;
2394begin
2395  setlength(groupindex,0);
2396  setlength(internalgrouplist,length(groups));
2397  for i:=0 to length(groups)-1 do
2398  begin
2399    alreadyIndexed:=false;
2400    for j:=0 to length(groupindex)-1 do
2401    begin
2402      if groupindex[j]=groups[i] then
2403      begin
2404        alreadyIndexed:=true;
2405        internalgrouplist[i]:=j;
2406        break;
2407      end;
2408    end;
2409
2410    if not alreadyIndexed then
2411    begin
2412      setlength(groupindex,length(groupindex)+1);
2413      groupindex[length(groupindex)-1]:=groups[i];
2414      internalgrouplist[i]:=length(groupindex)-1;
2415    end;
2416
2417
2418  end;
2419end;
2420
2421
2422procedure TfrmStructures.Setgroup1Click(Sender: TObject);
2423var
2424  x: tedit;
2425  sgroup: string;
2426begin
2427  x:=TEdit(popupmenu2.PopupComponent);
2428
2429  sgroup:=inttostr(groups[x.Tag]);
2430
2431  InputQuery('Structure definer', 'Which group do you want to set this address to?', sgroup);
2432  groups[x.Tag]:=strtoint(sgroup);
2433
2434  updategroupindex;
2435
2436  tvStructureView.Refresh;
2437end;
2438
2439end.
2440
2441
2442
Note: See TracBrowser for help on using the browser.