root/Cheat Engine/Structuresfrm.pas @ 311

Revision 311, 74.0 kB (checked in by dark_byte, 8 months ago)

mass commit for beta 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
911    if selectednode.index>=0 then
912      edtOffset.text:=inttohex(definedstructures[selectedstructure.basestructure].structelement[selectednode.index].offset-1,1);
913
914
915    if showmodal=mrok then
916    begin
917      if cbtype.ItemIndex=-1 then exit;
918
919      //allocate a spot for the new element
920      i:=length(definedstructures[selectedstructure.basestructure].structelement);
921      setlength(definedstructures[selectedstructure.basestructure].structelement,i+1);
922
923      //move the elements after selectedelement
924      for j:=i-1 downto selectedelement+1 do
925        definedstructures[selectedstructure.basestructure].structelement[j+1]:=definedstructures[selectedstructure.basestructure].structelement[j];
926
927      i:=selectedelement+1;
928
929      definedstructures[selectedstructure.basestructure].structelement[i].pointerto:=cbpointerto.checked;
930      definedstructures[selectedstructure.basestructure].structelement[i].description:=edtDescription.text;
931      base:=strToInt('$'+edtOffset.text);
932
933      if definedstructures[selectedstructure.basestructure].structelement[i].pointerto then
934      begin
935        if cbtype.itemindex<=14 then
936          definedstructures[selectedstructure.basestructure].structelement[i].structurenr:=-(cbtype.ItemIndex+1)
937        else
938          definedstructures[selectedstructure.basestructure].structelement[i].structurenr:=cbtype.ItemIndex-15;
939
940        definedstructures[selectedstructure.basestructure].structelement[i].bytesize:=4;
941        definedstructures[selectedstructure.basestructure].structelement[i].pointertosize:=bytesize;
942      end
943      else
944      begin
945        if cbtype.ItemIndex<=14 then //basetype
946        begin
947          definedstructures[selectedstructure.basestructure].structelement[i].offset:=base;
948          definedstructures[selectedstructure.basestructure].structelement[i].structurenr:=-(cbtype.ItemIndex+1);
949          definedstructures[selectedstructure.basestructure].structelement[i].bytesize:=bytesize;
950        end
951        else
952        begin
953          //not a pointer, but also no base type, so just append the selected structure
954          j:=cbtype.ItemIndex-15;  //j now contains the structure number
955
956          d:=length(definedstructures[j].structelement);
957          setlength(definedstructures[selectedstructure.basestructure].structelement,length(definedstructures[currentstructure.basestructure].structelement)+d-1);
958
959          //move the other elements as well
960          for k:=length(definedstructures[selectedstructure.basestructure].structelement)-1 downto selectedelement+d+1 do
961            definedstructures[selectedstructure.basestructure].structelement[k]:=definedstructures[selectedstructure.basestructure].structelement[k-d+1];
962
963          for k:=0 to length(definedstructures[j].structelement)-1 do
964          begin
965            definedstructures[selectedstructure.basestructure].structelement[i]:=definedstructures[j].structelement[k];
966            definedstructures[selectedstructure.basestructure].structelement[i].description:=edtDescription.text+'_'+definedstructures[j].structelement[k].description;
967            inc(definedstructures[selectedstructure.basestructure].structelement[i].offset, base);
968            inc(i);
969          end;
970        end;
971      end;
972
973      sortStructure(definedstructures[selectedstructure.basestructure]);
974      self.update(true);
975      mainform.itemshavechanged:=true;
976
977      if not tvStructureView.Items.GetFirstNode.Expanded then
978        tvStructureView.Items.GetFirstNode.Expand(false);
979    end;
980  end;
981end;
982
983
984
985procedure TfrmStructures.updatetimerTimer(Sender: TObject);
986begin
987  if currentstructure<>nil then currentstructure.refresh;
988end;
989
990procedure TfrmStructures.tvStructureViewCollapsing(Sender: TObject;
991  Node: TTreeNode; var AllowCollapse: Boolean);
992begin
993  allowcollapse:=not (node=tvStructureView.Items.GetFirstNode);
994end;
995
996procedure TfrmStructures.edtAddressChange(Sender: TObject);
997begin
998  try
999    setaddress((sender as TEdit).tag, symhandler.getAddressFromName((sender as TEdit).text));
1000  except
1001
1002  end;
1003end;
1004
1005procedure TfrmStructures.tvStructureViewExpanding(Sender: TObject;
1006  Node: TTreeNode; var AllowExpansion: Boolean);
1007var s: tstructure;
1008    elementnr: integer;
1009    basestruct: integer;
1010    elementaddress: array of dword;
1011    i,j: integer;
1012begin
1013  AllowExpansion:=true;
1014
1015  s:=tstructure(node.Data);
1016  if s=nil then exit;
1017  if node.getFirstChild<>nil then exit;
1018
1019  elementnr:=node.Index;
1020
1021  //structure and element nr are known, so lets see what it is
1022
1023  basestruct:=s.basestructure;
1024
1025  setlength(elementaddress,length(addresses));
1026  for i:=0 to length(addresses)-1 do
1027  begin
1028    elementaddress[i]:=addresses[i];
1029    for j:=0 to elementnr-2 do
1030      inc(elementaddress[i],definedstructures[basestruct].structelement[j].bytesize);
1031  end;
1032
1033  //make sure it's a pointer
1034  if definedstructures[basestruct].structelement[elementnr].pointerto then
1035  begin
1036    s.objects[elementnr].child:=tstructure.create(tvStructureView,node,elementaddress,definedstructures[basestruct].structelement[elementnr].structurenr);
1037
1038    setlength(s.objects[elementnr].child.addresses,length(currentstructure.addresses));
1039    for i:=0 to length(currentstructure.addresses)-1 do
1040      s.objects[elementnr].child.addresses[i]:=currentstructure.addresses[i];
1041  end;
1042
1043  currentstructure.refresh;
1044end;
1045
1046procedure TfrmStructures.tvStructureViewMouseDown(Sender: TObject;
1047  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
1048var tn: ttreenode;
1049begin
1050  if button in [mbright, mbleft] then
1051  begin
1052    tn:=tvStructureView.GetNodeAt(x,y);
1053    tvStructureView.Selected:=tn;
1054
1055   
1056  end;
1057end;
1058
1059procedure TfrmStructures.PopupMenu1Popup(Sender: TObject);
1060var
1061  i: integer;
1062  s: Tstructure;
1063  elementnr: integer;
1064begin
1065  for i:=0 to popupmenu1.Items.Count-1 do
1066    popupmenu1.Items[i].Visible:=currentstructure<>nil;
1067
1068
1069  n3.Visible:=(tvStructureView.selected<>nil) and (tvStructureView.selected.Level=1);
1070
1071
1072  if (tvStructureView.selected<>nil) then
1073  begin
1074    s:=tstructure(tvStructureView.Selected.Data);
1075    if (s<>nil) and (s.basestructure>=0) then
1076    begin
1077      Addtoaddresslist1.Visible:=true;
1078      Deleteelement1.Visible:=true;
1079      n2.Visible:=true;
1080      Memorybrowsethisaddress1.Visible:=true;
1081      elementnr:=tvStructureView.Selected.Index;
1082
1083      Memorybrowsepointer1.Visible:=(elementnr>=0) and definedstructures[s.basestructure].structelement[elementnr].pointerto;
1084    end else
1085    begin
1086      Deleteelement1.Visible:=false;
1087      n2.Visible:=false;
1088      Memorybrowsepointer1.Visible:=false;
1089      Addtoaddresslist1.Visible:=false;
1090      Memorybrowsethisaddress1.Visible:=false;
1091
1092      if (s<>nil) and (s.basestructure<0) then
1093      begin
1094        Addelement1.Visible:=false;
1095        ChangeElement1.Visible:=false;
1096      end;
1097       
1098    end;
1099  end;
1100
1101
1102  Recalculateaddress1.visible:=n3.Visible;
1103end;
1104
1105procedure TfrmStructures.Deleteelement1Click(Sender: TObject);
1106var s: tstructure;
1107    elementnr: integer;
1108    i: integer;
1109begin
1110  if currentstructure=nil then exit;
1111
1112  if tvStructureView.Selected<>nil then
1113  begin
1114    elementnr:=tvStructureView.Selected.Index;
1115    s:=tstructure(tvStructureView.Selected.Data);
1116
1117    if s=nil then exit;
1118    if s.basestructure<0 then exit;
1119
1120    if messagedlg('Are you sure you want to delete '+definedstructures[s.basestructure].structelement[elementnr].description+'?', mtconfirmation, [mbyes,mbno], 0) <>mryes then exit;
1121
1122    if tvStructureView.Selected.HasChildren then
1123      tvStructureView.Selected.Collapse(true);
1124
1125    for i:=elementnr to length(definedstructures[s.basestructure].structelement)-2 do
1126      definedstructures[s.basestructure].structelement[i]:=definedstructures[s.basestructure].structelement[i+1];
1127
1128    setlength(definedstructures[s.basestructure].structelement,length(definedstructures[s.basestructure].structelement)-1);
1129    mainform.itemshavechanged:=true;
1130  end;
1131
1132  update(true);
1133end;
1134
1135procedure TfrmStructures.Save1Click(Sender: TObject);
1136var f: tfilestream;
1137    i,j: integer;
1138    x: dword;
1139    cemarker: string;
1140
1141    doc: TXMLDocument;
1142    CheatTable: IXMLNode;
1143    Structures: IXMLNode;
1144begin
1145  if savedialog1.Execute then
1146  begin
1147    if uppercase(ExtractFileExt(savedialog1.FileName))='.CSX' then
1148    begin
1149      //save as xml
1150      doc:=TXMLDocument.Create(application);
1151      try
1152        doc.Options:=doc.Options+[doNodeAutoIndent];
1153        doc.Active:=true;
1154
1155        CheatTable:=doc.AddChild('CheatTable');
1156        if length(definedstructures)>0 then
1157        begin
1158          Structures:=CheatTable.AddChild('Structures');
1159          for i:=0 to length(definedstructures)-1 do
1160            SaveStructToXMLNode(definedstructures[i],Structures);
1161        end;
1162
1163        doc.SaveToFile(savedialog1.filename);
1164      finally
1165        doc.Free;
1166      end;
1167    end;
1168
1169    if uppercase(ExtractFileExt(savedialog1.FileName))='.CES' then
1170    begin
1171      f:=tfilestream.Create(savedialog1.FileName,fmcreate);
1172      try
1173        cemarker:='CHEATENGINE';
1174        f.WriteBuffer(cemarker[1],length(cemarker));
1175
1176        x:=structureversion;
1177        f.writebuffer(x,4);
1178
1179        x:=length(definedstructures);
1180        f.WriteBuffer(x,4);
1181        for i:=0 to length(definedstructures)-1 do
1182        begin
1183          x:=length(definedstructures[i].name);
1184          f.WriteBuffer(x,4); //namelength
1185          if x>0 then f.WriteBuffer(definedstructures[i].name[1],x);
1186
1187          x:=length(definedstructures[i].structelement);
1188          f.WriteBuffer(x,4);
1189
1190          for j:=0 to length(definedstructures[i].structelement)-1 do
1191          begin
1192            x:=length(definedstructures[i].structelement[j].description);
1193            f.WriteBuffer(x,4);
1194            if x>0 then f.Write(definedstructures[i].structelement[j].description[1],x);
1195
1196
1197            f.WriteBuffer(definedstructures[i].structelement[j].pointerto,sizeof(definedstructures[i].structelement[j].pointerto));
1198            f.WriteBuffer(definedstructures[i].structelement[j].pointertoSize,sizeof(definedstructures[i].structelement[j].pointerto));
1199            f.WriteBuffer(definedstructures[i].structelement[j].structurenr,sizeof(definedstructures[i].structelement[j].structurenr));
1200            f.WriteBuffer(definedstructures[i].structelement[j].bytesize,sizeof(definedstructures[i].structelement[j].bytesize));
1201          end;
1202
1203        end;
1204      finally
1205        f.free;
1206      end;
1207    end;   
1208  end;
1209end;
1210
1211procedure TfrmStructures.Open1Click(Sender: TObject);
1212var f: tfilestream;
1213    i,j: integer;
1214    startindex: integer;
1215    x: dword;
1216    cemarker: string;
1217    c: pchar;
1218    s: string;
1219    oldsize: integer;
1220    structures, structure: IXMLNode;
1221    CheatTable: IXMLNode;
1222    doc: TXMLDocument;
1223begin
1224  if opendialog1.Execute then
1225  begin
1226    if (uppercase(ExtractFileExt(OpenDialog1.FileName))='.CSX') or (uppercase(ExtractFileExt(OpenDialog1.FileName))='.XML') then
1227    begin
1228      oldsize:=length(definedstructures);
1229      doc:=TXMLDocument.Create(application);
1230      try
1231        doc.FileName:=opendialog1.filename;
1232        doc.active:=true;
1233        CheatTable:=doc.ChildNodes.FindNode('CheatTable'); //because I made it compatible with a ct
1234        if cheattable<>nil then
1235        begin
1236          Structures:=cheattable.ChildNodes.FindNode('Structures');
1237          if Structures<>nil then
1238          begin
1239
1240            setlength(definedstructures,length(definedstructures)+Structures.ChildNodes.Count);
1241            try
1242              for i:=0 to Structures.ChildNodes.Count-1 do
1243              begin
1244                Structure:=Structures.ChildNodes[i];
1245                LoadStructFromXMLNode(definedstructures[oldsize+i], structure);
1246              end;
1247            except
1248              setlength(definedstructures,oldsize);
1249              raise exception.Create('This is not a valid structure file');
1250            end;
1251          end;
1252        end;
1253        update(true);
1254      finally
1255        doc.free;
1256      end;
1257    end
1258    else
1259    if uppercase(ExtractFileExt(OpenDialog1.FileName))='.CES' then
1260    begin
1261      //old 5.4 CES
1262      f:=tfilestream.Create(opendialog1.FileName,fmopenread);
1263      try
1264        cemarker:='CHEATENGINE';
1265
1266        getmem(c,12);
1267        try
1268          f.ReadBuffer(c^,11);
1269          c[11]:=#0;
1270          s:=c;
1271        finally
1272          freemem(c);
1273        end;
1274
1275        if s<>cemarker then raise exception.Create('This is not a valid structure file');
1276
1277        f.ReadBuffer(x,4);
1278        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....)');
1279
1280        startindex:=length(definedstructures);
1281
1282        f.ReadBuffer(x,4);
1283        setlength(definedstructures,length(definedstructures)+x);
1284
1285        for i:=startindex to length(definedstructures)-1 do
1286        begin
1287          f.readbuffer(x,4);
1288          getmem(c,x+1);
1289          try
1290            f.ReadBuffer(c^,x);
1291            c[x]:=#0;
1292            definedstructures[i].name:=c;
1293          finally
1294            freemem(c);
1295          end;
1296
1297          f.readbuffer(x,4);
1298          setlength(definedstructures[i].structelement,x);
1299
1300          for j:=0 to length(definedstructures[i].structelement)-1 do
1301          begin
1302            f.readbuffer(x,4);
1303            getmem(c,x+1);
1304            try
1305              f.ReadBuffer(c^,x);
1306              c[x]:=#0;
1307              definedstructures[i].structelement[j].description:=c;
1308            finally
1309              freemem(c);
1310            end;
1311
1312            f.ReadBuffer(definedstructures[i].structelement[j].pointerto,sizeof(definedstructures[i].structelement[j].pointerto));
1313            f.ReadBuffer(definedstructures[i].structelement[j].pointertoSize,sizeof(definedstructures[i].structelement[j].pointerto));
1314            f.ReadBuffer(definedstructures[i].structelement[j].structurenr,sizeof(definedstructures[i].structelement[j].structurenr));
1315            f.ReadBuffer(definedstructures[i].structelement[j].bytesize,sizeof(definedstructures[i].structelement[j].bytesize));
1316          end;
1317
1318        end;
1319      finally
1320        f.free;
1321      end;
1322
1323      TMenuItem.Create(self);
1324
1325
1326      update(true);
1327    end else raise exception.create('Unkown file extension');
1328  end;
1329end;
1330
1331procedure TfrmStructures.New1Click(Sender: TObject);
1332begin
1333  if (length(definedstructures)>0) and (messagedlg('Are you sure you want to remove all structures?',mtconfirmation,[mbyes,mbno],0)=mryes) then
1334  begin
1335    currentstructure.Free;
1336    currentstructure:=nil;
1337   
1338    setlength(definedstructures,0);
1339    refreshmenuitems;
1340  end;
1341
1342  Definenewstructure1.Click;
1343end;
1344
1345procedure TfrmStructures.ChangeElement1Click(Sender: TObject);
1346var i,j: integer;
1347    size: dword;
1348    structtype: string;
1349    selectedstructure: tstructure;
1350    selectedelement: integer;
1351    selectednode: ttreenode;
1352begin
1353  if currentstructure=nil then exit;
1354 
1355  if tvStructureView.Selected=tvStructureView.Items.GetFirstNode then
1356  begin
1357    renamestructure1.Click;
1358    exit;
1359  end;
1360
1361
1362  selectednode:=tvStructureView.Selected;
1363  if selectednode=nil then exit;
1364
1365  selectedstructure:=tstructure(selectednode.Data);
1366  if selectedstructure=nil then exit;
1367
1368  selectedelement:=selectednode.Index;
1369
1370  i:=selectedstructure.basestructure;
1371  if i<0 then exit;
1372 
1373  size:=definedstructures[i].structelement[selectedelement].bytesize;
1374
1375  with tfrmstructuresaddelement.create(self) do
1376  begin
1377    //fill the combobox with possible types
1378    //the base types, and defined types
1379    cbtype.Items.AddObject('Byte',pointer(1));
1380    cbtype.Items.AddObject('Byte Signed',pointer(1));
1381    cbtype.Items.AddObject('Byte Hexadecimal',pointer(1));
1382    cbtype.Items.AddObject('2 Bytes',pointer(2));
1383    cbtype.Items.AddObject('2 Bytes Signed',pointer(2));
1384    cbtype.Items.AddObject('2 Bytes Hexadecimal',pointer(2));
1385    cbtype.Items.AddObject('4 Bytes',pointer(4));
1386    cbtype.Items.AddObject('4 Bytes Signed',pointer(4));
1387    cbtype.Items.AddObject('4 Bytes Hexadecimal',pointer(4));
1388    cbtype.Items.AddObject('8 Bytes',pointer(8));
1389    cbtype.Items.AddObject('8 Bytes Hexadecimal',pointer(8));
1390    cbtype.Items.AddObject('Float',pointer(4));
1391    cbtype.Items.AddObject('Double',pointer(8));
1392    cbtype.Items.AddObject('String',pointer(size));
1393    cbtype.Items.AddObject('String Unicode',pointer(size));
1394
1395    cbtype.DropDownCount:=17;
1396
1397    //and add the other defined structures as well
1398    for i:=0 to length(definedstructures)-1 do
1399    begin
1400      size:=0;
1401      for j:=0 to length(definedstructures[i].structelement)-1 do
1402        inc(size,definedstructures[i].structelement[j].bytesize);
1403
1404      cbtype.Items.AddObject(definedstructures[i].name,pointer(size));
1405    end;
1406
1407    if definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr<0 then
1408      cbtype.ItemIndex:=-definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr-1
1409    else
1410      cbtype.itemindex:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr+15;
1411
1412
1413    edtDescription.text:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].description;
1414    cbpointerto.checked:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointerto;
1415    if cbpointerto.Checked then
1416      edtByteSize.Text:=inttostr(definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointertosize);
1417//    else
1418//      edtByteSize.Text
1419
1420    edtOffset.Text:=inttohex(definedstructures[selectedstructure.basestructure].structelement[selectedelement].offset,1);
1421
1422    cbType.OnChange(cbType);
1423
1424    if showmodal=mrok then
1425    begin
1426      definedstructures[selectedstructure.basestructure].structelement[selectedelement].description:=edtDescription.text;
1427      definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointerto:=cbpointerto.checked;
1428      definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointertosize:=bytesize;
1429      definedstructures[selectedstructure.basestructure].structelement[selectedelement].offset:=strtoint('$'+edtOffset.text);
1430
1431      if cbtype.itemindex<=14 then
1432        definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr:=-(cbtype.ItemIndex+1)
1433      else
1434        definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr:=cbtype.ItemIndex-15;
1435
1436      if definedstructures[selectedstructure.basestructure].structelement[selectedelement].pointerto then
1437        definedstructures[selectedstructure.basestructure].structelement[selectedelement].bytesize:=4
1438      else
1439        definedstructures[selectedstructure.basestructure].structelement[selectedelement].bytesize:=bytesize;
1440
1441      if tvStructureView.Selected.HasChildren then
1442        tvStructureView.Selected.DeleteChildren;
1443
1444      sortstructure(definedstructures[selectedstructure.basestructure]);
1445
1446      self.update(true);
1447      mainform.itemshavechanged:=true;
1448
1449
1450    end;
1451  end;
1452
1453end;
1454
1455procedure TfrmStructures.tvStructureViewDblClick(Sender: TObject);
1456var
1457  selectedstructure: tstructure;
1458  selectednode: ttreenode;
1459  selectedelement: integer;
1460  i: integer;
1461  a: dword;
1462  cursorpos: tpoint;
1463  tvrect: trect;
1464  selectedsection: integer;
1465begin
1466  //find out what part is doubleclicked
1467
1468  //find the position that is clicked
1469  cursorpos:=mouse.CursorPos;
1470  GetWindowRect(TTreeview(sender).Handle, tvrect);
1471
1472  cursorpos.X:=cursorpos.X-tvrect.Left;
1473  cursorpos.Y:=cursorpos.Y-tvrect.Top;
1474  //now find out which section this X belongs to
1475
1476  selectedsection:=headercontrol1.Sections.Count-1; //default pick the last one
1477  for i:=0 to headercontrol1.Sections.Count-1 do
1478    if (cursorpos.X>headercontrol1.Sections[i].Left) and (cursorpos.X<(headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width)) then
1479    begin
1480      selectedsection:=i;
1481      break;
1482    end;
1483
1484  if selectedsection=0 then
1485  begin
1486    ChangeElement1.Click;
1487    exit;
1488  end;
1489
1490 
1491
1492  selectednode:=tvStructureView.Selected;
1493  if selectednode<>nil then
1494  begin
1495    selectedstructure:=tstructure(selectednode.Data);
1496    if (selectedstructure<>nil) and (selectedstructure.basestructure>=0) then
1497    begin
1498      selectedelement:=selectednode.Index;
1499      a:=selectedstructure.addresses[selectedsection-1];
1500      for i:=0 to selectedelement-1 do
1501        inc(a,definedstructures[selectedstructure.basestructure].structelement[i].bytesize);
1502
1503      with Tvaluechangeform.Create(application) do
1504      begin
1505        address:=a;
1506
1507        case definedstructures[selectedstructure.basestructure].structelement[selectedelement].structurenr of
1508          -1,-2,-3: vtype:=0;
1509          -4,-5,-6: vtype:=1;
1510          -7,-8,-9: vtype:=2;
1511          -10,-11: vtype:=6;
1512          -12: vtype:=4;
1513          -13: vtype:=5;
1514          -14:
1515            begin
1516              slength:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].bytesize;
1517              unicode:=false;
1518              vtype:=7;
1519            end;
1520
1521          -15:
1522            begin
1523              unicode:=true;
1524              slength:=definedstructures[selectedstructure.basestructure].structelement[selectedelement].bytesize div 2;
1525              vtype:=7;
1526            end;
1527
1528          else vtype:=0;
1529        end;
1530
1531
1532        ShowModal;
1533        self.update(true);
1534      end;
1535    end;
1536  end;
1537end;
1538
1539procedure TfrmStructures.Addtoaddresslist1Click(Sender: TObject);
1540var
1541  selectedstructure: tstructure;
1542  selectednode: ttreenode;
1543  selectedelement: integer;
1544  offsets: array of dword;
1545
1546  objectname: string;
1547
1548  snr: integer;
1549  vtype: integer;
1550  vlength: integer;
1551  unicode,ispointer,showashex: boolean;
1552
1553  i: integer;
1554
1555  tvrect: trect;
1556  clickpos: tpoint;
1557  section: integer;
1558begin
1559  if currentstructure=nil then exit;
1560
1561  GetWindowRect(tvStructureView.Handle, tvrect);
1562
1563  clickpos.X:=popupmenu1.PopupPoint.X-tvrect.Left;
1564  clickpos.Y:=popupmenu1.PopupPoint.Y-tvrect.Top;
1565
1566  section:=headercontrol1.Sections.Count-1;
1567  for i:=0 to headercontrol1.Sections.Count-1 do
1568  begin
1569    if (clickpos.x>=headercontrol1.Sections[i].Left)
1570      and
1571       (clickpos.x<headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width) then
1572    begin
1573      //found it
1574      section:=i;
1575      break;
1576    end;
1577  end;
1578
1579  if section>0 then
1580    section:=section-1; //count starts from 1, so decrease
1581
1582 
1583  showashex:=false;
1584  selectednode:=tvStructureView.Selected;
1585  if selectednode<>nil then
1586  begin
1587    selectedstructure:=tstructure(selectednode.Data);
1588
1589    if selectedstructure<>nil then
1590    begin
1591      if selectedstructure.basestructure>=0 then
1592      case definedstructures[selectedstructure.basestructure].structelement[selectednode.Index].structurenr of
1593        -1,-2,-3: vtype:=0;
1594        -4,-5,-6: vtype:=1;
1595        -7,-8,-9: vtype:=2;
1596        -10,-11: vtype:=6;
1597        -12: vtype:=3;
1598        -13: vtype:=4;
1599        -14: begin
1600               vtype:=7;
1601               vlength:=definedstructures[selectedstructure.basestructure].structelement[selectednode.Index].bytesize;
1602               unicode:=false;
1603             end;
1604
1605        -15: begin
1606               vtype:=8;
1607               vlength:=definedstructures[selectedstructure.basestructure].structelement[selectednode.Index].bytesize div 2;
1608               unicode:=true;
1609             end;
1610
1611        0..maxint :
1612             begin
1613               vtype:=2;
1614               showashex:=true;
1615             end;
1616      end else
1617      case selectedstructure.basestructure of
1618        -1,-2,-3: vtype:=0;
1619        -4,-5,-6: vtype:=1;
1620        -7,-8,-9: vtype:=2;
1621        -10,-11: vtype:=6;
1622        -12: vtype:=3;
1623        -13: vtype:=4;
1624        -14: begin
1625               vtype:=7;
1626               vlength:=4;
1627               unicode:=false;
1628             end;
1629
1630        -15: begin
1631               vtype:=8;
1632               vlength:=4;
1633               unicode:=true;
1634             end;
1635
1636        0..maxint : exit;
1637      end
1638
1639    end else exit;
1640
1641    objectname:='';
1642    setlength(offsets,0);
1643    while (selectedstructure<>nil) do
1644    begin
1645      //get the offsets for each structure till you get to the base address
1646      selectedelement:=selectednode.Index;
1647      snr:=selectedstructure.basestructure;
1648
1649      setlength(offsets,length(offsets)+1);
1650      offsets[length(offsets)-1]:=0;
1651
1652      if snr>=0 then
1653      begin
1654        for i:=0 to selectedelement-1 do
1655          inc(offsets[length(offsets)-1],definedstructures[snr].structelement[i].bytesize);
1656      end;
1657
1658      selectednode:=selectednode.Parent;
1659      if selectednode<>nil then
1660        selectedstructure:=tstructure(selectednode.data)
1661      else
1662        break;
1663    end;
1664
1665
1666    //now add it to the list
1667    mainform.addaddress('bla',addresses[section]+offsets[length(offsets)-1],offsets[0],length(offsets)-1,length(offsets)>1,vtype,vlength,0,unicode,showashex);
1668    mainform.itemshavechanged:=true;
1669  end;
1670end;
1671
1672procedure TfrmStructures.Recalculateaddress1Click(Sender: TObject);
1673var a: string;
1674    oldaddress,newaddress: dword;
1675
1676    selectedstructure: tstructure;
1677    selectednode: ttreenode;
1678    selectedelement,snr: integer;
1679    i: integer;
1680    delta: integer;
1681    tvrect: trect;
1682    clickpos: tpoint;
1683    section: integer;
1684begin
1685  if currentstructure=nil then exit;
1686
1687  GetWindowRect(tvStructureView.Handle, tvrect);
1688
1689  clickpos.X:=popupmenu1.PopupPoint.X-tvrect.Left;
1690  clickpos.Y:=popupmenu1.PopupPoint.Y-tvrect.Top;
1691
1692  section:=headercontrol1.Sections.Count-1;
1693  for i:=0 to headercontrol1.Sections.Count-1 do
1694  begin
1695    if (clickpos.x>=headercontrol1.Sections[i].Left)
1696      and
1697       (clickpos.x<headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width) then
1698    begin
1699      //found it
1700      section:=i;
1701      break;
1702    end;
1703  end;
1704
1705  if section>0 then
1706    section:=section-1; //count starts from 1, so decrease
1707
1708     
1709  selectednode:=tvStructureView.Selected;
1710  if selectednode<>nil then
1711  begin
1712    selectedstructure:=tstructure(selectednode.Data);
1713    selectedelement:=selectednode.Index;
1714    snr:=selectedstructure.basestructure;
1715
1716    oldaddress:=addresses[section];
1717
1718    inc(oldaddress,definedstructures[snr].structelement[selectedelement].offset);
1719
1720    a:=inttohex(memorybrowser.memoryaddress,8);
1721    if inputquery('Recalculate base of structure','Give the address of this element',a) then
1722    begin
1723      try
1724        newaddress:=strtoint('$'+a);
1725      except
1726        raise exception.Create('I have no idea what '+a+' means');
1727      end;
1728
1729      delta:=newaddress-oldaddress;
1730      addresses[section]:=addresses[section]+delta;
1731      edits[section].text:=inttohex(addresses[section],8);
1732      update(true);
1733
1734      mainform.itemshavechanged:=true;
1735    end;
1736  end;
1737end;
1738
1739procedure TfrmStructures.FormClose(Sender: TObject;
1740  var Action: TCloseAction);
1741begin
1742  action:=cafree;
1743end;
1744
1745procedure TfrmStructures.HeaderControl1SectionResize(
1746  HeaderControl: THeaderControl; Section: THeaderSection);
1747var x: integer;
1748begin
1749  x:=(HeaderControl1.Sections[HeaderControl1.Sections.Count-1].Left+HeaderControl1.Sections[HeaderControl1.Sections.Count-1].Width);
1750  scrollbox1.HorzScrollBar.Range:=x;
1751
1752  tvStructureView.refresh;
1753  ShowScrollBar(tvStructureView.Handle,SB_HORZ          , false);
1754end;
1755
1756procedure TfrmStructures.FormCreate(Sender: TObject);
1757begin
1758  setlength(groups,1);
1759  setlength(addresses,1);
1760  setlength(edits,1);
1761  edits[0]:=edtAddress;
1762  groups[0]:=0;
1763  lastnewedit:=edtaddress;
1764  edtAddress.OnEnter:=extraenter;
1765
1766  setlength(frmStructures,length(frmStructures)+1);
1767  frmStructures[length(frmStructures)-1]:=self;
1768
1769  UpdateGroupIndex;
1770end;
1771
1772procedure TfrmStructures.ExtraEnter(Sender: TObject);
1773begin
1774  popupmenu2.PopupComponent:=TComponent(sender);
1775end;
1776
1777procedure TfrmStructures.Addextraaddress1Click(Sender: TObject);
1778var x: tedit;
1779    newsection: THeadersection;
1780begin
1781  x:=tedit.Create(self);
1782  with x do
1783  begin
1784    left:=lastnewedit.Left+lastnewedit.Width+16;
1785    top:=lastnewedit.Top;
1786    width:=lastnewedit.Width;
1787    text:=lastnewedit.Text;
1788    parent:=lastnewedit.Parent;
1789
1790    x.PopupMenu:=PopupMenu2;
1791    x.OnEnter:=extraenter;
1792    x.OnChange:=edtAddressChange;
1793    x.Tag:=lastnewedit.Tag+1;
1794
1795  end;
1796
1797  setlength(addresses,length(addresses)+1);
1798  addresses[length(addresses)-1]:=addresses[x.tag-1];
1799
1800  setlength(groups,length(groups)+1);
1801  groups[length(groups)-1]:=0;
1802  UpdateGroupIndex;
1803
1804
1805   
1806  setlength(edits,length(edits)+1);
1807
1808  edits[length(edits)-1]:=x;
1809  lastnewedit:=x;
1810
1811  newsection:=headercontrol1.Sections.Add;
1812  newsection.Text:='Address: Value';
1813  newsection.Width:=200;
1814  newsection.MinWidth:=20;
1815  edtAddressChange(x); 
1816end;
1817
1818procedure TfrmStructures.Remove1Click(Sender: TObject);
1819var x: tedit;
1820    i: integer;
1821begin
1822  x:=TEdit(popupmenu2.PopupComponent);
1823  if x.tag=0 then exit; //can't remove the first one
1824
1825  for i:=x.tag to length(edits)-2 do
1826  begin
1827    groups[i]:=groups[i+1];
1828    edits[i]:=edits[i+1];
1829    edits[i].Left:=edits[i].Left-edits[i].Width-16;
1830    edits[i].Tag:=i;
1831  end;
1832  setlength(edits,length(edits)-1);
1833
1834  lastnewedit:=edits[length(edits)-1];
1835
1836  if currentstructure<>nil then
1837    currentstructure.removeAddress(x.tag);
1838
1839  UpdateGroupIndex;
1840 
1841  x.free;
1842end;
1843
1844procedure TfrmStructures.Undo1Click(Sender: TObject);
1845begin
1846  TEdit(popupmenu2.PopupComponent).Undo;
1847end;
1848
1849procedure TfrmStructures.Cut1Click(Sender: TObject);
1850begin
1851  TEdit(popupmenu2.PopupComponent).CutToClipboard;
1852end;
1853
1854
1855
1856procedure TfrmStructures.Copy1Click(Sender: TObject);
1857begin
1858  TEdit(popupmenu2.PopupComponent).CopyToClipboard;
1859end;
1860
1861procedure TfrmStructures.Paste1Click(Sender: TObject);
1862begin
1863  TEdit(popupmenu2.PopupComponent).PasteFromClipboard;
1864end;
1865
1866procedure TfrmStructures.SelectAll1Click(Sender: TObject);
1867begin
1868  TEdit(popupmenu2.PopupComponent).SelectAll;
1869end;
1870
1871
1872
1873
1874procedure TfrmStructures.tvStructureViewAdvancedCustomDrawItem(
1875  Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState;
1876  Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean);
1877{
1878multigroup usage:
1879If all entries of the same group are the same, mark them green, otherwhise red
1880If the value of another group does not match the value of the first group, mark it red
1881}
1882var 
1883  i,j: integer;
1884  laststart: integer;
1885  textrect: trect;
1886  linerect: trect;
1887  textlinerect: trect;
1888  fulltextline: trect;
1889  totalsections: integer;
1890  sections: array of string;
1891  sections2: array of string;
1892  currentsection: integer;
1893  oldcolor: tcolor;
1894
1895  clip: trect;
1896
1897  currentGroup: integer;
1898  groupmatches: array of boolean;
1899  groupcolors: array of tcolor;
1900  groupvalues: array of string;
1901begin
1902  //looks like it's even called before create is done...
1903  if stage=cdPostPaint then
1904  begin
1905    textrect:=node.DisplayRect(true);
1906    linerect:=node.DisplayRect(false);
1907
1908    fulltextline:=linerect;
1909    fulltextline.Left:=textrect.Left;
1910    oldcolor:=sender.Canvas.Brush.Color;
1911    sender.Canvas.Brush.color:=tvStructureView.color;
1912    sender.Canvas.FillRect(fulltextline); //whipe the original text
1913
1914    if headercontrol1=nil then exit;
1915    totalsections:=headercontrol1.Sections.Count;
1916    setlength(sections,totalsections);
1917    setlength(sections2,totalsections);
1918    currentsection:=0;
1919
1920
1921    setlength(groupvalues,length(groupindex));
1922    setlength(groupcolors,length(groupindex));
1923    setlength(groupmatches,length(groupindex));
1924    for i:=0 to length(groupcolors)-1 do
1925    begin
1926      groupcolors[i]:=clGreen;
1927      groupmatches[i]:=true;
1928    end;
1929
1930    laststart:=1;
1931    //search for seperators (#13)
1932    for i:=1 to length(node.Text) do
1933      if node.Text[i]=#13 then
1934      begin
1935        //found one
1936        sections[currentsection]:=copy(node.text,laststart,i-laststart);
1937        sections2[currentsection]:= copy(sections[currentsection],pos(':',sections[currentsection]),length(sections[currentsection]));
1938        laststart:=i+1;
1939        inc(currentsection);
1940        if (currentsection>=totalsections) then
1941          break; //enough, if there is a rest, it has to be a bug
1942      end;
1943
1944    //go through the values
1945    for i:=1 to length(sections2)-1 do
1946    begin
1947      currentGroup:=internalgrouplist[i-1];
1948
1949      if groupvalues[currentGroup]='' then
1950        groupvalues[currentGroup]:=sections2[i]
1951      else
1952      begin
1953        if groupvalues[currentGroup]<>sections2[i] then
1954        begin
1955          groupcolors[currentGroup]:=clred;
1956          groupmatches[currentGroup]:=false;
1957        end;
1958      end;
1959    end;
1960
1961    for i:=1 to length(groupvalues)-1 do
1962    begin
1963      if (groupmatches[i]) and (groupmatches[i-1]) then //both groups match
1964      begin
1965        if groupvalues[i-1]<>groupvalues[i] then  //but the values don't match with the previous group
1966          groupcolors[i]:=clBlue;
1967      end;
1968    end;
1969
1970
1971    //if laststart=1 then
1972    //  sections[currentsection]:=node.text;
1973
1974    textlinerect.left:=textrect.left;
1975    textlinerect.Top:=linerect.Top;
1976    textlinerect.Right:=headercontrol1.Sections.Items[headercontrol1.Sections.Count-1].Left+sender.Canvas.textwidth(sections[totalsections-1]);
1977    textlinerect.Bottom:=linerect.Bottom;
1978    if textlinerect.right<textlinerect.left then
1979      textlinerect.right:=textlinerect.left;
1980
1981    sender.Canvas.Refresh;
1982    if not (cdsSelected in State) then
1983    begin
1984      sender.Canvas.Brush.Style:=bsSolid;
1985      sender.Canvas.Brush.Color:=tvStructureView.Color;
1986      sender.Canvas.FillRect(textlinerect);
1987//      if different then
1988//        tvStructureView.canvas.Font.Color:=clRed
1989//      else
1990//        tvStructureView.canvas.Font.Color:=clWindowText;
1991
1992    end
1993    else
1994    begin
1995      sender.Canvas.Brush.Style:=bsSolid;
1996      sender.Canvas.Brush.Color:=clHighlight;   
1997      sender.Canvas.FillRect(textlinerect);
1998      sender.Canvas.DrawFocusRect(textlinerect);
1999//      if different then
2000//      begin
2001//        tvStructureView.canvas.Font.Color:=clRed;
2002//        tvStructureView.canvas.Font.Style:=[fsBold];
2003//      end
2004//      else
2005//        tvStructureView.canvas.Font.Color:=clHighlightText;
2006
2007    end;
2008
2009    sender.Canvas.Refresh;
2010
2011    clip:=textrect;
2012    clip.Right:=headercontrol1.Sections[0].Left+headercontrol1.Sections[0].Width;
2013    sender.Canvas.TextRect(clip,textrect.Left,textrect.Top,sections[0]);
2014
2015
2016    sender.Canvas.Refresh;
2017    for i:=1 to totalsections-1 do
2018    begin
2019      currentGroup:=internalgrouplist[i-1];
2020      tvStructureView.canvas.Font.Color:=groupcolors[currentgroup];
2021
2022      clip.Left:=headercontrol1.Sections[i].Left;
2023      clip.Right:=headercontrol1.Sections[i].Left+headercontrol1.Sections[i].Width;
2024      sender.Canvas.TextRect(clip, headercontrol1.Sections[i].Left+(node.Level-1)*tvStructureView.Indent,textrect.Top,sections[i]);
2025      sender.Canvas.Refresh;
2026    end;
2027  end;
2028
2029  DefaultDraw:=true;
2030  ShowScrollBar(tvStructureView.Handle,SB_HORZ          , false);
2031end;
2032
2033procedure TfrmStructures.FormDestroy(Sender: TObject);
2034var i,j: integer;
2035begin
2036  //remove from the list
2037  for i:=0 to length(frmStructures)-1 do
2038    if frmStructures[i]=self then
2039    begin
2040      //found it, now move the rest and shink the array
2041      for j:=i to length(frmStructures)-2 do
2042        frmStructures[j]:=frmStructures[j+1];
2043
2044      setlength(frmStructures,length(frmStructures)-1);
2045      exit;
2046    end;
2047end;
2048
2049procedure TfrmStructures.PopupMenu2Popup(Sender: TObject);
2050var x: tedit;
2051begin
2052  x:=TEdit(popupmenu2.PopupComponent);
2053  Remove1.Visible:=(x<>nil) and (x.tag<>0);
2054  n6.Visible:=remove1.Visible;
2055
2056  if groups[x.Tag]<>0 then
2057    setgroup1.Caption:='Change group ('+inttostr(groups[x.tag])+')'
2058  else
2059    setgroup1.Caption:='Set group';
2060end;
2061
2062procedure TfrmStructures.Renamestructure1Click(Sender: TObject);
2063begin
2064  if currentstructure<>nil then
2065  begin
2066    inputquery('Rename structure','Give the new name of this structure',definedstructures[currentstructure.basestructure].name);
2067    update(true);
2068  end;
2069end;
2070
2071procedure TfrmStructures.Deletecurrentstructure1Click(Sender: TObject);
2072var i,j: integer;
2073begin
2074  if MessageDlg('Are you sure you want to delete '+definedstructures[currentstructure.basestructure].name+'?',mtConfirmation, [mbyes,mbno],0)=mryes then
2075  begin
2076    //remove all children that make use of this structnr
2077    //and move all children that point to higher numbered ones
2078    for i:=0 to length(definedstructures)-1 do
2079      for j:=0 to length(definedstructures[i].structelement)-1 do
2080      begin
2081        if definedstructures[i].structelement[j].structurenr=currentstructure.basestructure then
2082          definedstructures[i].structelement[j].structurenr:=-7;
2083
2084        if definedstructures[i].structelement[j].structurenr>currentstructure.basestructure then
2085          dec(definedstructures[i].structelement[j].structurenr);
2086
2087        if definedstructures[i].structelement[j].structurenr=0 then
2088          definedstructures[i].structelement[j].structurenr:=-7;
2089      end;
2090
2091    for i:=currentstructure.basestructure to length(definedstructures)-2 do
2092      definedstructures[i]:=definedstructures[i+1];
2093
2094    setlength(definedstructures,length(definedstructures)-1);
2095    freeandnil(currentstructure);
2096
2097    update(true);
2098  end;
2099end;
2100
2101procedure TfrmStructures.Newwindow1Click(Sender: TObject);
2102begin
2103  with tfrmstructures.create(application) do
2104  begin
2105    edtAddress.Text:=inttohex(memorybrowser.memoryaddress,8);
2106    update(false);
2107    show;
2108  end;
2109end;
2110
2111procedure TfrmStructures.Memorybrowsepointer1Click(Sender: TObject);
2112var
2113  i: integer;
2114  s: Tstructure;
2115  elementnr: integer;
2116  tvrect: trect;
2117  clickpos: tpoint;
2118  section: integer;
2119  address: dword;
2120  x: dword;
2121begin
2122  if (tvStructureView.selected<>nil) then
2123  begin
2124    s:=tstructure(tvStructureView.Selected.Data);
2125    if s=nil then exit;
2126
2127    elementnr:=tvStructureView.Selected.Index;
2128
2129    if (elementnr>=0) then
2130    begin
2131      //find the position that is clicked
2132      GetWindowRect(tvStructureView.Handle, tvrect);
2133
2134      clickpos.X:=popupmenu1.PopupPoint.X-tvrect.Left;
2135      clickpos.Y:=popupmenu1.PopupPoint.Y-tvrect.Top;
2136
2137      section:=headercontrol1.Sections.Count-1;
2138      for i:=0 to headercontrol1.Sections.Count-1 do
2139      begin
2140        if (clickpos.x>=headercontrol1.Sections[i].Left)
2141          and
2142           (clickpos.x<headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width) then
2143        begin
2144          //found it
2145          section:=i;
2146          break;
2147        end;
2148      end;
2149
2150      if section>0 then
2151        section:=section-1; //count starts from 1, so decrease
2152
2153      if readprocessmemory(processhandle, pointer(s.addresses[section]+definedstructures[s.basestructure].structelement[elementnr].offset), @address,4,x) then
2154      begin
2155        memorybrowser.memoryaddress:=address;
2156        memorybrowser.RefreshMB;
2157      end;
2158
2159    end;
2160   // definedstructures[s.basestructure].structelement[elementnr].
2161  end;
2162end;
2163
2164procedure TfrmStructures.Memorybrowsethisaddress1Click(Sender: TObject);
2165var
2166  i: integer;
2167  s: Tstructure;
2168  elementnr: integer;
2169  tvrect: trect;
2170  clickpos: tpoint;
2171  section: integer;
2172  address: dword;
2173  x: dword;
2174begin
2175  if (tvStructureView.selected<>nil) then
2176  begin
2177    s:=tstructure(tvStructureView.Selected.Data);
2178    elementnr:=tvStructureView.Selected.Index;
2179    if s=nil then exit;
2180
2181
2182    if (elementnr>=0) then
2183    begin
2184      //find the position that is clicked
2185      GetWindowRect(tvStructureView.Handle, tvrect);
2186
2187      clickpos.X:=popupmenu1.PopupPoint.X-tvrect.Left;
2188      clickpos.Y:=popupmenu1.PopupPoint.Y-tvrect.Top;
2189
2190      section:=headercontrol1.Sections.Count-1;
2191      for i:=0 to headercontrol1.Sections.Count-1 do
2192      begin
2193        if (clickpos.x>=headercontrol1.Sections[i].Left)
2194          and
2195           (clickpos.x<headercontrol1.Sections[i].Left+headercontrol1.Sections[i].width) then
2196        begin
2197          //found it
2198          section:=i;
2199          break;
2200        end;
2201      end;
2202
2203      if section>0 then
2204        section:=section-1; //count starts from 1, so decrease
2205
2206      if s.basestructure>=0 then
2207      begin
2208        memorybrowser.memoryaddress:=s.addresses[section]+definedstructures[s.basestructure].structelement[elementnr].offset;
2209        memorybrowser.RefreshMB;
2210      end;
2211    end;
2212   // definedstructures[s.basestructure].structelement[elementnr].
2213  end;
2214
2215
2216end;
2217
2218procedure TfrmStructures.automaticallyGuessOffsets(baseOffset: dword; structsize: integer);
2219var
2220  buf: array of byte;
2221  buf2: array of byte;
2222  i,j,t: integer;
2223  t2: TVariableType;
2224  x,y: dword;
2225begin
2226    setlength(buf,structsize);
2227    setlength(buf2,8);
2228    //now read the memory
2229    if readprocessmemory(processhandle,pointer(addresses[0]+baseOffset),@buf[0],structsize,x) then
2230    begin
2231      x:=0;
2232      while x<structsize do
2233      begin
2234        i:=length(definedstructures[length(definedstructures)-1].structelement);
2235        setlength(definedstructures[length(definedstructures)-1].structelement,i+1);
2236        definedstructures[length(definedstructures)-1].structelement[i].offset:=baseoffset+x;
2237        definedstructures[length(definedstructures)-1].structelement[i].pointerto:=false;
2238
2239        //value
2240        //check what type it is
2241        t2:=FindTypeOfData(addresses[0]+baseoffset+x,@buf[x],structsize-x);
2242        if t2=vtPointer then
2243        begin
2244          //pointer
2245
2246
2247          definedstructures[length(definedstructures)-1].structelement[i].pointerto:=true;
2248          definedstructures[length(definedstructures)-1].structelement[i].pointertoSize:=8;
2249          definedstructures[length(definedstructures)-1].structelement[i].bytesize:=4;
2250          definedstructures[length(definedstructures)-1].structelement[i].description:='pointer to ';
2251
2252          if readprocessmemory(processhandle,pointer(pdword(@buf[x])^),@buf2[0],8,y) then
2253          begin
2254            t2:=FindTypeOfData(pdword(@buf[x])^,@buf2[0],8);
2255            t:=convertVariableTypeTostructnr(t2);
2256            definedstructures[length(definedstructures)-1].structelement[i].structurenr:=t;
2257          end
2258          else definedstructures[length(definedstructures)-1].structelement[i].structurenr:=-9;
2259
2260          inc(x,4);
2261          continue;
2262        end;
2263
2264
2265        t:=convertVariableTypeTostructnr(t2);
2266
2267
2268
2269        definedstructures[length(definedstructures)-1].structelement[i].structurenr:=t;
2270
2271
2272
2273        case t of
2274          -1: //byte
2275          begin
2276            definedstructures[length(definedstructures)-1].structelement[i].description:='Byte';
2277            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=1;
2278            inc(x,1);
2279          end;
2280
2281          -4: //word
2282          begin
2283            definedstructures[length(definedstructures)-1].structelement[i].description:='Word';
2284            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=2;
2285            inc(x,2);
2286          end;
2287
2288          -7: //dword
2289          begin
2290            definedstructures[length(definedstructures)-1].structelement[i].description:='Dword';
2291            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=4;
2292            inc(x,4);
2293          end;
2294
2295          -12: //single
2296          begin
2297            definedstructures[length(definedstructures)-1].structelement[i].description:='Float';
2298            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=4;
2299            inc(x,4);
2300          end;
2301
2302          -13: //double
2303          begin
2304            definedstructures[length(definedstructures)-1].structelement[i].description:='Double';
2305            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=8;
2306            inc(x,8);
2307          end;
2308
2309          -14: //string
2310          begin
2311            definedstructures[length(definedstructures)-1].structelement[i].description:='String';
2312
2313            //find out how long this string is:
2314            definedstructures[length(definedstructures)-1].structelement[i].bytesize:=0;
2315            while (x<structsize) and (buf[x]>=32) and (buf[x]<=127) do
2316            begin
2317              inc(x);
2318              inc(definedstructures[length(definedstructures)-1].structelement[i].bytesize);
2319            end;
2320          end;
2321
2322
2323        end;
2324      end;
2325
2326    end;
2327end;
2328
2329procedure TfrmStructures.Autoguessoffsets1Click(Sender: TObject);
2330var
2331  sStartOffset: string;
2332  sStructSize: string;
2333  base: TbaseStructure;
2334  startOffset: integer;
2335  structSize: integer;
2336begin
2337  if currentstructure<>nil then
2338  begin
2339    base:=definedstructures[currentstructure.basestructure];
2340    if length(base.structelement)>0 then
2341      sStartOffset:=inttohex(base.structelement[length(base.structelement)-1].offset+base.structelement[length(base.structelement)-1].bytesize,1)
2342    else
2343      sStartOffset:='0';
2344
2345    if not inputquery('Structure define','Please give a starting offset to evaluate',sStartOffset) then exit;
2346    startOffset:=StrToInt('$'+sStartOffset);
2347
2348    sStructSize:='4096';
2349    if not inputquery('Structure define','Please give the size of the block to evaluate',sStructSize) then exit;
2350    structSize:=StrToInt(sStructSize);
2351
2352    automaticallyGuessOffsets(startOffset, structsize);
2353  end;
2354end;
2355
2356procedure  TfrmStructures.UpdateGroupIndex;
2357var i,j: integer;
2358    alreadyIndexed: boolean;
2359begin
2360  setlength(groupindex,0);
2361  setlength(internalgrouplist,length(groups));
2362  for i:=0 to length(groups)-1 do
2363  begin
2364    alreadyIndexed:=false;
2365    for j:=0 to length(groupindex)-1 do
2366    begin
2367      if groupindex[j]=groups[i] then
2368      begin
2369        alreadyIndexed:=true;
2370        internalgrouplist[i]:=j;
2371        break;
2372      end;
2373    end;
2374
2375    if not alreadyIndexed then
2376    begin
2377      setlength(groupindex,length(groupindex)+1);
2378      groupindex[length(groupindex)-1]:=groups[i];
2379      internalgrouplist[i]:=length(groupindex)-1;
2380    end;
2381
2382
2383  end;
2384end;
2385
2386
2387procedure TfrmStructures.Setgroup1Click(Sender: TObject);
2388var
2389  x: tedit;
2390  sgroup: string;
2391begin
2392  x:=TEdit(popupmenu2.PopupComponent);
2393
2394  sgroup:=inttostr(groups[x.Tag]);
2395
2396  InputQuery('Structure definer', 'Which group do you want to set this address to?', sgroup);
2397  groups[x.Tag]:=strtoint(sgroup);
2398
2399  updategroupindex;
2400
2401  tvStructureView.Refresh;
2402end;
2403
2404end.
2405
2406
2407
Note: See TracBrowser for help on using the browser.