Если Ваша программа после завершенмя " съест" некоторое количество памяти, Windows тактично об этом умолчит, и ошибка останется не найденной. Поэтому я рекомендую на этапе разработки, в файл проекта вставлять модуль checkMem, который отследит некорректную работу с памятью. Вставлять его нужно первым, для обеспечения чистоты эксперимента. Текст модуля:

 

Code:

unit checkMem;                    

interface

implementation

 

uses sysUtils, dialogs;

var HPs : THeapStatus;

var HPe : THeapStatus;

var lost: integer;

initialization

  HPs := getHeapStatus;

finalization

  HPe := getHeapStatus;

  Lost:= HPe.TotalAllocated - HPs.TotalAllocated;

  if lost >  0thenbegin

     beep;

     ShowMessage( format('lostMem: %d',[ lost ]) );

  end;

end.

 

 

Code:

{©Drkb v.3(2007): drkb ru}

var

  p1 : ^String;

  s1 : String;

begin

  s1 := 'NotTest';

  new (p1);

  p1 := @s1;

  p1^ := 'Test';

  Label1.Caption := s1

 

 

 

Я не раз натыкался в этом некоторые из моих старых код и подумал, что я  поделиться им с вами:

Code:

function CreateVariantPtr(_Value: variant): pVariant;

begin

GetMem(Result, SizeOf(Variant));

Result^ := _Value;

end;

Автор: Павел

 

Оглавление

 

1. Введение

 

В данной статье изучаются принципы работы с памятью в системе Windows 32. Исследуется проблема накопления потоковых данных в специальных потоковых хранилищах. Работа с памятью является одной из важнейших функций любой программы. Выделение участков памяти для структур программы должно быть эффективным, поэтому программист должен хорошо разбираться в особенностях этого процесса.

 В статье приводятся только основные принципы работы с памятью в системе Windows 32. Для подробного изучения всех тонкостей этого сложного процесса читатель может обратиться к специальной литературе. Особенно хочется отметить книгу: Дж.Рихтер, "Windows для профессионалов".

 

Это то, что я нашел при создании простой машины состояний:

Ниже приведен простой пример для Borland Delphi, использующий указатели функций для управления программным потоком. Просто создайте простую форму с единственной кнопкой и скопируйте код из Unit1 во вновь созданный модуль. Добавьте к проекту Unit2 и скомпилируйте проект. Дайте мне знать, если у вас возникнут какие-либо проблемы.

Code:

interface

 

uses

 

SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,

Forms, Dialogs, StdCtrls;

 

type

 

TForm1 = class(TForm)

   Button1: TButton;

   procedure Button1Click(Sender: TObject);

private

   { Private declarations }

public

   { Public declarations }

end;

 

var

 

Form1: TForm1;

CurrProc: LongInt;

MyVal: LongInt;

 

implementation

 

uses Unit2;

 

{$R *.DFM}

 

procedure TForm1.Button1Click(Sender: TObject);

var

 

NewProc: LongInt;

MyString: string;

begin

 

CurrProc := 2; { начальная точка в таблице методов }

MyVal := 0; { вспомогательная переменная }

NewProc := 0;

   { возвращаемое значение для следующего индекса в таблице методов }

while CurrProc < 6do

begin

   { выполняем текущий индекс в таблице методов и получаем следующую процедуру }

   NewProc := ProcTable[CurrProc](MyVal);

 

   { просто показываем значения NewProc и CurrProc }

   FmtStr(MyString, 'NewProc [%d] CurrProc [%d]', [NewProc, CurrProc]);

   MessageDlg(MyString, mtInformation, [mbOK], 0);

 

   { присваиваем текущую процедуру возвращаемой процедуре }

   CurrProc := NewProc;

end;

 

end;

 

end.

 

 


 

Code:

{ Это простой пример, определяющий массив указателей на функции }

 

interface

 

type

 

{ определяем Procs как функцию }

Procs = function(var ProcNum: LongInt): LongInt;

 

var

 

{ объявляем массив указателей на функции }

ProcTable: array[1..5] of Procs;

 

{ определения интерфейсов функций }

function Proc1(var MyVal: LongInt): LongInt; far;

function Proc2(var MyVal: LongInt): LongInt; far;

function Proc3(var MyVal: LongInt): LongInt; far;

function Proc4(var MyVal: LongInt): LongInt; far;

function Proc5(var MyVal: LongInt): LongInt; far;

 

implementation

 

uses Dialogs;

 

function Proc1(var MyVal: LongInt): LongInt;

begin

 

MessageDlg('Процедура 1', mtInformation, [mbOK], 0);

Proc1 := 6;

end;

 

function Proc2(var MyVal: LongInt): LongInt;

begin

 

MessageDlg('Процедура 2', mtInformation, [mbOK], 0);

Proc2 := 3;

end;

 

function Proc3(var MyVal: LongInt): LongInt;

begin

 

MessageDlg('Процедура 3', mtInformation, [mbOK], 0);

Proc3 := 4;

end;

 

function Proc4(var MyVal: LongInt): LongInt;

begin

 

MessageDlg('Процедура 4', mtInformation, [mbOK], 0);

Proc4 := 5;

end;

 

function Proc5(var MyVal: LongInt): LongInt;

begin

 

MessageDlg('Процедура 5', mtInformation, [mbOK], 0);

Proc5 := 1;

end;

 

initialization

 

{ инициализируем содержание массива указателей на функции }

@ProcTable[1] := @Proc1;

@ProcTable[2] := @Proc2;

@ProcTable[3] := @Proc3;

@ProcTable[4] := @Proc4;

@ProcTable[5] := @Proc5;

 

end.

 

Я думаю это можно сделать приблизительно так: объявите в каждой форме процедуры, обрабатывающие нажатие кнопки, типа процедуры CutButtonPressed(Sender:TObject) of Object; затем просто назначьте события кнопок OnClick этим процедурам при наступлении событий форм OnActivate. Этот способ соответствует концепции ОО-программирования, но если вам не нравится это, то вы все еще можете воспользоваться указателями функций, которая предоставляет Delphi.

 


 

Объявите базовый класс формы с объявлениями абстрактных функций для каждой функции, которую вы хотите вызывать из вашего toolbar. Затем наследуйте каждую вашу форму от базового класса формы и создайте определения этих функций.

 

Пример: (Здесь может встретиться пара синтаксических ошибок - я не компилил это)

 

Code:

type

TBaseForm = class(TForm)

public

   procedure Method1; virtual; abstract;

end;

 

type

TDerivedForm1 = class(TBaseForm)

public

   procedure Method1; override;

end;

 

TDerivedForm2 = class(TBaseForm)

public

   procedure Method1; override;

end;

 

procedure TDerivedForm1.Method1;

begin

....

end;

 

procedure TDerivedForm2.Method1;

begin

....

end;

 

{Для вызова функции из вашего toolbar,

получите активную в настоящий момент форму и вызовите Method1}

 

procedure OnButtonClick;

var

AForm: TBaseForm;

begin

AForm := ActiveForm as TBaseForm;

AForm.Method1;

end;

 

 

 

 

Code:

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

  StdCtrls;

 

type

  TMyObjectPtr = ^TMyObject;

  TMyObject = record

    First_Name: String[20];

    Last_Name: String[20];

    Next: TMyObjectPtr;

  end;

 

type

  TForm1 = class(TForm)

    bSortByLastName: TButton;

    bDisplay: TButton;

    bPopulate: TButton;

    ListBox1: TListBox;

    bClear: TButton;

    procedure bSortByLastNameClick(Sender: TObject);

    procedure bPopulateClick(Sender: TObject);

    procedure bDisplayClick(Sender: TObject);

    procedure bClearClick(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

  pStartOfList: TMyObjectPtr = nil;

 

{List manipulation routines}

procedure SortMyObjectListByLastName(var aStartOfList: TMyObjectPtr);

function CreateMyObject(aFirstName, aLastName: String): TMyObjectPtr;

procedure AppendMyObject(var aCurrentItem, aNewItem: TMyObjectPtr);

procedure ClearMyObjectList(var aMyObject: TMyObjectPtr);

procedure RemoveMyObject(var aStartOfList, aRemoveMe: TMyObjectPtr);

function AreInAlphaOrder(aString1, aString2: String): Boolean;

 

 

implementation

 

{$R *.DFM}

 

 

procedure TForm1.bClearClick(Sender: TObject);

begin

  ClearMyObjectList(pStartOfList);

end;

 

procedure TForm1.bPopulateClick(Sender: TObject);

var

  pNew: TMyObjectPtr;

begin

  {Initialize the list with some static data}

  pNew := CreateMyObject('Suzy','Martinez');

  AppendMyObject(pStartOfList, pNew);

  pNew := CreateMyObject('John','Sanchez');

  AppendMyObject(pStartOfList, pNew);

  pNew := CreateMyObject('Mike','Rodriguez');

  AppendMyObject(pStartOfList, pNew);

  pNew := CreateMyObject('Mary','Sosa');

  AppendMyObject(pStartOfList, pNew);

  pNew := CreateMyObject('Betty','Hayek');

  AppendMyObject(pStartOfList, pNew);

  pNew := CreateMyObject('Luke','Smith');

  AppendMyObject(pStartOfList, pNew);

  pNew := CreateMyObject('John','Sosa');

  AppendMyObject(pStartOfList, pNew);

end;

 

procedure TForm1.bSortByLastNameClick(Sender: TObject);

begin

  SortMyObjectListByLastName(pStartOfList);

end;

 

procedure TForm1.bDisplayClick(Sender: TObject);

var

  pTemp: TMyObjectPtr;

begin

  {Display the list items}

  ListBox1.Items.Clear;

  pTemp := pStartOfList;

  while pTemp <> nildo

  begin

    ListBox1.Items.Add(pTemp^.Last_Name + ', ' + pTemp.First_Name);

    pTemp := pTemp^.Next;

  end;

end;

 

procedure ClearMyObjectList(var aMyObject: TMyObjectPtr);

var

  TempMyObject: TMyObjectPtr;

begin

  {Free the memory used by the list items}

  TempMyObject := aMyObject;

  while aMyObject <> nildo

  begin

    aMyObject := aMyObject^.Next;

    Dispose(TempMyObject);

    TempMyObject := aMyObject;

  end;

end;

 

function CreateMyObject(aFirstName, aLastName: String): TMyObjectPtr;

begin

  {Instantiate a new list item}

  new(result);

  result^.First_Name := aFirstName;

  result^.Last_Name := aLastName;

  result^.Next := nil;

end;

 

procedure SortMyObjectListByLastName(var aStartOfList: TMyObjectPtr);

var

  aSortedListStart, aSearch, aBest: TMyObjectPtr;

begin

  {Sort the list by the Last_Name "field"}

  aSortedListStart := nil;

  while (aStartOfList <> nil) do

  begin

    aSearch := aStartOfList;

    aBest := aSearch;

    while aSearch^.Next <> nildo

    begin

      ifnot AreInAlphaOrder(aBest^.Last_Name, aSearch^.Last_Name) then

        aBest := aSearch;

      aSearch := aSearch^.Next;

    end;

    RemoveMyObject(aStartOfList, aBest);

    AppendMyObject(aSortedListStart, aBest);

  end;

  aStartOfList := aSortedListStart;

end;

 

procedure AppendMyObject(var aCurrentItem, aNewItem: TMyObjectPtr);

begin

  {Recursive function that appends the new item to the end of the list}

  if aCurrentItem = nilthen

    aCurrentItem := aNewItem

  else

    AppendMyObject(aCurrentItem^.Next, aNewItem);

end;

 

procedure RemoveMyObject(var aStartOfList, aRemoveMe: TMyObjectPtr);

var

  pTemp: TMyObjectPtr;

begin

  {Removes a specific item from the list and collapses the empty spot.}

  pTemp := aStartOfList;

  if pTemp = aRemoveMe then

    aStartOfList := aStartOfList^.Next

  else

  begin

    while (pTemp^.Next <> aRemoveMe) and (pTemp^.Next <> nil) do

      pTemp := pTemp^.Next;

    if pTemp = nilthen Exit; //Shouldn't ever happen

   if pTemp^.Next = nilthen Exit; //Shouldn't ever happen

   pTemp^.Next := aRemoveMe^.Next;

  end;

  aRemoveMe^.Next := nil;

end;

 

function AreInAlphaOrder(aString1, aString2: String): Boolean;

var

  i: Integer;

begin

  {Returns True if aString1 should come before aString2 in an alphabetic ascending sort}

  Result := True;

 

  while Length(aString2) < Length(aString1) do aString2 := aString2 + '!';

  while Length(aString1) < Length(aString2) do aString1 := aString1 + '!';

 

  for i := 1to Length(aString1) do

  begin

    if aString1[i] > aString2[i] then Result := False;

    if aString1[i] <> aString2[i] then break;

  end;

end;

 

end.

Модуль содержит функции для работы с блоками памяти.

AllocateMem - выделяет блок памяти из Count записей по RecSize байт, возвращает адрес выделенного блока памяти в случае успеха или nil в случае ошибки.

 ReallocateMem - устанавливает новый размер блока памяти, выделенного функцией AllocateMem. В качестве параметра Pointer можт быть использован как

типизированный так и нетипизированный указатель.

 DeallocateMem - освобождает память, выделенную функциями AllocateMem или ReallocateMem. В качестве параметра Pointer можт быть использован как

типизированный так и нетипизированный указатель.

 MemSize - возвращает размер блока памяти, выделенного функциями AllocateMem или ReallocateMem.

Следующий пример конвертирует указатель в Cardinal, увеличиваем значение адреса, и конвертирует обратно в указатель, который и возвращает.

Внимание, функция не выделяет никаких блоков памяти, она просто работает с указателем.

Code:

Зависимости: System

Автор:       Григорий Ситнин, gregor gregor.ru, Москва

Copyright:   Григорий Ситнин, 2003

Дата:        8 июля 2003 г.

***************************************************** }

 

function IncPtr(APointer: pointer; AHowMuch: cardinal = 1): pointer;

begin

//*** Конвертируем указатель в Cardinal, увеличиваем значение адреса,

//*** и конвертируем обратно в указатель, который и возвращаем.

//**! Внимание, функция не выделяет никаких блоков памяти,

//**! она просто работает с указателем.

Result := Ptr(cardinal(APointer) + AHowMuch);

end;

Пример использования:

 

{$APPTYPE CONSOLE}

program testptr;

uses SysUtils, uIncPtr; //*** Модуль uIncPtr содержит функцию IncPtr

var

ptr1, ptr2: pointer;

begin

ptr1 := AllocMem(255);

ptr2 := incptr(ptr1, 10);

writeln('ptr1 : ', cardinal(ptr1));

//*** Напечатать увеличенный на 10 указатель ptr1

writeln('ptr2 (+10): ', cardinal(ptr2));

FreeMem(ptr1, 255)

end.