Да, вы можете получить доступ к подпрограмме, которая вложена в другой (родительской) подпрограмме, от внешнего мира. Хотя это несколько сложно. Я нашел это в Интернете.
Как пройти вложенную процедуру в качестве процедурного параметра (32 бит)
Delphi обычно не поддерживает прохождение вложенных подпрограмм в качестве процедурных параметров:
// This code does not compile:
procedure testpass(p: tprocedure);
begin
p;
end;
procedure calltestpass;
procedure inner;
begin
showmessage('hello');
end;
begin
testpass(inner);
end;
Очевидное обходной путь должен пройти процедуру адрес и приведите его в тестовый комплект:
// This code compiles and runs OK
procedure testpass(p: pointer);
begin
tProcedure(p);
end;
procedure calltestpass;
procedure inner;
begin
showmessage('hello');
end;
begin
testpass(@inner);
end;
Существует, однако, ловушка в a bove example - если «внутренняя» процедура ссылается на любую переменную, которая была нажата на стек, прежде чем «внутренняя» процедура была вызвана из testpass (параметры calltestpass - если были какие-либо или локальные переменные в callTestpass - если они были), ваш система вероятнее всего, происходит сбой:
// This code compiles OK but generates runtime exception (could even be
// EMachineHangs :-))
procedure testpass(p: pointer);
begin
tProcedure(p);
end;
procedure calltestpass;
var msg: string;
procedure inner;
begin
msg := 'hello';
showmessage(msg);
end;
begin
testpass(@inner);
end;
причина заключается в том, в простых словах, что расположение кадра стека было «разрушено» путем вызова testpass рутинными и «внутренним» процедура неправильно вычисляет параметры и локальные переменные местоположения (не вините Delphi, пожалуйста). Обходной путь заключается в настройке правильного контекста стека до «внутренний» вызывается из «testpass».
// This code compiles and runs OK
{$O-}
procedure testpass(p: pointer);
var callersBP: longint;
begin
asm // get caller's base pointer value at the very beginning
push dword ptr [ebp]
pop callersBP
end;
// here we can have some other OP code
asm // pushes caller's base pointer value onto stack and calls tProcedure(p)
push CallersBP
Call p
Pop CallersBP
end;
// here we can have some other OP code
end;
{$O+}
procedure calltestpass;
var msg: string;
procedure inner;
begin
msg := 'hello';
showmessage(msg);
end;
begin
testpass(@inner);
end;
Пожалуйста, обратите внимание, что оптимизация отключена для процедуры проверки. Оптимизация обычно не очень хорошо обрабатывает смешанный код OP/ассемблера.
Частный частный :) Вы ищете способ сделать его общедоступным без изменения кода? – mjn
Это даже не личное, это внутреннее. Он не существует вне «родительской» процедуры, где он встроен. –