root/Cheat Engine/Structuresfrm.pas @ 309

Revision 309, 69.7 kB (checked in by dark_byte, 8 months ago)

bugfixes for the heaplist and memory dissect

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