Gracias por los consejos. Open Tools API es el camino a seguir y es posible utilizar la API Open Tools desde un componente en un formulario en designtime.
Así que aquí está mi solución:
necesito dos unidades, una para el componente y otro para registrar el componente y el código que utilizan la API de herramientas abiertas.
Aquí viene la unidad de componentes:
unit TestLabels;
interface
uses
SysUtils, Classes, Windows, Controls, StdCtrls;
type
TTestLabel = class(TLabel)
private
FTestProperty: Boolean;
procedure SetTestProperty(const Value: Boolean);
procedure Changed;
published
property TestProperty: Boolean read FTestProperty write SetTestProperty;
end;
var
OnGetUnitPath: TFunc;
implementation
{ TTestLabel }
procedure TTestLabel.Changed;
begin
if not (csDesigning in ComponentState) then
Exit; // I only need the path at designtime
if csLoading in ComponentState then
Exit; // at this moment you retrieve the unit path which was current before
if not Assigned(OnGetUnitPath) then
Exit;
// only for demonstration
Caption := OnGetUnitPath;
MessageBox(0, PChar(ExtractFilePath(OnGetUnitPath)), 'Path of current unit', 0);
end;
procedure TTestLabel.SetTestProperty(const Value: Boolean);
begin
if FTestProperty Value then
begin
FTestProperty := Value;
Changed;
end;
end;
end.
Aquí es la unidad para registrar el componente y la llamada a la Herramientas API abierta:
unit TestLabelsReg;
interface
uses
SysUtils, Classes, Controls, StdCtrls, TestLabels;
procedure register;
implementation
uses
ToolsAPI;
function GetCurrentUnitPath: String;
var
ModuleServices: IOTAModuleServices;
Module: IOTAModule;
SourceEditor: IOTASourceEditor;
idx: integer;
begin
Result := '';
SourceEditor := nil;
if SysUtils.Supports(BorlandIDEServices, IOTAModuleServices,
ModuleServices) then
begin
Module := ModuleServices.CurrentModule;
if System.Assigned(Module) then
begin
idx := Module.GetModuleFileCount - 1;
// Iterate over modules till we find a source editor or list exhausted
while (idx >= 0) and not SysUtils.Supports(Module.GetModuleFileEditor(idx), IOTASourceEditor, SourceEditor) do
System.Dec(idx);
// Success if list wasn't ehausted.
if idx >= 0 then
Result := ExtractFilePath(SourceEditor.FileName);
end;
end;
end;
procedure register;
begin
RegisterComponents('Samples', [TTestLabel]);
TestLabels.OnGetUnitPath := GetCurrentUnitPath;
end;
end.
Estoy bastante seguro de que GetCurrentUnitPath no compila (al menos la expresión booleana para el ciclo while no lo hace) y el ciclo while nunca terminará. Pero la idea es interesante, así que renuncié a tu respuesta. –
@Jeroen: Gracias por señalar esto. El editor stackoverflow.com recortó la línea "while not ((idx <0) o SysUtils.Supports (Module.GetModuleFileEditor (idx), IOTASourceEditor, SourceEditor) do". He ajustado la condición del while-loop para que stackoverflow.com lo muestra correcto. Por cierto, CurrentUnitPath se extrae (con modificaciones) del DUnit wizzard que viene con Delphi. –